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;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -3543,6 +3544,7 @@
|
|||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -3580,6 +3582,7 @@
|
|||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -80,19 +80,19 @@ static const uint8_t b64ToBits[256] =
|
|||||||
|
|
||||||
size_t mpw_base64_decode_max(const char *b64Text) {
|
size_t mpw_base64_decode_max(const char *b64Text) {
|
||||||
|
|
||||||
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
|
register const char *b64Cursor = b64Text;
|
||||||
while (b64ToBits[*(b64Cursor++)] <= 63);
|
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
|
||||||
int b64Size = (int)(b64Cursor - (uint8_t *)b64Text) - 1;
|
size_t b64Size = b64Cursor - b64Text;
|
||||||
|
|
||||||
// Every 4 b64 chars yield 3 plain bytes => len = 3 * ceil(b64Size / 4)
|
// 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;
|
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
|
||||||
while (b64ToBits[*(b64Cursor++)] <= 63);
|
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
|
||||||
int b64Remaining = (int)(b64Cursor - (uint8_t *)b64Text) - 1;
|
size_t b64Remaining = b64Cursor - (uint8_t *)b64Text;
|
||||||
|
|
||||||
b64Cursor = (uint8_t *)b64Text;
|
b64Cursor = (uint8_t *)b64Text;
|
||||||
register uint8_t *plainCursor = plainBuf;
|
register uint8_t *plainCursor = plainBuf;
|
||||||
@ -112,7 +112,7 @@ int mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
|
|||||||
if (b64Remaining > 3)
|
if (b64Remaining > 3)
|
||||||
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
|
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
|
||||||
|
|
||||||
return (int)(plainCursor - plainBuf);
|
return plainCursor - plainBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char basis_64[] =
|
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*/;
|
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;
|
size_t plainCursor = 0;
|
||||||
char *b64Cursor = b64Text;
|
char *b64Cursor = b64Text;
|
||||||
@ -151,5 +151,5 @@ int mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*b64Cursor = '\0';
|
*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)
|
* @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.
|
* @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).
|
* @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
|
* @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.
|
* @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
|
// Base64-decode
|
||||||
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
|
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) {
|
if ((int)bufSize < 0) {
|
||||||
err( "Base64 decoding error." );
|
err( "Base64 decoding error." );
|
||||||
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
|
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.
|
// 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) {
|
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;
|
return NULL;
|
||||||
|
|
||||||
// IV = zero
|
// 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
|
// Add PKCS#7 padding
|
||||||
uint32_t aesSize = ((uint32_t)*bufSize + AES_BLOCKLEN - 1) & -AES_BLOCKLEN; // round up to block size.
|
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.
|
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 );
|
uint8_t *aesBuf = malloc( aesSize );
|
||||||
memcpy( aesBuf, buf, *bufSize );
|
if (!aesBuf) {
|
||||||
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
mpw_free( &resultBuf, aesSize );
|
||||||
uint8_t *resultBuf = malloc( aesSize );
|
|
||||||
if (!resultBuf) {
|
|
||||||
mpw_free( &aesBuf, aesSize );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy( aesBuf, buf, *bufSize );
|
||||||
|
memset( aesBuf + *bufSize, (int)(aesSize - *bufSize), aesSize - *bufSize );
|
||||||
|
|
||||||
if (encrypt)
|
if (encrypt)
|
||||||
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
||||||
else
|
else
|
||||||
@ -434,14 +437,14 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
|
|||||||
return resultBuf;
|
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
|
#if UNUSED
|
||||||
@ -562,7 +565,7 @@ const char *mpw_hex(const void *buf, const size_t length) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (size_t kH = 0; kH < length; kH++)
|
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];
|
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 ) );
|
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) {
|
size_t mpw_utf8_charlen(const char *utf8String) {
|
||||||
|
|
||||||
// Legal UTF-8 byte sequences: <http://www.unicode.org/unicode/uni2errata/UTF-8_Corrigendum.html>
|
// 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. */
|
* @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(
|
uint8_t const *mpw_hash_hmac_sha256(
|
||||||
const uint8_t *key, const size_t keySize, const uint8_t *message, const size_t messageSize);
|
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.
|
/** Encrypt a plainBuffer 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. */
|
* @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(
|
uint8_t const *mpw_aes_encrypt(
|
||||||
const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize);
|
const uint8_t *key, const size_t keySize, const uint8_t *plainBuffer, size_t *bufferSize);
|
||||||
/** Decrypt a cipherBuf with the given key using AES-128-CBC.
|
/** Decrypt a cipherBuffer 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. */
|
* @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(
|
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
|
#if UNUSED
|
||||||
/** Calculate an OTP using RFC-4226.
|
/** Calculate an OTP using RFC-4226.
|
||||||
* @return A string (allocated) containing exactly `digits` decimal OTP digits. */
|
* @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. */
|
* @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(const void *buf, const size_t length);
|
||||||
const char *mpw_hex_l(const uint32_t number);
|
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.
|
/** Encode a fingerprint for a buffer.
|
||||||
* @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */
|
* @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);
|
const MPKeyID mpw_id_buf(const void *buf, const size_t length);
|
||||||
|
Loading…
Reference in New Issue
Block a user