Index: src/pbkdf2.h ================================================================== --- src/pbkdf2.h +++ src/pbkdf2.h @@ -49,11 +49,11 @@ /*! @brief The buffer to write the key to. */ unsigned char *key; /*! * @brief The desired length for the derived key. * - * @ref key needs to have enough storage). + * @ref key needs to have enough storage. */ size_t keyLength; /*! @brief Whether data may be stored in swappable memory. */ bool allowsSwappableMemory; } of_pbkdf2_parameters_t; Index: src/scrypt.h ================================================================== --- src/scrypt.h +++ src/scrypt.h @@ -28,10 +28,40 @@ /*! @file */ @class OFHMAC; +/*! + * @brief The parameters for @ref of_scrypt. + */ +typedef struct of_scrypt_parameters_t { + /*! @brief The block size to use. */ + size_t blockSize; + /*! @brief The CPU/memory cost factor to use. */ + size_t costFactor; + /*! @brief The parallelization to use. */ + size_t parallelization; + /*! @brief The salt to derive a key with. */ + const unsigned char *salt; + /*! @brief The length of the salt. */ + size_t saltLength; + /*! @brief The password to derive a key from. */ + const char *password; + /*! @brief The length of the password. */ + size_t passwordLength; + /*! @brief The buffer to write the key to. */ + unsigned char *key; + /*! + * @brief The desired length for the derived key. + * + * @ref key needs to have enough storage. + */ + size_t keyLength; + /*! @brief Whether data may be stored in swappable memory. */ + bool allowsSwappableMemory; +} of_scrypt_parameters_t; + #ifdef __cplusplus extern "C" { #endif extern void of_salsa20_8_core(uint32_t buffer[_Nonnull 16]); extern void of_scrypt_block_mix(uint32_t *output, const uint32_t *input, @@ -40,26 +70,13 @@ size_t costFactor, uint32_t *tmp); /*! * @brief Derives a key from a password and a salt using scrypt. * - * @param blockSize The block size to use - * @param costFactor The CPU/memory cost factor to use - * @param parallelization The parallelization to use - * @param salt The salt to derive a key with - * @param saltLength The length of the salt - * @param password The password to derive a key from - * @param passwordLength The length of the password - * @param key The buffer to write the key to - * @param keyLength The desired length for the derived key (`key` needs to have - * enough storage) - * @param allowsSwappableMemory Whether data may be stored in swappable memory + * @param param The parameters to use */ -extern void of_scrypt(size_t blockSize, size_t costFactor, - size_t parallelization, const unsigned char *salt, size_t saltLength, - const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength, bool allowsSwappableMemory); +extern void of_scrypt(of_scrypt_parameters_t param); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/scrypt.m ================================================================== --- src/scrypt.m +++ src/scrypt.m @@ -83,12 +83,12 @@ { uint32_t tmp[16]; /* Check defined here and executed in of_scrypt() */ #define OVERFLOW_CHECK_1 \ - if (blockSize > SIZE_MAX / 2 || \ - 2 * blockSize - 1 > SIZE_MAX / 16) \ + if (param.blockSize > SIZE_MAX / 2 || \ + 2 * param.blockSize - 1 > SIZE_MAX / 16) \ @throw [OFOutOfRangeException exception]; memcpy(tmp, input + (2 * blockSize - 1) * 16, 64); for (size_t i = 0; i < 2 * blockSize; i++) { @@ -110,12 +110,12 @@ void of_scrypt_romix(uint32_t *buffer, size_t blockSize, size_t costFactor, uint32_t *tmp) { /* Check defined here and executed in of_scrypt() */ -#define OVERFLOW_CHECK_2 \ - if (blockSize > SIZE_MAX / 128 / costFactor) \ +#define OVERFLOW_CHECK_2 \ + if (param.blockSize > SIZE_MAX / 128 / param.costFactor) \ @throw [OFOutOfRangeException exception]; uint32_t *tmp2 = tmp + 32 * blockSize; memcpy(tmp, buffer, 128 * blockSize); @@ -137,20 +137,19 @@ if (i < costFactor - 1) memcpy(tmp, buffer, 128 * blockSize); } } -void of_scrypt(size_t blockSize, size_t costFactor, - size_t parallelization, const unsigned char *salt, size_t saltLength, - const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength, bool allowsSwappableMemory) +void +of_scrypt(of_scrypt_parameters_t param) { OFSecureData *tmp = nil, *buffer = nil; OFHMAC *HMAC = nil; - if (blockSize == 0 || costFactor <= 1 || - (costFactor & (costFactor - 1)) != 0 || parallelization == 0) + if (param.blockSize == 0 || param.costFactor <= 1 || + (param.costFactor & (param.costFactor - 1)) != 0 || + param.parallelization == 0) @throw [OFInvalidArgumentException exception]; /* * These are defined by the functions above. They are defined there so * that the check is next to the code and easy to verify, but actually @@ -160,61 +159,63 @@ OVERFLOW_CHECK_2 @try { uint32_t *tmpItems, *bufferItems; - if (costFactor > SIZE_MAX - 1 || - (costFactor + 1) > SIZE_MAX / 128) + if (param.costFactor > SIZE_MAX - 1 || + (param.costFactor + 1) > SIZE_MAX / 128) @throw [OFOutOfRangeException exception]; tmp = [[OFSecureData alloc] - initWithItemSize: blockSize - count: (costFactor + 1) * 128 - allowsSwappableMemory: allowsSwappableMemory]; + initWithItemSize: param.blockSize + count: (param.costFactor + 1) * 128 + allowsSwappableMemory: param.allowsSwappableMemory]; tmpItems = tmp.mutableItems; - if (parallelization > SIZE_MAX / 128) + if (param.parallelization > SIZE_MAX / 128) @throw [OFOutOfRangeException exception]; buffer = [[OFSecureData alloc] - initWithItemSize: blockSize - count: parallelization * 128 - allowsSwappableMemory: allowsSwappableMemory]; + initWithItemSize: param.blockSize + count: param.parallelization * 128 + allowsSwappableMemory: param.allowsSwappableMemory]; bufferItems = buffer.mutableItems; HMAC = [[OFHMAC alloc] initWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: allowsSwappableMemory]; + allowsSwappableMemory: param.allowsSwappableMemory]; of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = salt, - .saltLength = saltLength, - .password = password, - .passwordLength = passwordLength, - .key = (unsigned char *)bufferItems, - .keyLength = parallelization * 128 * blockSize, - .allowsSwappableMemory = allowsSwappableMemory + .HMAC = HMAC, + .iterations = 1, + .salt = param.salt, + .saltLength = param.saltLength, + .password = param.password, + .passwordLength = param.passwordLength, + .key = (unsigned char *)bufferItems, + .keyLength = param.parallelization * 128 * + param.blockSize, + .allowsSwappableMemory = param.allowsSwappableMemory }); - for (size_t i = 0; i < parallelization; i++) - of_scrypt_romix(bufferItems + i * 32 * blockSize, - blockSize, costFactor, tmpItems); + for (size_t i = 0; i < param.parallelization; i++) + of_scrypt_romix(bufferItems + i * 32 * param.blockSize, + param.blockSize, param.costFactor, tmpItems); of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)bufferItems, - .saltLength = parallelization * 128 * blockSize, - .password = password, - .passwordLength = passwordLength, - .key = key, - .keyLength = keyLength, - .allowsSwappableMemory = allowsSwappableMemory + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)bufferItems, + .saltLength = param.parallelization * 128 * + param.blockSize, + .password = param.password, + .passwordLength = param.passwordLength, + .key = param.key, + .keyLength = param.keyLength, + .allowsSwappableMemory = param.allowsSwappableMemory }); } @finally { [tmp release]; [buffer release]; [HMAC release]; } } Index: tests/PBKDF2Tests.m ================================================================== --- tests/PBKDF2Tests.m +++ tests/PBKDF2Tests.m @@ -33,99 +33,95 @@ /* Test vectors from RFC 6070 */ TEST(@"PBKDF2-SHA1, 1 iteration", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, .allowsSwappableMemory = true - })) && - memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5\x24\xAF" - "\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) + })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" + "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) TEST(@"PBKDF2-SHA1, 2 iterations", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 2, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, + .HMAC = HMAC, + .iterations = 2, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, .allowsSwappableMemory = true - })) && - memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9\x2A\xCE" - "\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) + })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" + "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) TEST(@"PBKDF2-SHA1, 4096 iterations", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, .allowsSwappableMemory = true - })) && - memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49\xD9\x26" - "\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) + })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" + "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) /* This test takes too long, even on a fast machine. */ #if 0 TEST(@"PBKDF2-SHA1, 16777216 iterations", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 16777216, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, + .HMAC = HMAC, + .iterations = 16777216, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, .allowsSwappableMemory = true - })) && - memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B\x3D\x6B" - "\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) + })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" + "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) #endif TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", - .saltLength = 36, - .password = "passwordPASSWORDpassword", - .passwordLength = 24, - .key = key, - .keyLength = 25, + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"saltSALTsaltSALTsalt" + "SALTsaltSALTsalt", + .saltLength = 36, + .password = "passwordPASSWORDpassword", + .passwordLength = 24, + .key = key, + .keyLength = 25, .allowsSwappableMemory = true })) && memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" - "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) + "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"sa\0lt", - .saltLength = 5, - .password = "pass\0word", - .passwordLength = 9, - .key = key, - .keyLength = 16, + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"sa\0lt", + .saltLength = 5, + .password = "pass\0word", + .passwordLength = 9, + .key = key, + .keyLength = 16, .allowsSwappableMemory = true - })) && - memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7\xF0\x34" - "\x25\xE0\xC3", 16) == 0) + })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" + "\xF0\x34\x25\xE0\xC3", 16) == 0) objc_autoreleasePoolPop(pool); } @end Index: tests/ScryptTests.m ================================================================== --- tests/ScryptTests.m +++ tests/ScryptTests.m @@ -154,28 +154,66 @@ R(memcpy(ROMixBuffer, ROMixInput, 128)) && R(of_scrypt_romix(ROMixBuffer, 1, 16, ROMixTmp)) && memcmp(ROMixBuffer, ROMixOutput, 128) == 0) TEST(@"scrypt test vector #1", - R(of_scrypt(1, 16, 1, (unsigned char *)"", 0, "", 0, output, 64, - true)) && memcmp(output, testVector1, 64) == 0) + R(of_scrypt((of_scrypt_parameters_t){ + .blockSize = 1, + .costFactor = 16, + .parallelization = 1, + .salt = (unsigned char *)"", + .saltLength = 0, + .password = "", + .passwordLength = 0, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector1, 64) == 0) TEST(@"scrypt test vector #2", - R(of_scrypt(8, 1024, 16, (unsigned char *)"NaCl", 4, "password", 8, - output, 64, true)) && memcmp(output, testVector2, 64) == 0) + R(of_scrypt((of_scrypt_parameters_t){ + .blockSize = 8, + .costFactor = 1024, + .parallelization = 16, + .salt = (unsigned char *)"NaCl", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector2, 64) == 0) TEST(@"scrypt test vector #3", - R(of_scrypt(8, 16384, 1, (unsigned char *)"SodiumChloride", 14, - "pleaseletmein", 13, output, 64, true)) && - memcmp(output, testVector3, 64) == 0) + R(of_scrypt((of_scrypt_parameters_t){ + .blockSize = 8, + .costFactor = 16384, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector3, 64) == 0) /* The forth test vector is too expensive to include it in the tests. */ #if 0 TEST(@"scrypt test vector #4", - R(of_scrypt(8, 1048576, 1, (unsigned char *)"SodiumChloride", 14, - "pleaseletmein", 13, output, 64, true)) && - memcmp(output, testVector4, 64) == 0) + R(of_scrypt((of_scrypt_parameters_t){ + .blockSize = 8, + .costFactor = 1048576, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector4, 64) == 0) #endif objc_autoreleasePoolPop(pool); } @end