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