diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 609 |
1 files changed, 274 insertions, 335 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index f980d7ecfc..28963f52cb 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -51,9 +51,9 @@ #define CRYPTO_PRIVATE #include "crypto.h" -#include "../common/torlog.h" +#include "torlog.h" #include "aes.h" -#include "../common/util.h" +#include "util.h" #include "container.h" #include "compat.h" #include "sandbox.h" @@ -1394,6 +1394,78 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out) return 0; } +/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the + * Base64 encoding of the DER representation of the private key as a NUL + * terminated string, and return it via <b>priv_out</b>. Return 0 on + * sucess, -1 on failure. + * + * It is the caller's responsibility to sanitize and free the resulting buffer. + */ +int +crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out) +{ + unsigned char *der = NULL; + int der_len; + int ret = -1; + + *priv_out = NULL; + + der_len = i2d_RSAPrivateKey(pk->key, &der); + if (der_len < 0 || der == NULL) + return ret; + + size_t priv_len = base64_encode_size(der_len, 0) + 1; + char *priv = tor_malloc_zero(priv_len); + if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) { + *priv_out = priv; + ret = 0; + } else { + tor_free(priv); + } + + memwipe(der, 0, der_len); + OPENSSL_free(der); + return ret; +} + +/** Given a string containing the Base64 encoded DER representation of the + * private key <b>str</b>, decode and return the result on success, or NULL + * on failure. + */ +crypto_pk_t * +crypto_pk_base64_decode(const char *str, size_t len) +{ + crypto_pk_t *pk = NULL; + + char *der = tor_malloc_zero(len + 1); + int der_len = base64_decode(der, len, str, len); + if (der_len <= 0) { + log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64)."); + goto out; + } + + const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */ + RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len); + if (!rsa) { + crypto_log_errors(LOG_WARN, "decoding private key"); + goto out; + } + + pk = crypto_new_pk_from_rsa_(rsa); + + /* Make sure it's valid. */ + if (crypto_pk_check_key(pk) <= 0) { + crypto_pk_free(pk); + pk = NULL; + goto out; + } + + out: + memwipe(der, 0, len + 1); + tor_free(der); + return pk; +} + /* symmetric crypto */ /** Return a pointer to the key set for the cipher in <b>env</b>. @@ -1765,235 +1837,12 @@ static BIGNUM *dh_param_p_tls = NULL; /** Shared G parameter for our DH key exchanges. */ static BIGNUM *dh_param_g = NULL; -/** Generate and return a reasonable and safe DH parameter p. */ -static BIGNUM * -crypto_generate_dynamic_dh_modulus(void) -{ - BIGNUM *dynamic_dh_modulus; - DH *dh_parameters; - int r, dh_codes; - char *s; - - dynamic_dh_modulus = BN_new(); - tor_assert(dynamic_dh_modulus); - - dh_parameters = DH_new(); - tor_assert(dh_parameters); - - r = DH_generate_parameters_ex(dh_parameters, - DH_BYTES*8, DH_GENERATOR, NULL); - tor_assert(r == 0); - - r = DH_check(dh_parameters, &dh_codes); - tor_assert(r && !dh_codes); - - BN_copy(dynamic_dh_modulus, dh_parameters->p); - tor_assert(dynamic_dh_modulus); - - DH_free(dh_parameters); - - { /* log the dynamic DH modulus: */ - s = BN_bn2hex(dynamic_dh_modulus); - tor_assert(s); - log_info(LD_OR, "Dynamic DH modulus generated: [%s]", s); - OPENSSL_free(s); - } - - return dynamic_dh_modulus; -} - -/** Store our dynamic DH modulus (and its group parameters) to - <b>fname</b> for future use. */ -static int -crypto_store_dynamic_dh_modulus(const char *fname) -{ - int len, new_len; - DH *dh = NULL; - unsigned char *dh_string_repr = NULL; - char *base64_encoded_dh = NULL; - char *file_string = NULL; - int retval = -1; - static const char file_header[] = "# This file contains stored Diffie-" - "Hellman parameters for future use.\n# You *do not* need to edit this " - "file.\n\n"; - - tor_assert(fname); - - if (!dh_param_p_tls) { - log_info(LD_CRYPTO, "Tried to store a DH modulus that does not exist."); - goto done; - } - - if (!(dh = DH_new())) - goto done; - if (!(dh->p = BN_dup(dh_param_p_tls))) - goto done; - if (!(dh->g = BN_new())) - goto done; - if (!BN_set_word(dh->g, DH_GENERATOR)) - goto done; - - len = i2d_DHparams(dh, &dh_string_repr); - if ((len < 0) || (dh_string_repr == NULL)) { - log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2)."); - goto done; - } - - base64_encoded_dh = tor_calloc(len, 2); /* should be enough */ - new_len = base64_encode(base64_encoded_dh, len * 2, - (char *)dh_string_repr, len); - if (new_len < 0) { - log_warn(LD_CRYPTO, "Error occured while base64-encoding DH modulus."); - goto done; - } - - /* concatenate file header and the dh parameters blob */ - new_len = tor_asprintf(&file_string, "%s%s", file_header, base64_encoded_dh); - - /* write to file */ - if (write_bytes_to_new_file(fname, file_string, new_len, 0) < 0) { - log_info(LD_CRYPTO, "'%s' was already occupied.", fname); - goto done; - } - - retval = 0; - - done: - if (dh) - DH_free(dh); - if (dh_string_repr) - OPENSSL_free(dh_string_repr); - tor_free(base64_encoded_dh); - tor_free(file_string); - - return retval; -} - -/** Return the dynamic DH modulus stored in <b>fname</b>. If there is no - dynamic DH modulus stored in <b>fname</b>, return NULL. */ -static BIGNUM * -crypto_get_stored_dynamic_dh_modulus(const char *fname) -{ - int retval; - char *contents = NULL; - const char *contents_tmp = NULL; - int dh_codes; - DH *stored_dh = NULL; - BIGNUM *dynamic_dh_modulus = NULL; - int length = 0; - unsigned char *base64_decoded_dh = NULL; - const unsigned char *cp = NULL; - - tor_assert(fname); - - contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); - if (!contents) { - log_info(LD_CRYPTO, "Could not open file '%s'", fname); - goto done; /*usually means that ENOENT. don't try to move file to broken.*/ - } - - /* skip the file header */ - contents_tmp = eat_whitespace(contents); - if (!*contents_tmp) { - log_warn(LD_CRYPTO, "Stored dynamic DH modulus file " - "seems corrupted (eat_whitespace)."); - goto err; - } - - /* 'fname' contains the DH parameters stored in base64-ed DER - * format. We are only interested in the DH modulus. - * NOTE: We allocate more storage here than we need. Since we're already - * doing that, we can also add 1 byte extra to appease Coverity's - * scanner. */ - - cp = base64_decoded_dh = tor_malloc_zero(strlen(contents_tmp) + 1); - length = base64_decode((char *)base64_decoded_dh, strlen(contents_tmp), - contents_tmp, strlen(contents_tmp)); - if (length < 0) { - log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (base64)."); - goto err; - } - - stored_dh = d2i_DHparams(NULL, &cp, length); - if ((!stored_dh) || (cp - base64_decoded_dh != length)) { - log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (d2i)."); - goto err; - } - - { /* check the cryptographic qualities of the stored dynamic DH modulus: */ - retval = DH_check(stored_dh, &dh_codes); - if (!retval || dh_codes) { - log_warn(LD_CRYPTO, "Stored dynamic DH modulus is not a safe prime."); - goto err; - } - - retval = DH_size(stored_dh); - if (retval < DH_BYTES) { - log_warn(LD_CRYPTO, "Stored dynamic DH modulus is smaller " - "than '%d' bits.", DH_BYTES*8); - goto err; - } - - if (!BN_is_word(stored_dh->g, 2)) { - log_warn(LD_CRYPTO, "Stored dynamic DH parameters do not use '2' " - "as the group generator."); - goto err; - } - } - - { /* log the dynamic DH modulus: */ - char *s = BN_bn2hex(stored_dh->p); - tor_assert(s); - log_info(LD_OR, "Found stored dynamic DH modulus: [%s]", s); - OPENSSL_free(s); - } - - goto done; - - err: - - { - /* move broken prime to $filename.broken */ - char *fname_new=NULL; - tor_asprintf(&fname_new, "%s.broken", fname); - - log_warn(LD_CRYPTO, "Moving broken dynamic DH prime to '%s'.", fname_new); - - if (replace_file(fname, fname_new)) - log_notice(LD_CRYPTO, "Error while moving '%s' to '%s'.", - fname, fname_new); - - tor_free(fname_new); - } - - if (stored_dh) { - DH_free(stored_dh); - stored_dh = NULL; - } - - done: - tor_free(contents); - tor_free(base64_decoded_dh); - - if (stored_dh) { - dynamic_dh_modulus = BN_dup(stored_dh->p); - DH_free(stored_dh); - } - - return dynamic_dh_modulus; -} - -/** Set the global TLS Diffie-Hellman modulus. - * If <b>dynamic_dh_modulus_fname</b> is set, try to read a dynamic DH modulus - * off it and use it as the DH modulus. If that's not possible, - * generate a new dynamic DH modulus. - * If <b>dynamic_dh_modulus_fname</b> is NULL, use the Apache mod_ssl DH +/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH * modulus. */ void -crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) +crypto_set_tls_dh_prime(void) { BIGNUM *tls_prime = NULL; - int store_dh_prime_afterwards = 0; int r; /* If the space is occupied, free the previous TLS DH prime */ @@ -2002,44 +1851,24 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) dh_param_p_tls = NULL; } - if (dynamic_dh_modulus_fname) { /* use dynamic DH modulus: */ - log_info(LD_OR, "Using stored dynamic DH modulus."); - tls_prime = crypto_get_stored_dynamic_dh_modulus(dynamic_dh_modulus_fname); - - if (!tls_prime) { - log_notice(LD_OR, "Generating fresh dynamic DH modulus. " - "This might take a while..."); - tls_prime = crypto_generate_dynamic_dh_modulus(); - - store_dh_prime_afterwards++; - } - } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ - tls_prime = BN_new(); - tor_assert(tls_prime); + tls_prime = BN_new(); + tor_assert(tls_prime); - /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. - */ - r =BN_hex2bn(&tls_prime, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - } + /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see + * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this + * prime. + */ + r = BN_hex2bn(&tls_prime, + "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" + "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" + "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" + "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" + "B0E7393E0F24218EB3"); + tor_assert(r); tor_assert(tls_prime); dh_param_p_tls = tls_prime; - - if (store_dh_prime_afterwards) - /* save the new dynamic DH modulus to disk. */ - if (crypto_store_dynamic_dh_modulus(dynamic_dh_modulus_fname)) { - log_notice(LD_CRYPTO, "Failed while storing dynamic DH modulus. " - "Make sure your data directory is sane."); - } } /** Initialize dh_param_p and dh_param_g if they are not already @@ -2076,10 +1905,8 @@ init_dh_param(void) dh_param_p = circuit_dh_prime; dh_param_g = generator; - /* Ensure that we have TLS DH parameters set up, too, even if we're - going to change them soon. */ if (!dh_param_p_tls) { - crypto_set_tls_dh_prime(NULL); + crypto_set_tls_dh_prime(); } } @@ -2548,8 +2375,40 @@ crypto_rand_int(unsigned int max) } } +/** Return a pseudorandom integer, chosen uniformly from the values <i>i</i> + * such that <b>min</b> <= <i>i</i> < <b>max</b>. + * + * <b>min</b> MUST be in range [0, <b>max</b>). + * <b>max</b> MUST be in range (min, INT_MAX]. + */ +int +crypto_rand_int_range(unsigned int min, unsigned int max) +{ + tor_assert(min < max); + tor_assert(max <= INT_MAX); + + /* The overflow is avoided here because crypto_rand_int() returns a value + * between 0 and (max - min) inclusive. */ + return min + crypto_rand_int(max - min); +} + +/** As crypto_rand_int_range, but supports uint64_t. */ +uint64_t +crypto_rand_uint64_range(uint64_t min, uint64_t max) +{ + tor_assert(min < max); + return min + crypto_rand_uint64(max - min); +} + +/** As crypto_rand_int_range, but supports time_t. */ +time_t +crypto_rand_time_range(time_t min, time_t max) +{ + return (time_t) crypto_rand_uint64_range(min, max); +} + /** Return a pseudorandom 64-bit integer, chosen uniformly from the values - * between 0 and <b>max</b>-1. */ + * between 0 and <b>max</b>-1 inclusive. */ uint64_t crypto_rand_uint64(uint64_t max) { @@ -2610,7 +2469,7 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, if (min_rand_len > max_rand_len) min_rand_len = max_rand_len; - randlen = min_rand_len + crypto_rand_int(max_rand_len - min_rand_len + 1); + randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1); prefixlen = strlen(prefix); resultlen = prefixlen + strlen(suffix) + randlen + 16; @@ -2657,36 +2516,163 @@ smartlist_shuffle(smartlist_t *sl) } } +#define BASE64_OPENSSL_LINELEN 64 + +/** Return the Base64 encoded size of <b>srclen</b> bytes of data in + * bytes. + * + * If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return the size + * of the encoded output as multiline output (64 character, `\n' terminated + * lines). + */ +size_t +base64_encode_size(size_t srclen, int flags) +{ + size_t enclen; + tor_assert(srclen < INT_MAX); + + if (srclen == 0) + return 0; + + enclen = ((srclen - 1) / 3) * 4 + 4; + if (flags & BASE64_ENCODE_MULTILINE) { + size_t remainder = enclen % BASE64_OPENSSL_LINELEN; + enclen += enclen / BASE64_OPENSSL_LINELEN; + if (remainder) + enclen++; + } + tor_assert(enclen < INT_MAX && enclen > srclen); + return enclen; +} + +/** Internal table mapping 6 bit values to the Base64 alphabet. */ +static const char base64_encode_table[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + /** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write * the result into <b>dest</b>, if it will fit within <b>destlen</b> - * bytes. Return the number of bytes written on success; -1 if + * bytes. Return the number of bytes written on success; -1 if * destlen is too short, or other failure. + * + * If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return encoded + * output in multiline format (64 character, `\n' terminated lines). */ int -base64_encode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - /* FFFF we might want to rewrite this along the lines of base64_decode, if - * it ever shows up in the profile. */ - EVP_ENCODE_CTX ctx; - int len, ret; - tor_assert(srclen < INT_MAX); +base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, + int flags) +{ + const unsigned char *usrc = (unsigned char *)src; + const unsigned char *eous = usrc + srclen; + char *d = dest; + uint32_t n = 0; + size_t linelen = 0; + size_t enclen; + int n_idx = 0; + + if (!src || !dest) + return -1; - /* 48 bytes of input -> 64 bytes of output plus newline. - Plus one more byte, in case I'm wrong. - */ - if (destlen < ((srclen/48)+1)*66) + /* Ensure that there is sufficient space, including the NUL. */ + enclen = base64_encode_size(srclen, flags); + if (destlen < enclen + 1) return -1; if (destlen > SIZE_T_CEILING) return -1; + if (enclen > INT_MAX) + return -1; - EVP_EncodeInit(&ctx); - EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len, - (unsigned char*)src, (int)srclen); - EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret); - ret += len; - return ret; + memset(dest, 0, enclen); + + /* XXX/Yawning: If this ends up being too slow, this can be sped up + * by separating the multiline format case and the normal case, and + * processing 48 bytes of input at a time when newlines are desired. + */ +#define ENCODE_CHAR(ch) \ + STMT_BEGIN \ + *d++ = ch; \ + if (flags & BASE64_ENCODE_MULTILINE) { \ + if (++linelen % BASE64_OPENSSL_LINELEN == 0) { \ + linelen = 0; \ + *d++ = '\n'; \ + } \ + } \ + STMT_END + +#define ENCODE_N(idx) \ + ENCODE_CHAR(base64_encode_table[(n >> ((3 - idx) * 6)) & 0x3f]) + +#define ENCODE_PAD() ENCODE_CHAR('=') + + /* Iterate over all the bytes in src. Each one will add 8 bits to the + * value we're encoding. Accumulate bits in <b>n</b>, and whenever we + * have 24 bits, batch them into 4 bytes and flush those bytes to dest. + */ + for ( ; usrc < eous; ++usrc) { + n = (n << 8) | *usrc; + if ((++n_idx) == 3) { + ENCODE_N(0); + ENCODE_N(1); + ENCODE_N(2); + ENCODE_N(3); + n_idx = 0; + n = 0; + } + } + switch (n_idx) { + case 0: + /* 0 leftover bits, no pading to add. */ + break; + case 1: + /* 8 leftover bits, pad to 12 bits, write the 2 6-bit values followed + * by 2 padding characters. + */ + n <<= 4; + ENCODE_N(2); + ENCODE_N(3); + ENCODE_PAD(); + ENCODE_PAD(); + break; + case 2: + /* 16 leftover bits, pad to 18 bits, write the 3 6-bit values followed + * by 1 padding character. + */ + n <<= 2; + ENCODE_N(1); + ENCODE_N(2); + ENCODE_N(3); + ENCODE_PAD(); + break; + default: + /* Something went catastrophically wrong. */ + tor_fragile_assert(); + return -1; + } + +#undef ENCODE_N +#undef ENCODE_PAD +#undef ENCODE_CHAR + + /* Multiline output always includes at least one newline. */ + if (flags & BASE64_ENCODE_MULTILINE && linelen != 0) + *d++ = '\n'; + + tor_assert(d - dest == (ptrdiff_t)enclen); + + *d++ = '\0'; /* NUL terminate the output. */ + + return (int) enclen; } +#undef BASE64_OPENSSL_LINELEN + /** @{ */ /** Special values used for the base64_decode_table */ #define X 255 @@ -2731,26 +2717,6 @@ static const uint8_t base64_decode_table[256] = { int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) { -#ifdef USE_OPENSSL_BASE64 - EVP_ENCODE_CTX ctx; - int len, ret; - /* 64 bytes of input -> *up to* 48 bytes of output. - Plus one more byte, in case I'm wrong. - */ - if (destlen < ((srclen/64)+1)*49) - return -1; - if (destlen > SIZE_T_CEILING) - return -1; - - memset(dest, 0, destlen); - - EVP_DecodeInit(&ctx); - EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len, - (unsigned char*)src, srclen); - EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret); - ret += len; - return ret; -#else const char *eos = src+srclen; uint32_t n=0; int n_idx=0; @@ -2821,20 +2787,19 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) tor_assert((dest-dest_orig) <= INT_MAX); return (int)(dest-dest_orig); -#endif } #undef X #undef SP #undef PAD /** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing = - * and newline characters, and store the nul-terminated result in the first + * characters, and store the nul-terminated result in the first * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */ int digest_to_base64(char *d64, const char *digest) { char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST_LEN); + base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0); buf[BASE64_DIGEST_LEN] = '\0'; memcpy(d64, buf, BASE64_DIGEST_LEN+1); return 0; @@ -2846,33 +2811,20 @@ digest_to_base64(char *d64, const char *digest) int digest_from_base64(char *digest, const char *d64) { -#ifdef USE_OPENSSL_BASE64 - char buf_in[BASE64_DIGEST_LEN+3]; - char buf[256]; - if (strlen(d64) != BASE64_DIGEST_LEN) - return -1; - memcpy(buf_in, d64, BASE64_DIGEST_LEN); - memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3); - if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN) - return -1; - memcpy(digest, buf, DIGEST_LEN); - return 0; -#else if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN) return 0; else return -1; -#endif } /** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the - * trailing = and newline characters, and store the nul-terminated result in - * the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */ + * trailing = characters, and store the nul-terminated result in the first + * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */ int digest256_to_base64(char *d64, const char *digest) { char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN); + base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0); buf[BASE64_DIGEST256_LEN] = '\0'; memcpy(d64, buf, BASE64_DIGEST256_LEN+1); return 0; @@ -2884,23 +2836,10 @@ digest256_to_base64(char *d64, const char *digest) int digest256_from_base64(char *digest, const char *d64) { -#ifdef USE_OPENSSL_BASE64 - char buf_in[BASE64_DIGEST256_LEN+3]; - char buf[256]; - if (strlen(d64) != BASE64_DIGEST256_LEN) - return -1; - memcpy(buf_in, d64, BASE64_DIGEST256_LEN); - memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3); - if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN) - return -1; - memcpy(digest, buf, DIGEST256_LEN); - return 0; -#else if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN) return 0; else return -1; -#endif } /** Implements base32 encoding as in RFC 4648. Limitation: Requires |