Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 99 additions & 49 deletions src/wp_krb5kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
100 changes: 58 additions & 42 deletions test/test_krb5kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,25 @@ 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;
}

/* Test vectors */
static int test_krb5kdf_vector(void)
{
int err = 0;
int i;
unsigned char oKey[32];
unsigned char wKey[32];
/* Test vector - AES-128-CBC */
Expand All @@ -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;
Expand Down
Loading