diff --git a/src/wp_krb5kdf.c b/src/wp_krb5kdf.c index ced802e9..df591056 100644 --- a/src/wp_krb5kdf.c +++ b/src/wp_krb5kdf.c @@ -292,84 +292,134 @@ static int wp_kdf_krb5kdf_expected_key_size(wp_Krb5kdfCtx* ctx) * s[l] = (constant rot 13*(l/K))[l%k] * block[l % N] += s[l] (with carry) * finally add carry if any + * + * @param [in] block Block to fill with constant. + * @param [in] blocksize Size of block in bytes. + * @param [in] constant Constant to use for fill. + * @param [in] constant_len Length of constant in bytes. Not zero and less + * than or equal to blocksize. */ static void n_fold(unsigned char *block, unsigned int blocksize, const unsigned char *constant, size_t constant_len) { - unsigned int cnt; - unsigned int i; + unsigned int const_len = (unsigned int)constant_len; unsigned int a; unsigned int b; + unsigned int cnt; unsigned int carry; - unsigned int rot; unsigned int bi; - unsigned int const_len = (unsigned int)constant_len; + unsigned int rot; + unsigned int i; + + /* Copy in unrotated constant first. */ + XMEMCPY(block, constant, constant_len); /* If equal size then only one unrotated copy of constant needed. */ if (blocksize == const_len) { - XMEMCPY(block, constant, constant_len); return; } - /* Compute GCD of constant_len and blocksize. */ - a = blocksize; - b = const_len; - while (b != 0) { + /* Compute first iteration of GCD of constant_len and blocksize. */ + a = const_len; + b = blocksize % const_len; + + if (b == 0) { + /* Fill rest of block with rotated constant - no adding. */ + /* First rotate amount. */ + rot = 13; + for (i = const_len; i < blocksize; i += const_len) { + unsigned int j; + /* Calculate first index into constant to rotate. */ + unsigned int ci = (i - (rot >> 3) - 1) % const_len; + /* Calculate amount to rotate right and left. */ + unsigned char rr = rot & 0x7; + unsigned char rl = 8 - rr; + /* Load first constant value - large type to handle shift 8. */ + unsigned int cv = constant[ci]; + + for (j = 0; j < const_len; j++) { + /* Get rotated constant buffer value. */ + block[i + j] = (unsigned char)(cv << rl); + /* Calculate next constant index. */ + ci = (ci + 1) % const_len; + /* Load next constant value. */ + cv = constant[ci]; + /* OR in second rotated value. */ + block[i + j] |= (unsigned char)(cv >> rr); + } + /* Update rotate amount. */ + rot += 13; + } + return; + } + + /* Complete computation of GCD of constant_len and blocksize. */ + do { unsigned int t = b; b = a % b; a = t; - } + } while (b != 0); /* Calculate LCM of constant_len and blocksize. */ cnt = (const_len * blocksize) / a; - /* Start with constant un-rotated and then add to zero for the rest. */ - XMEMCPY(block, constant, constant_len); + /* Set rest to zero for add. */ XMEMSET(block + constant_len, 0, blocksize - constant_len); /* No initial carry. */ carry = 0; - /* First rotation is 13 bits. */ - rot = 13; - /* Starting block index - constant_len <= blocksize. */ - bi = const_len; + /* Last block is first as we are adding in reverse. */ + bi = blocksize - 1; + /* Rotation count for when adding last constant. */ + rot = 13 * ((cnt - const_len) / const_len); /* Do one constant at a time - cnt is a multiple of constant_len. */ - for (i = const_len; i < cnt; i += const_len) { - unsigned int j; - /* Calculate first index into constant to rotate. */ - unsigned int ci = ((cnt - (rot >> 3)) - 1) % const_len; - /* Calculate amount to rotate right and left. */ - unsigned char rr = rot & 0x7; - unsigned char rl = 8 - rr; - - /* Add in constant buffer to block. */ - for (j = 0; j < const_len; j++) { - /* Rotated constant value. */ - unsigned char rcv; - - /* Get rotated constant buffer value. */ - rcv = (unsigned char)(constant[ci] << rl); - ci = (ci + 1) % const_len; - rcv |= (unsigned char)(constant[ci] >> rr); - - /* Add block value and rotated constant value to previous carry. */ - carry += block[bi]; - carry += rcv; - /* Store new block value. */ - block[bi] = (unsigned char)(carry & 0xff); - /* Get carry. */ - carry >>= 8; - - /* Next block index. */ - bi = (bi + 1) % blocksize; - } - rot += 13; + for (i = cnt - const_len; i >= const_len; i -= const_len) { + int j; + /* Calculate last index into constant to rotate. */ + unsigned int ci = (i - (rot >> 3) - 1) % const_len; + /* Calculate amount to rotate right and left. */ + unsigned char rr = rot & 0x7; + unsigned char rl = 8 - rr; + /* Load first constant value - large type to handle shift 8. */ + unsigned int cv = constant[ci]; + + /* Add in constant buffer to block. */ + for (j = const_len - 1; j >= 0; j--) { + /* Rotated constant value. */ + unsigned char rcv; + + /* Get rotated constant buffer value. */ + rcv = (unsigned char)(cv >> rr); + /* Calculate next constant index. */ + ci = (ci + (const_len - 1)) % const_len; + /* Load next constant value. */ + cv = constant[ci]; + /* OR in second rotated value. */ + rcv |= (unsigned char)(cv << rl); + + /* Add block value and rotated constant value to previous carry. */ + carry += block[bi]; + carry += rcv; + /* Store new block value. */ + block[bi] = (unsigned char)(carry & 0xff); + /* Get carry. */ + carry >>= 8; + /* Previous block index. */ + bi = (bi + (blocksize - 1)) % blocksize; + } + /* Calculate rotation for previous constant block. */ + rot -= 13; } /* Final carry pass. */ - for (i = 0; (i < blocksize) && (carry > 0); i++) { - carry += block[i]; - block[i] = (unsigned char)(carry & 0xff); + while (carry > 0) { + /* Add block value to previous carry. */ + carry += block[bi]; + /* Store new block value. */ + block[bi] = (unsigned char)(carry & 0xff); + /* Get carry. */ carry >>= 8; + /* Previous block index. */ + bi = (bi + (blocksize - 1)) % blocksize; } } diff --git a/test/test_krb5kdf.c b/test/test_krb5kdf.c index 6ca5e404..a96aeed1 100644 --- a/test/test_krb5kdf.c +++ b/test/test_krb5kdf.c @@ -113,6 +113,17 @@ static int test_krb5kdf_error_cases(OSSL_LIB_CTX* libCtx) } PRINT_MSG("Negative test passed - KRB5KDF correctly rejected wrong key size for AES-256-CBC"); + PRINT_MSG("Testing KRB5KDF error case - 0 length constant"); + /* This should fail since AES-256 key size is 32 bytes */ + err = test_krb5kdf_calc(libCtx, key, sizeof(key), "AES-256-CBC", + inKey16, sizeof(inKey16), constant, 0); + if (err == 0) { + /* If we get here, the test failed because it should have errored */ + PRINT_MSG("FAILED: KRB5KDF accepted 0 length constant"); + return 1; + } + PRINT_MSG("Negative test passed - KRB5KDF correctly rejected 0 length constant"); + return 0; } @@ -120,6 +131,7 @@ static int test_krb5kdf_error_cases(OSSL_LIB_CTX* libCtx) static int test_krb5kdf_vector(void) { int err = 0; + int i; unsigned char oKey[32]; unsigned char wKey[32]; /* Test vector - AES-128-CBC */ @@ -135,51 +147,55 @@ static int test_krb5kdf_vector(void) 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 }; unsigned char constant[] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; - /* Test AES-128-CBC */ - PRINT_MSG("Testing KRB5KDF with OpenSSL - AES-128-CBC"); - err = test_krb5kdf_calc(osslLibCtx, oKey, 16, "AES-128-CBC", - inKey128, sizeof(inKey128), constant, sizeof(constant)); - if (err == 1) { - PRINT_MSG("FAILED OpenSSL - AES-128-CBC"); - return err; - } - PRINT_MSG("Testing KRB5KDF with wolfSSL - AES-128-CBC"); - err = test_krb5kdf_calc(wpLibCtx, wKey, 16, "AES-128-CBC", - inKey128, sizeof(inKey128), constant, sizeof(constant)); - if (err == 1) { - PRINT_MSG("FAILED wolfSSL - AES-128-CBC"); - return err; - } - if (memcmp(oKey, wKey, 16) != 0) { - PRINT_MSG("FAILED, wolfSSL and OpenSSL derived different keys"); - PRINT_BUFFER("OpenSSL key", oKey, 16); - PRINT_BUFFER("wolfSSL key", wKey, 16); - return 1; - } - - /* Test AES-256-CBC */ - PRINT_MSG("Testing KRB5KDF with OpenSSL - AES-256-CBC"); - err = test_krb5kdf_calc(osslLibCtx, oKey, 32, "AES-256-CBC", - inKey256, sizeof(inKey256), constant, sizeof(constant)); - if (err == 1) { - PRINT_MSG("FAILED OpenSSL - AES-256-CBC"); - return err; - } - PRINT_MSG("Testing KRB5KDF with wolfSSL - AES-256-CBC"); - err = test_krb5kdf_calc(wpLibCtx, wKey, 32, "AES-256-CBC", - inKey256, sizeof(inKey256), constant, sizeof(constant)); - if (err == 1) { - PRINT_MSG("FAILED wolfSSL - AES-256-CBC"); - return err; - } - if (memcmp(oKey, wKey, 32) != 0) { - PRINT_MSG("FAILED, wolfSSL and OpenSSL derived different keys"); - PRINT_BUFFER("OpenSSL key", oKey, 32); - PRINT_BUFFER("wolfSSL key", wKey, 32); - return 1; + for (i = 1; i < (int)sizeof(constant); i++) { + PRINT_MSG("Constant Length: %d", i); + /* Test AES-128-CBC */ + PRINT_MSG("Testing KRB5KDF with OpenSSL - AES-128-CBC"); + err = test_krb5kdf_calc(osslLibCtx, oKey, 16, "AES-128-CBC", + inKey128, sizeof(inKey128), constant, i); + if (err == 1) { + PRINT_MSG("FAILED OpenSSL - AES-128-CBC"); + return err; + } + PRINT_MSG("Testing KRB5KDF with wolfSSL - AES-128-CBC"); + err = test_krb5kdf_calc(wpLibCtx, wKey, 16, "AES-128-CBC", + inKey128, sizeof(inKey128), constant, i); + if (err == 1) { + PRINT_MSG("FAILED wolfSSL - AES-128-CBC"); + return err; + } + if (memcmp(oKey, wKey, 16) != 0) { + PRINT_MSG("FAILED, wolfSSL and OpenSSL derived different keys"); + PRINT_BUFFER("OpenSSL key", oKey, 16); + PRINT_BUFFER("wolfSSL key", wKey, 16); + return 1; + } + + /* Test AES-256-CBC */ + PRINT_MSG("Testing KRB5KDF with OpenSSL - AES-256-CBC"); + err = test_krb5kdf_calc(osslLibCtx, oKey, 32, "AES-256-CBC", + inKey256, sizeof(inKey256), constant, i); + if (err == 1) { + PRINT_MSG("FAILED OpenSSL - AES-256-CBC"); + return err; + } + PRINT_MSG("Testing KRB5KDF with wolfSSL - AES-256-CBC"); + err = test_krb5kdf_calc(wpLibCtx, wKey, 32, "AES-256-CBC", + inKey256, sizeof(inKey256), constant, i); + if (err == 1) { + PRINT_MSG("FAILED wolfSSL - AES-256-CBC"); + return err; + } + if (memcmp(oKey, wKey, 32) != 0) { + PRINT_MSG("FAILED, wolfSSL and OpenSSL derived different keys"); + PRINT_BUFFER("OpenSSL key", oKey, 32); + PRINT_BUFFER("wolfSSL key", wKey, 32); + return 1; + } } return err;