2
0

Hide app secrets such as API keys in code.

Move secret keys out of the repository and hide them in the binary.

C-string -> String decoding for unsigned strings and buffers to
facilitate conversion of various C API strings into Swift.

Some cleanup in base64 coding utility.

A utility for converting hex strings into byte buffers.

Improved checks during AES routine and fix PKCS padding bug if
plain text fits block size.
This commit is contained in:
Maarten Billemont 2020-01-02 17:04:29 -05:00
parent 8886c6a6ef
commit f999e75ebe
6 changed files with 62 additions and 31 deletions

View File

@ -3054,6 +3054,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -3543,6 +3544,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -3580,6 +3582,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",

View File

@ -80,19 +80,19 @@ static const uint8_t b64ToBits[256] =
size_t mpw_base64_decode_max(const char *b64Text) {
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
while (b64ToBits[*(b64Cursor++)] <= 63);
int b64Size = (int)(b64Cursor - (uint8_t *)b64Text) - 1;
register const char *b64Cursor = b64Text;
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
size_t b64Size = b64Cursor - b64Text;
// Every 4 b64 chars yield 3 plain bytes => len = 3 * ceil(b64Size / 4)
return (size_t)(3 /*bytes*/ * ((b64Size + 4 /*chars*/ - 1) / 4 /*chars*/));
return 3 /*bytes*/ * ((b64Size + 4 /*chars*/ - 1) / 4 /*chars*/);
}
int mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
size_t mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
while (b64ToBits[*(b64Cursor++)] <= 63);
int b64Remaining = (int)(b64Cursor - (uint8_t *)b64Text) - 1;
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
size_t b64Remaining = b64Cursor - (uint8_t *)b64Text;
b64Cursor = (uint8_t *)b64Text;
register uint8_t *plainCursor = plainBuf;
@ -112,7 +112,7 @@ int mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
if (b64Remaining > 3)
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
return (int)(plainCursor - plainBuf);
return plainCursor - plainBuf;
}
static const char basis_64[] =
@ -124,7 +124,7 @@ size_t mpw_base64_encode_max(size_t plainSize) {
return 4 /*chars*/ * (plainSize + 3 /*bytes*/ - 1) / 3 /*bytes*/;
}
int mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize) {
size_t mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize) {
size_t plainCursor = 0;
char *b64Cursor = b64Text;
@ -151,5 +151,5 @@ int mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize)
}
*b64Cursor = '\0';
return (int)(b64Cursor - b64Text);
return b64Cursor - b64Text;
}

View File

@ -69,7 +69,7 @@ size_t mpw_base64_decode_max(const char *b64Text);
* @param plainBuf a byte buffer, size should be at least mpw_base64_decode_max(b64Text)
* @return The amount of bytes that were written to plainBuf.
*/
int mpw_base64_decode(uint8_t *plainBuf, const char *b64Text);
size_t mpw_base64_decode(uint8_t *plainBuf, const char *b64Text);
/**
* @return The amount of characters needed to encode a plainBuf of the given size as base-64 (excluding the terminating NUL).
@ -79,4 +79,4 @@ size_t mpw_base64_encode_max(size_t plainSize);
* @param b64Text a character buffer, size should be at least mpw_base64_encode_max(plainSize) + 1
* @return The amount of characters that were written to b64Text, excluding the terminating NUL.
*/
int mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize);
size_t mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize);

View File

@ -169,7 +169,7 @@ const char *mpw_site_crypted_password_v0(
// Base64-decode
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText ), cipherBufSize = bufSize;
size_t bufSize = mpw_base64_decode( cipherBuf, cipherText ), cipherBufSize = bufSize;
if ((int)bufSize < 0) {
err( "Base64 decoding error." );
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );

View File

@ -398,7 +398,7 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
// We do our best to not fail on odd buf's, eg. non-padded cipher texts.
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
if (!key || keySize < AES_BLOCKLEN || !*bufSize)
if (!key || keySize < AES_BLOCKLEN || !bufSize || !*bufSize)
return NULL;
// IV = zero
@ -409,16 +409,19 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
// Add PKCS#7 padding
uint32_t aesSize = ((uint32_t)*bufSize + AES_BLOCKLEN - 1) & -AES_BLOCKLEN; // round up to block size.
if (encrypt && !(*bufSize % AES_BLOCKLEN)) // add pad block if plain text fits block size.
encrypt += AES_BLOCKLEN;
aesSize += AES_BLOCKLEN;
uint8_t *resultBuf = calloc( aesSize, sizeof( uint8_t ) );
if (!resultBuf)
return NULL;
uint8_t *aesBuf = malloc( aesSize );
memcpy( aesBuf, buf, *bufSize );
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
uint8_t *resultBuf = malloc( aesSize );
if (!resultBuf) {
mpw_free( &aesBuf, aesSize );
if (!aesBuf) {
mpw_free( &resultBuf, aesSize );
return NULL;
}
memcpy( aesBuf, buf, *bufSize );
memset( aesBuf + *bufSize, (int)(aesSize - *bufSize), aesSize - *bufSize );
if (encrypt)
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
else
@ -434,14 +437,14 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
return resultBuf;
}
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize) {
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuffer, size_t *bufferSize) {
return mpw_aes( true, key, keySize, plainBuf, bufSize );
return mpw_aes( true, key, keySize, plainBuffer, bufferSize );
}
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize) {
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuffer, size_t *bufferSize) {
return mpw_aes( false, key, keySize, cipherBuf, bufSize );
return mpw_aes( false, key, keySize, cipherBuffer, bufferSize );
}
#if UNUSED
@ -562,7 +565,7 @@ const char *mpw_hex(const void *buf, const size_t length) {
return NULL;
for (size_t kH = 0; kH < length; kH++)
sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02X", ((const uint8_t *)buf)[kH] );
sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02hhX", ((const uint8_t *)buf)[kH] );
return mpw_hex_buf[mpw_hex_buf_i];
}
@ -577,6 +580,26 @@ const char *mpw_hex_l(const uint32_t number) {
return mpw_hex( &buf, sizeof( buf ) );
}
const uint8_t *mpw_unhex(const char *hex) {
if (!hex)
return NULL;
size_t length = strlen( hex );
if (length == 0 || length % 2 != 0)
return NULL;
size_t bytes = length / 2;
uint8_t *buf = malloc( bytes );
for (size_t b = 0; b < bytes; ++b)
if (sscanf( hex + b * 2, "%02hhX", &buf[b] ) != 1) {
mpw_free( &buf, bytes );
return NULL;
}
return buf;
}
size_t mpw_utf8_charlen(const char *utf8String) {
// Legal UTF-8 byte sequences: <http://www.unicode.org/unicode/uni2errata/UTF-8_Corrigendum.html>

View File

@ -207,14 +207,16 @@ uint8_t const *mpw_kdf_blake2b(
* @return A buffer (allocated, 32-byte) containing the MAC or NULL if the key or message is missing, the MAC could not be allocated or generated. */
uint8_t const *mpw_hash_hmac_sha256(
const uint8_t *key, const size_t keySize, const uint8_t *message, const size_t messageSize);
/** Encrypt a plainBuf with the given key using AES-128-CBC.
* @return A buffer (allocated, bufSize) containing the cipherBuf or NULL if the key or buffer is missing, the key size is out of bounds or the result could not be allocated. */
/** Encrypt a plainBuffer with the given key using AES-128-CBC.
* @param bufferSize A pointer to the size of the plain buffer on input, and the size of the returned cipher buffer on output.
* @return A buffer (allocated, bufferSize) containing the cipherBuffer or NULL if the key or buffer is missing, the key size is out of bounds or the result could not be allocated. */
uint8_t const *mpw_aes_encrypt(
const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize);
/** Decrypt a cipherBuf with the given key using AES-128-CBC.
* @return A buffer (allocated, bufSize) containing the plainBuf or NULL if the key or buffer is missing, the key size is out of bounds or the result could not be allocated. */
const uint8_t *key, const size_t keySize, const uint8_t *plainBuffer, size_t *bufferSize);
/** Decrypt a cipherBuffer with the given key using AES-128-CBC.
* @param bufferSize A pointer to the size of the cipher buffer on input, and the size of the returned plain buffer on output.
* @return A buffer (allocated, bufferSize) containing the plainBuffer or NULL if the key or buffer is missing, the key size is out of bounds or the result could not be allocated. */
uint8_t const *mpw_aes_decrypt(
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize);
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuffer, size_t *bufferSize);
#if UNUSED
/** Calculate an OTP using RFC-4226.
* @return A string (allocated) containing exactly `digits` decimal OTP digits. */
@ -232,6 +234,9 @@ const char *mpw_vstr(const char *format, va_list args);
* @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */
const char *mpw_hex(const void *buf, const size_t length);
const char *mpw_hex_l(const uint32_t number);
/** Decode a string of hexadecimal characters into a buffer.
* @return A buffer (allocated, strlen(hex) / 2); or NULL if hex is NULL, empty, or not an even-length hexadecimal string. */
const uint8_t *mpw_unhex(const char *hex);
/** Encode a fingerprint for a buffer.
* @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */
const MPKeyID mpw_id_buf(const void *buf, const size_t length);