Commit 85d7f62c authored by Geoff Simmons's avatar Geoff Simmons

Test encryption against the example in ch 3.2 of RFC8188.

Exposed a bug in padding that has been fixed.
parent 0e70d1a7
......@@ -86,11 +86,11 @@ encode_header(uint8_t *hdr, uint32_t rs, uint8_t idlen, uint8_t *keyid)
int
add_salt(unsigned char *hdr, char *errmsg)
{
if (RAND_bytes(hdr, SALT_LEN) != 1) {
mk_error(errmsg);
return (-1);
}
return 0;
if (RAND_bytes(hdr, SALT_LEN) != 1) {
mk_error(errmsg);
return (-1);
}
return 0;
}
/* ch 2.2 pseudorandom key */
......@@ -272,7 +272,7 @@ encrypt_record(EVP_CIPHER_CTX *ctx, unsigned char *plaintext,
unsigned char nonce[NONCE_LEN], int last, unsigned char *ciphertext,
char errmsg[ERRMSG_LEN])
{
int delim_idx, len, ciphertext_len;
int len, ciphertext_len;
uint8_t *tag;
AN(ctx);
......@@ -285,12 +285,11 @@ encrypt_record(EVP_CIPHER_CTX *ctx, unsigned char *plaintext,
assert(rs >= 18);
assert((unsigned)plaintext_len <= rs - (TAG_LEN + 1));
delim_idx = rs - (TAG_LEN + 1);
if (!last)
plaintext[delim_idx] = '\1';
plaintext[plaintext_len] = '\1';
else
plaintext[delim_idx] = '\2';
for (int i = delim_idx - 1; i > plaintext_len; i--)
plaintext[plaintext_len] = '\2';
for (unsigned i = plaintext_len + 1; i < rs - TAG_LEN; i++)
plaintext[i] = '\0';
if (EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, cek, nonce, -1)
......@@ -317,8 +316,9 @@ encrypt_record(EVP_CIPHER_CTX *ctx, unsigned char *plaintext,
return (-1);
}
ciphertext_len += len;
assert((unsigned)ciphertext_len == rs - TAG_LEN);
tag = ciphertext + (rs - TAG_LEN);
tag = ciphertext + ciphertext_len;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_LEN, tag)) {
mk_error(errmsg);
return (-1);
......
......@@ -165,17 +165,24 @@ ssize_t decrypt_record(EVP_CIPHER_CTX *ctx, unsigned char *ciphertext,
* ciphertext
*
* The buffer at plaintext MUST have at least rs bytes allocated.
* plaintext is modified for padding during the call; make a copy if the
* original plaintext must be retained. This is necessary in particular
* when more than one record is required for a message, since the
* plaintext for subsequent records must begin at a location that will
* have been overwritten.
*
* plaintext_len MAY NOT be > rs - (TAG_LEN + 1).
*
* rs for every record MUST equal the record size set for the entire
* message, except possibly for the last record, which may be smaller.
*
* If last is non-zero, then this is the last record in the message.
*
* At least rs bytes must be allocated for the buffer at ciphertext.
* The authentication tag is appended at ciphertext + (rs - TAG_LEN).
*
* Returns -1 on error, otherwise the number of ciphertext bytes. That
* number will be equal to rs for every record but the last, which may be
* smaller.
* number will be equal to (rs - TAG_LEN) for every record.
*/
ssize_t encrypt_record(EVP_CIPHER_CTX *ctx, unsigned char *plaintext,
int plaintext_len, uint32_t rs, uint8_t cek[AES128_KEYLEN],
......
......@@ -77,6 +77,7 @@ const unsigned char body2_b64[] =
"uNCkWiNYzKTnBN9ji3+qWAAAABkCYTHOG8chz/gnvgOqdGYovxyjuqRyJFjEDyoF1Fvkj6hQPdPHI51OEUKEpgz3SsLWIqS/uA==",
key2_b64[] = "BO3ZVPxUlnLORbVGMpbT1Q==",
exp_keyid2[] = "a1";
static const int exp_bodylen2 = 73;
static const uint32_t exp_rs2 = 25;
static const uint8_t exp_idlen2 = 2;
......@@ -85,7 +86,7 @@ main(int argc, char *argv[])
{
EVP_CIPHER_CTX *ctx;
unsigned char prk_b64[45], cek_b64[25], nonce_b64[17],
body1_test_b64[73];
body1_test_b64[73], body2_test_b64[101];
unsigned char key1[AES128_KEYLEN + 2], key2[AES128_KEYLEN + 2],
salt[SALT_LEN + 2], prk[SHA256_LEN], cek[SHA256_LEN],
nonce[SHA256_LEN], seq[NONCE_LEN],
......@@ -93,7 +94,7 @@ main(int argc, char *argv[])
char errmsg[ERRMSG_LEN];
uint32_t rs;
uint8_t idlen;
int len, last, plaintext_len;
int len, last, plaintext_len, ciphertext_len;
(void)argc;
(void)argv;
......@@ -162,10 +163,7 @@ main(int argc, char *argv[])
/* example 2, ch 3.2 */
if ((ctx = cipher_ctx_reset(ctx, 0, errmsg)) == NULL) {
fprintf(stderr, "ex2: cipher_ctx_reset: %s\n", errmsg);
exit(-1);
}
memset(plaintext, 0x00, sizeof(plaintext));
len = EVP_DecodeBlock(key2, key2_b64, sizeof(key2_b64) - 1);
assert(len == AES128_KEYLEN + 2);
......@@ -178,15 +176,15 @@ main(int argc, char *argv[])
AZ(memcmp(&body2[HDR_PREFIX_LEN], exp_keyid2, idlen));
if (derive_prk(body2, key2, prk, errmsg) != 0) {
fprintf(stderr, "ex2 PRK: %s\n", errmsg);
fprintf(stderr, "ex2 decrypt PRK: %s\n", errmsg);
exit(-1);
}
if (derive_cek(prk, cek, errmsg) != 0) {
fprintf(stderr, "ex2 CEK: %s\n", errmsg);
fprintf(stderr, "ex2 decrypt CEK: %s\n", errmsg);
exit(-1);
}
if (derive_prenonce(prk, nonce, errmsg) != 0) {
fprintf(stderr, "ex2 NONCE: %s\n", errmsg);
fprintf(stderr, "ex2 decrypt NONCE: %s\n", errmsg);
exit(-1);
}
......@@ -222,7 +220,7 @@ main(int argc, char *argv[])
/* example 1, ch 3.1, encryption */
memset(plaintext, 0xff, 64);
memset(plaintext, 0xff, sizeof(plaintext));
memcpy(plaintext, exp_plaintext, exp_plaintext_len);
/* Ordinarily call add_salt() to get random salt. */
......@@ -278,12 +276,78 @@ main(int argc, char *argv[])
len = EVP_EncodeBlock(body1_test_b64, body1, bodylen1);
assert(len == 72);
AZ(memcmp(body1_test_b64, body1_b64, len));
cipher_ctx_fini(ctx);
/* example 2, ch 3.2, encryption */
memset(plaintext, 0, sizeof(plaintext));
memcpy(plaintext, exp_plaintext, exp_plaintext_len);
/*
* The salt previously decoded for the decryption test is still in
* body2.
*/
memset(body2 + SALT_LEN, 0xff, sizeof(body2) - SALT_LEN);
encode_header(body2, exp_rs2, exp_idlen2, (uint8_t *)exp_keyid2);
if (derive_prk(body2, key2, prk, errmsg) != 0) {
fprintf(stderr, "ex2 encrypt PRK: %s\n", errmsg);
exit(-1);
}
if (derive_cek(prk, cek, errmsg) != 0) {
fprintf(stderr, "ex2 encrypt CEK: %s\n", errmsg);
exit(-1);
}
if (derive_prenonce(prk, nonce, errmsg) != 0) {
fprintf(stderr, "ex2 encrypt NONCE: %s\n", errmsg);
exit(-1);
}
if ((ctx = cipher_ctx_init(1, errmsg)) == NULL) {
fprintf(stderr, "ex2 encrypt: cipher_ctx_init: %s\n", errmsg);
exit(-1);
}
/* First record, first 7 bytes of the plaintext */
last = 0;
ciphertext = body2 + HDR_PREFIX_LEN + exp_idlen2;
len = encrypt_record(ctx, plaintext, 7, exp_rs2, cek, nonce, last,
ciphertext, errmsg);
if (len < 0) {
fprintf(stderr, "ex2 1st record encrypt_record: %s\n", errmsg);
exit(-1);
}
assert((unsigned)len == exp_rs2 - TAG_LEN);
ciphertext_len = exp_rs2;
/* Second record, last 8 bytes of the plaintext */
seq[NONCE_LEN - 1] = 1; // simulates increment
for (int i = 0; i < NONCE_LEN; i++)
nonce[i] ^= seq[i];
ciphertext += ciphertext_len;
last = 1;
/* plaintext was overwritten for padding */
memcpy(plaintext, exp_plaintext, exp_plaintext_len);
len = encrypt_record(ctx, plaintext + 7, 8, exp_rs2, cek, nonce, last,
ciphertext, errmsg);
if (len < 0) {
fprintf(stderr, "ex1 2nd record encrypt_record: %s\n", errmsg);
exit(-1);
}
assert((unsigned)len == exp_rs2 - TAG_LEN);
ciphertext_len += exp_rs2;
assert(ciphertext_len + HDR_PREFIX_LEN + exp_idlen2 == exp_bodylen2);
len = EVP_EncodeBlock(body2_test_b64, body2, exp_bodylen2);
assert(len == 100);
AZ(memcmp(body2_test_b64, body2_b64, len));
cipher_ctx_fini(ctx);
/* Just call add_salt() for sanity's sake. */
memset(body1, 0, SALT_LEN);
if (add_salt(body1, errmsg) != 0) {
/* Just call add_salt() for sanity's sake. */
memset(body1, 0, SALT_LEN);
if (add_salt(body1, errmsg) != 0) {
fprintf(stderr, "add_salt: %s\n", errmsg);
exit(-1);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment