Trouble with OpenSSL's BN_bn2bin function
-
19-09-2019 - |
Question
I'm trying to use the BN_* functions in OpenSSL. Specifically, I have the following code:
#import <openssl/bn.h>
BIGNUM * num = BN_new();
BN_set_word(num, 42);
char * buffer = malloc((BN_num_bytes(num)+1) * sizeof(char));
buffer[BN_num_bytes(num)] = '\0';
int len = BN_bn2bin(num, buffer);
printf("42 in binary is %s\n", buffer);
However, when I do this, I don't get a string of ones and zeros. Instead it prints "42 in binary is *"
. As far as I can tell, and from the very limited number of examples available on the web that I've compared this to, I've implemented this correctly.
Any ideas why it isn't working?
Solution
BN_bn2bin
doesn't create a printable string - instead, it creates a representation that is truly binary (i.e. a sequence of bits). More specifically, it createas a big-endian representation of the number. Since 42 fits into one byte, you get one byte 0x2a, which is "*" in ASCII.
If you want a 0/1 representation, you need to iterate over all bytes, and do the printing yourself (e.g. with shifting or a lookup table).
OTHER TIPS
Here's some code that actually turns the BN_bn2bin
output into a printable string just like the output of BN_bn2dec
and BN_bn2hex
. It's in a NodeJS library but is written in C++ for speed. Took me all day and probably isn't optimal (because I haven't written any C++ code since first year of uni). But it passes a bunch of unit tests so I know it works!
https://github.com/malcolmocean/node-bignum
if (BN_is_zero(&bignum->bignum_)) {
to = (char*) OPENSSL_malloc(2*sizeof(char));
to[0] = '0';
to[1] = '\0';
} else {
unsigned char *binary = (unsigned char*) OPENSSL_malloc(BN_num_bytes(&bignum->bignum_)*sizeof(unsigned char));
int len = BN_bn2bin(&bignum->bignum_, binary);
to = (char*) OPENSSL_malloc((len*8+2)*sizeof(char));
int offset = 0;
if (BN_is_negative(&bignum->bignum_)) {
to[0] = '-';
offset--;
}
unsigned char x = binary[0];
while (!(x & 128) && x) {
x = x << 1;
offset++;
}
for (int i = 0; i < len; i++) {
unsigned char bits = binary[i];
int j=7;
while(bits) {
if (bits & 1) {
to[8*i+j-offset] = '1';
} else {
to[8*i+j-offset] = '0';
}
bits = bits >> 1;
j--;
}
if (i > 0) {
while (j >= 0) {
to[8*i+j-offset] = '0';
j--;
}
}
}
to[8*len-offset] = '\0';
OPENSSL_free(binary);
}