The Basics Arbitrary Precision Math

86 To implement many public key encryption algorithms, the library must have support for mathematical operations on large integers. Use of standard C or C++ data types is not adequate in these situations. To alleviate this problem, OpenSSL provides the BN package. This package declares routines on the aggregate type BIGNUM , which have virtually no limits on the upper bounds of numbers. More specifically, the size of the number that a BIGNUM -typed variable can hold is limited only by available memory. Its likely that direct exposure to the BN package in developing an SSL-enabled application will be limited since it is a very low-level package, and the higher-level packages generally hide the details. However, because the package is so widely used and integral to public key cryptography, weve briefly covered it here.

4.5.1 The Basics

To use the BIGNUM package in your programs, youll need to include the header file opensslbn.h. Before we can use a BIGNUM , we must first initialize it. The BN package provides support for both statically allocated and dynamically allocated BIGNUM s. The function BN_new will allocate a new BIGNUM and initialize it for use. The function BN_init will initialize a statically allocated BIGNUM . When youre done using a BIGNUM , you should always be sure to destroy it, even if it is allocated on the stack, because internally, a BIGNUM dynamically allocates memory. The function BN_free will destroy a BIGNUM . Example 4-13 shows some examples of how these three functions are used. Example 4-13. Creating, initializing, and destroying BIGNUMs BIGNUM static_bn, dynamic_bn; Initialize a statically allocated BIGNUM BN_initstatic_bn; Allocate an initialize a new BIGNUM dynamic_bn = BN_new; Destroy the two BIGNUMs that we just created BN_freedynamic_bn; BN_freestatic_bn; A BIGNUM is implemented as an opaque structure that contains dynamically allocated memory. The functions provided to operate on a BIGNUM allow the programmer to remain blissfully unaware of whats going on for the most part, but it is important that the programmer does understand that there is much more going on internally. One such instance is when the value of one BIGNUM needs to be assigned to another BIGNUM . The natural inclination is to perform a shallow copy of the structure, but this should never be done Deep copies must be performed, and the BN package provides functions for doing just that. Example 4-14 demonstrates the right way and the wrong way to make a copy of a BIGNUM . Example 4-14. The wrong way and the right way to copy a BIGNUM BIGNUM a, b c; First, the wrong way to copy a BIGNUM a = b; c = b; Now the right way to copy a BIGNUM BN_copya,b; Copies b to a 87 c = BN_dupb; Creates c and initializes it to the same value as b It is important that we copy BIGNUM s properly. If we dont, were likely to experience unpredictable behavior or crashes. When programming with BIGNUM s, there will likely be situations in which youll need to make copies, so its best to learn this lesson early. Another operation that is similar in nature is the comparison of two BIGNUM s. We cannot simply compare two BIGNUM s using normal C comparison operators like =, , or . Instead, we must use the BN_cmp function to compare two BIGNUM s. This function will compare the two values, a and b, and return -1 if a is less than b, 0 if they are equal, and 1 if a is greater than b. The function BN_ucmp will perform the same type of comparison on the absolute values of a and b. It may be useful to convert a BIGNUM into a flat binary representation for the purpose of storing it in a file or sending it over a socket connection to a peer. Since a BIGNUM contains pointers to internal, dynamically allocated memory, it is not a flat structure, so we must convert it to one before we can send it anywhere. Conversely, we must be able to convert a flat representation of a BIGNUM back into a BIGNUM structure that the BN package can use. Two functions are provided for performing these respective operations. The first, BN_bn2bin , will convert a BIGNUM to a flat binary representation in big-endian form. The second, BN_bin2bn , performs the inverse operation, converting a flat binary representation of a big-endian number into a BIGNUM . Before converting a BIGNUM into a flat binary representation, we need to know the number of bytes of memory that will be required to hold the converted data. Its also important to know how big the binary representation is before converting it back into a BIGNUM . The number of bytes required to represent a BIGNUM in flat binary form can be discovered using the BN_num_bytes function. Example 4-15 demonstrates converting between BIGNUM and flat binary representations. Example 4-15. Converting between BIGNUM and binary representations Converting from BIGNUM to binary len = BN_num_bytesnum; buf = unsigned char malloclen; len = BN_bn2binnum, buf; Converting from binary to BIGNUM BN_bin2bnbuf, len, num; num = BN_bin2bnbuf, len, NULL; When BN_bn2bin performs its conversion, it will return the number of bytes that were written out into the supplied buffer. If an error occurs in the conversion, the return will be 0. When BN_bin2bn performs its conversion, the result is placed into the BIGNUM specified as the third argument, overwriting any value that it may have previously held. If the third argument is specified as NULL , a new BIGNUM is created and initialized with the value from the binary representation. In either case, the BN_bin2bn will always return a pointer to the BIGNUM that received the value or NULL if an error occurred during the conversion. Binary-encoded numbers are fine when we want to transfer the data over a medium that supports it—for example, a binary file or a socket. However, for circumstances in which we need a text- based representation, such as printing the number on the screen, it is inadequate. We can always base64-encode the data before emitting it, but the BN package provides more intuitive methods. The function BN_bn2hex converts a BIGNUM into a hexadecimal representation stored in a C- style string. The C-style string is allocated dynamically using OPENSSL_malloc , which must then be freed by the caller using OPENSSL_free . 88 char BN_bn2hexconst BIGNUM num; The function BN_bn2dec converts a BIGNUM into a decimal representation stored in a C-style string. The C-style string is allocated dynamically using OPENSSL_malloc , which must then be freed by the caller using OPENSSL_free . char BN_bn2decconst BIGNUM num; The function BN_hex2bn converts a hexadecimal representation of a number stored in a C-style string to a BIGNUM . The resulting value is stored in the supplied BIGNUM , or a new BIGNUM is created with BN_new if the BIGNUM is supplied as NULL . int BN_hex2bnBIGNUM num, const char str; The function BN_dec2bn converts a decimal representation of a number stored in a C-style string to a BIGNUM . The resulting value is stored in the supplied BIGNUM , or a new BIGNUM is created with BN_new if the BIGNUM is supplied as NULL . int BN_dec2bnBIGNUM num, const char str;

4.5.2 Mathematical Operations