diff --git a/core/c/base64.c b/core/c/base64.c index 2f7b4f5e..f801cc75 100644 --- a/core/c/base64.c +++ b/core/c/base64.c @@ -78,37 +78,35 @@ static const unsigned char pr2six[256] = 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; -size_t Base64decode_len(const char *bufcoded) { +size_t mpw_base64_decode_max(const char *b64Text) { - size_t nbytesdecoded; - register const unsigned char *bufin; + register const uint8_t *bufin; register int nprbytes; - bufin = (const unsigned char *)bufcoded; + bufin = (uint8_t *)b64Text; while (pr2six[*(bufin++)] <= 63); - nprbytes = (int)(bufin - (const unsigned char *)bufcoded) - 1; - nbytesdecoded = (size_t)(((nprbytes + 3) / 4) * 3); - - return nbytesdecoded; + nprbytes = (int)(bufin - (uint8_t *)b64Text) - 1; + return (size_t)(((nprbytes + 3) / 4) * 3); } -int Base64decode(uint8_t *bufplain, const char *bufcoded) { +int mpw_base64_decode(uint8_t *plainBuf, size_t plainMax, const char *b64Text) { - int nbytesdecoded; - register const unsigned char *bufin; - register unsigned char *bufout; + register const uint8_t *bufin; + register uint8_t *bufout; register int nprbytes; - bufin = (const unsigned char *)bufcoded; + bufin = (uint8_t *)b64Text; while (pr2six[*(bufin++)] <= 63); - nprbytes = (int)(bufin - (const unsigned char *)bufcoded) - 1; - nbytesdecoded = ((nprbytes + 3) / 4) * 3; + nprbytes = (int)(bufin - (uint8_t *)b64Text) - 1; - bufout = bufplain; - bufin = (const unsigned char *)bufcoded; + bufout = plainBuf; + bufin = (uint8_t *)b64Text; while (nprbytes > 4) { + if (bufout + 2 >= plainBuf + plainMax) + return -1; + *(bufout++) = (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); *(bufout++) = (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); *(bufout++) = (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); @@ -118,54 +116,67 @@ int Base64decode(uint8_t *bufplain, const char *bufcoded) { /* Note: (nprbytes == 1) would be an error, so just ingore that case */ if (nprbytes > 1) { + if (bufout >= plainBuf + plainMax) + return -1; *(bufout++) = (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); } if (nprbytes > 2) { + if (bufout >= plainBuf + plainMax) + return -1; *(bufout++) = (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); } if (nprbytes > 3) { + if (bufout >= plainBuf + plainMax) + return -1; *(bufout++) = (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); } - nbytesdecoded -= (4 - nprbytes) & 3; - return nbytesdecoded; + return (int)(bufout - plainBuf); } static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -size_t Base64encode_len(size_t len) { +size_t mpw_base64_encode_max(size_t plainSize) { - return ((len + 2) / 3 * 4); + // Every 3 plain bytes yield 4 b64 chars => len = 4 * ceil(plainSize / 3) + return 4 /*chars*/ * (plainSize + 3 /*bytes*/ - 1) / 3 /*bytes*/; } -int Base64encode(char *encoded, const uint8_t *string, size_t len) { +int mpw_base64_encode(char *b64Text, size_t b64Max, const uint8_t *plainBuf, size_t plainSize) { int i; char *p; - p = encoded; - for (i = 0; i < len - 2; i += 3) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2) | - ((string[i + 2] & 0xC0) >> 6)]; - *p++ = basis_64[string[i + 2] & 0x3F]; + p = b64Text; + for (i = 0; i < plainSize - 2; i += 3) { + if (p >= b64Text + b64Max) + return -1; + + *p++ = basis_64[(plainBuf[i] >> 2) & 0x3F]; + *p++ = basis_64[((plainBuf[i] & 0x3) << 4) | + ((plainBuf[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((plainBuf[i + 1] & 0xF) << 2) | + ((plainBuf[i + 2] & 0xC0) >> 6)]; + *p++ = basis_64[plainBuf[i + 2] & 0x3F]; } - if (i < len) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - if (i == (len - 1)) { - *p++ = basis_64[((string[i] & 0x3) << 4)]; + if (i < plainSize) { + if (p + 3 >= b64Text + b64Max) + return -1; + + *p++ = basis_64[(plainBuf[i] >> 2) & 0x3F]; + if (i == (plainSize - 1)) { + *p++ = basis_64[((plainBuf[i] & 0x3) << 4)]; *p++ = '='; } else { - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; + *p++ = basis_64[((plainBuf[i] & 0x3) << 4) | + ((plainBuf[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((plainBuf[i + 1] & 0xF) << 2)]; } *p++ = '='; } - return (int)(p - encoded); + *p = '\0'; + return (int)(p - b64Text); } diff --git a/core/c/base64.h b/core/c/base64.h index d696b270..defa8017 100644 --- a/core/c/base64.h +++ b/core/c/base64.h @@ -57,8 +57,23 @@ #include #include -size_t Base64decode_len(const char *bufcoded); -int Base64decode(uint8_t *bufplain, const char *bufcoded); +/** + * @return The amount of bytes needed to decode the given b64Text. + */ +size_t mpw_base64_decode_max(const char *b64Text); +/** Decodes a base-64 encoded string into a plain byte buffer. + * @param plainMax the maximum amount of bytes to write to plainBuf. + * @return The amount of bytes that were written to plainBuf or -1 if this amount would have exceeded plainMax. + */ +int mpw_base64_decode(uint8_t *plainBuf, size_t plainMax, const char *b64Text); -size_t Base64encode_len(size_t len); -int Base64encode(char *encoded, const uint8_t *string, size_t len); +/** + * @return The amount of characters needed to encode a plainBuf of the given size as base-64 (excluding the terminating NUL). + */ +size_t mpw_base64_encode_max(size_t plainSize); +/** Encodes a plain byte buffer into a base-64 encoded string. + * @param b64Max the maximum amount of characters to write to b64Text, excluding the terminating NUL. + * @return The amount of characters that were written to b64Text, excluding the terminating NUL + * or -1 if this amount would have exceeded b64Max. + */ +int mpw_base64_encode(char *b64Text, size_t b64Max, const uint8_t *plainBuf, size_t plainSize); diff --git a/core/c/mpw-algorithm_v0.c b/core/c/mpw-algorithm_v0.c index 5a819d2e..5893c674 100644 --- a/core/c/mpw-algorithm_v0.c +++ b/core/c/mpw-algorithm_v0.c @@ -157,16 +157,22 @@ const char *mpw_encrypt_v0( MPMasterKey masterKey, const char *plainText) { // Encrypt - dbg( "-- encrypting plainText: %s\n", plainText ); size_t bufSize = strlen( plainText ); const uint8_t *cipherBuf = mpw_aes_encrypt( masterKey, MPMasterKeySize, (const uint8_t *)plainText, bufSize ); - dbg( "-- cipherBuf: %lu bytes = ", bufSize ); - printb( cipherBuf, bufSize ); + if (!cipherBuf) { + err( "AES encryption error: %s\n", strerror( errno ) ); + return NULL; + } + // Base64-encode - char *cipherText = calloc( 1, Base64encode_len( bufSize ) + 1 ); - Base64encode( cipherText, cipherBuf, bufSize ); - dbg( "-- b64 encoded -> cipherText: %s\n", cipherText ); + size_t b64Max = mpw_base64_encode_max( bufSize ); + char *cipherText = calloc( 1, b64Max + 1 ); + if (mpw_base64_encode( cipherText, b64Max, cipherBuf, bufSize ) < 0) { + err( "Base64 encoding error." ); + mpw_free_string( cipherText ); + cipherText = NULL; + } mpw_free( cipherBuf, bufSize ); return cipherText; @@ -176,17 +182,19 @@ const char *mpw_decrypt_v0( MPMasterKey masterKey, const char *cipherText) { // Base64-decode - dbg( "-- decrypting cipherText: %s\n", cipherText ); - size_t bufSize = Base64decode_len( cipherText ) + 1; + size_t bufSize = mpw_base64_decode_max( cipherText ); uint8_t *cipherBuf = calloc( 1, bufSize ); - Base64decode( cipherBuf, cipherText ); - dbg( "-- b64 decoded: %lu bytes = ", bufSize ); - printb( cipherBuf, bufSize ); + if ((bufSize = (size_t)mpw_base64_decode( cipherBuf, bufSize, cipherText )) < 0) { + err( "Base64 decoding error." ); + mpw_free( cipherBuf, mpw_base64_decode_max( cipherText ) ); + return NULL; + } // Decrypt const char *plainText = (const char *)mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize ); - dbg( "-- decrypted -> plainText: %s\n", plainText ); + if (!plainText) + err( "AES decryption error: %s\n", strerror( errno ) ); mpw_free( cipherBuf, bufSize ); return plainText; diff --git a/core/c/mpw-util.c b/core/c/mpw-util.c index e95fc1a0..8b5c8bde 100644 --- a/core/c/mpw-util.c +++ b/core/c/mpw-util.c @@ -185,19 +185,22 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key if (!key || keySize < crypto_stream_KEYBYTES) return NULL; - uint8_t cipherKey[crypto_stream_KEYBYTES]; - memcpy( cipherKey, key, sizeof( cipherKey ) ); - uint8_t nonce[crypto_stream_NONCEBYTES]; bzero( (void *)nonce, sizeof( nonce ) ); if (encrypt) { uint8_t *const cipherBuf = malloc( bufSize ); - crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, cipherKey ); + if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) { + mpw_free( cipherBuf, bufSize ); + return NULL; + } return cipherBuf; } else { uint8_t *const plainBuf = malloc( bufSize ); - crypto_stream_aes128ctr( plainBuf, bufSize, nonce, cipherKey ); + if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) { + mpw_free( plainBuf, bufSize ); + return NULL; + } for (size_t c = 0; c < bufSize; ++c) plainBuf[c] = buf[c] ^ plainBuf[c]; return plainBuf;