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:
parent
8886c6a6ef
commit
f999e75ebe
@ -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)",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 ) );
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user