diff --git a/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj b/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj index 7ecad5dd..33948725 100644 --- a/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj +++ b/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj @@ -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)", diff --git a/platform-independent/c/core/src/base64.c b/platform-independent/c/core/src/base64.c index 5ec59496..bdb886e6 100644 --- a/platform-independent/c/core/src/base64.c +++ b/platform-independent/c/core/src/base64.c @@ -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; } diff --git a/platform-independent/c/core/src/base64.h b/platform-independent/c/core/src/base64.h index 1c5b38c4..8ff83b38 100644 --- a/platform-independent/c/core/src/base64.h +++ b/platform-independent/c/core/src/base64.h @@ -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); diff --git a/platform-independent/c/core/src/mpw-algorithm_v0.c b/platform-independent/c/core/src/mpw-algorithm_v0.c index a729aac3..1d98ad48 100644 --- a/platform-independent/c/core/src/mpw-algorithm_v0.c +++ b/platform-independent/c/core/src/mpw-algorithm_v0.c @@ -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 ) ); diff --git a/platform-independent/c/core/src/mpw-util.c b/platform-independent/c/core/src/mpw-util.c index 5e195434..9db0dc6c 100644 --- a/platform-independent/c/core/src/mpw-util.c +++ b/platform-independent/c/core/src/mpw-util.c @@ -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: diff --git a/platform-independent/c/core/src/mpw-util.h b/platform-independent/c/core/src/mpw-util.h index 978d2a51..01f36b7b 100644 --- a/platform-independent/c/core/src/mpw-util.h +++ b/platform-independent/c/core/src/mpw-util.h @@ -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);