/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* * Convert a string of hex digits (str) to an array (buf) of len bytes. * Return PR_TRUE if the hex string can fit in the byte array. Return * PR_FALSE if the hex string is empty or is too long.
*/
PRBool
from_hex_str(unsignedchar *buf, unsignedint len, constchar *str)
{ unsignedint nxdigit; /* number of hex digits in str */ unsignedint i; /* index into buf */ unsignedint j; /* index into str */
/* count the hex digits */
nxdigit = 0; for (nxdigit = 0; isxdigit((unsignedchar)str[nxdigit]); nxdigit++) { /* empty body */
} if (nxdigit == 0) { return PR_FALSE;
} if (nxdigit > 2 * len) { /* * The input hex string is too long, but we allow it if the * extra digits are leading 0's.
*/ for (j = 0; j < nxdigit - 2 * len; j++) { if (str[j] != '0') { return PR_FALSE;
}
} /* skip leading 0's */
str += nxdigit - 2 * len;
nxdigit = 2 * len;
} for (i = 0, j = 0; i < len; i++) { if (2 * i < 2 * len - nxdigit) { /* Handle a short input as if we padded it with leading 0's. */ if (2 * i + 1 < 2 * len - nxdigit) {
buf[i] = 0;
} else { char tmp[2];
tmp[0] = '0';
tmp[1] = str[j];
hex_to_byteval(tmp, &buf[i]);
j++;
}
} else {
hex_to_byteval(&str[j], &buf[i]);
j += 2;
}
} return PR_TRUE;
}
/* * Perform the TDEA Known Answer Test (KAT) or Multi-block Message * Test (MMT) in ECB or CBC mode. The KAT (there are five types) * and MMT have the same structure: given the key and IV (CBC mode * only), encrypt the given plaintext or decrypt the given ciphertext. * So we can handle them the same way. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
tdea_kat_mmt(char *reqfn)
{ char buf[180]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "CIPHERTEXT = <180 hex digits>\n".
*/
FILE *req; /* input stream from the REQUEST file */
FILE *resp; /* output stream to the RESPONSE file */ int i, j; int mode = NSS_DES_EDE3; /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */ int crypt = DECRYPT; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[24]; /* TDEA 3 key bundle */ unsignedint numKeys = 0; unsignedchar iv[8]; /* for all modes except ECB */ unsignedchar plaintext[8 * 20]; /* 1 to 20 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[8 * 20]; /* 1 to 20 blocks */ unsignedint ciphertextlen;
SECStatus rv;
req = fopen(reqfn, "r");
resp = stdout; while (fgets(buf, sizeof buf, req) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, resp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
crypt = ENCRYPT;
} else {
crypt = DECRYPT;
}
fputs(buf, resp); continue;
} /* NumKeys */ if (strncmp(&buf[0], "NumKeys", 7) == 0) {
i = 7; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
numKeys = buf[i];
fputs(buf, resp); continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) { /* mode defaults to ECB, if dataset has IV mode will be set CBC */
mode = NSS_DES_EDE3; /* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
memset(iv, 0, sizeof iv);
memset(plaintext, 0, sizeof plaintext);
plaintextlen = 0;
memset(ciphertext, 0, sizeof ciphertext);
ciphertextlen = 0;
fputs(buf, resp); continue;
} if (numKeys == 0) { if (strncmp(buf, "KEYs", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
key[j + 8] = key[j];
key[j + 16] = key[j];
}
fputs(buf, resp); continue;
}
} else { /* KEY1 = ... */ if (strncmp(buf, "KEY1", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
fputs(buf, resp); continue;
} /* KEY2 = ... */ if (strncmp(buf, "KEY2", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 8; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
fputs(buf, resp); continue;
} /* KEY3 = ... */ if (strncmp(buf, "KEY3", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 16; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
fputs(buf, resp); continue;
}
}
/* IV = ... */ if (strncmp(buf, "IV", 2) == 0) {
mode = NSS_DES_EDE3_CBC;
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, resp); continue;
}
/* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (crypt != ENCRYPT) { goto loser;
}
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
rv = tdea_encrypt_buf(mode, key,
(mode == NSS_DES_EDE3) ? NULL : iv,
ciphertext, &ciphertextlen, sizeof ciphertext,
plaintext, plaintextlen); if (rv != SECSuccess) { goto loser;
}
/* * Set the parity bit for the given byte
*/
BYTE
odd_parity(BYTE in)
{
BYTE out = in;
in ^= in >> 4;
in ^= in >> 2;
in ^= in >> 1; return (BYTE)(out ^ !(in & 1));
}
/* * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j] * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes.
*/ void
tdea_mct_next_keys(unsignedchar *key, constunsignedchar *text_2, constunsignedchar *text_1, constunsignedchar *text, unsignedint numKeys)
{ int k;
/* * Perform the Monte Carlo Test * * mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC * crypt = ENCRYPT || DECRYPT * inputtext = plaintext or Cyphertext depending on the value of crypt * inputlength is expected to be size 8 bytes * iv = needs to be set for NSS_DES_EDE3_CBC mode * resp = is the output response file.
*/ void
tdea_mct_test(int mode, unsignedchar *key, unsignedint numKeys, unsignedint crypt, unsignedchar *inputtext, unsignedint inputlength, unsignedchar *iv, FILE *resp)
{
int i, j; unsignedchar outputtext_1[8]; /* PT/CT[j-1] */ unsignedchar outputtext_2[8]; /* PT/CT[j-2] */ char buf[80]; /* holds one line from the input REQUEST file. */ unsignedint outputlen; unsignedchar outputtext[8];
SECStatus rv;
if (mode == NSS_DES_EDE3 && iv != NULL) {
printf("IV must be NULL for NSS_DES_EDE3 mode"); goto loser;
} elseif (mode == NSS_DES_EDE3_CBC && iv == NULL) {
printf("IV must not be NULL for NSS_DES_EDE3_CBC mode"); goto loser;
}
/* loop 400 times */ for (i = 0; i < 400; i++) { /* if i == 0 CV[0] = IV not necessary */ /* record the count and key values and plainText */
snprintf(buf, sizeof(buf), "COUNT = %d\n", i);
fputs(buf, resp); /* Output KEY1[i] */
fputs("KEY1 = ", resp);
to_hex_str(buf, key, 8);
fputs(buf, resp);
fputc('\n', resp); /* Output KEY2[i] */
fputs("KEY2 = ", resp);
to_hex_str(buf, &key[8], 8);
fputs(buf, resp);
fputc('\n', resp); /* Output KEY3[i] */
fputs("KEY3 = ", resp);
to_hex_str(buf, &key[16], 8);
fputs(buf, resp);
fputc('\n', resp); if (mode == NSS_DES_EDE3_CBC) { /* Output CV[i] */
fputs("IV = ", resp);
to_hex_str(buf, iv, 8);
fputs(buf, resp);
fputc('\n', resp);
} if (crypt == ENCRYPT) { /* Output PT[0] */
fputs("PLAINTEXT = ", resp);
} else { /* Output CT[0] */
fputs("CIPHERTEXT = ", resp);
}
/* Save PT/CT[j-2] and PT/CT[j-1] */ if (j == 9997)
memcpy(outputtext_2, outputtext, 8); if (j == 9998)
memcpy(outputtext_1, outputtext, 8); /* done at the end of the for(j) loop */
}
if (mode == NSS_DES_EDE3_CBC) { /* taken care of in the j=9999 iteration */ if (crypt == ENCRYPT) { /* P[i] = C[j-1] */ /* CV[i] = C[j] */
} else { /* taken care of in the j=9999 iteration */ /* CV[i] = C[j] */ /* C[i] = P[j] */
}
} else { /* ECB PT/CT[i] = PT/CT[j] */
memcpy(inputtext, outputtext, 8);
} /* done at the end of the for(i) loop */
fputc('\n', resp);
}
loser: return;
}
/* * Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes. * by gathering the input from the request file, and then * calling tdea_mct_test. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
tdea_mct(int mode, char *reqfn)
{ int i, j; char buf[80]; /* holds one line from the input REQUEST file. */
FILE *req; /* input stream from the REQUEST file */
FILE *resp; /* output stream to the RESPONSE file */ unsignedint crypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[24]; /* TDEA 3 key bundle */ unsignedint numKeys = 0; unsignedchar plaintext[8]; /* PT[j] */ unsignedchar ciphertext[8]; /* CT[j] */ unsignedchar iv[8];
/* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
memset(plaintext, 0, sizeof plaintext);
memset(ciphertext, 0, sizeof ciphertext);
memset(iv, 0, sizeof iv);
req = fopen(reqfn, "r");
resp = stdout; while (fgets(buf, sizeof buf, req) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, resp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
crypt = ENCRYPT;
} else {
crypt = DECRYPT;
}
fputs(buf, resp); continue;
} /* NumKeys */ if (strncmp(&buf[0], "NumKeys", 7) == 0) {
i = 7; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
numKeys = atoi(&buf[i]); continue;
} /* KEY1 = ... */ if (strncmp(buf, "KEY1", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
} /* KEY2 = ... */ if (strncmp(buf, "KEY2", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 8; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
} /* KEY3 = ... */ if (strncmp(buf, "KEY3", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 16; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
}
/* IV = ... */ if (strncmp(buf, "IV", 2) == 0) {
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
} continue;
}
/* * Doublecheck our result by encrypting the plaintext and * compare the output with the input ciphertext.
*/
cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16); if (cx == NULL) { goto loser;
}
rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
output, *outputlen); if (rv != SECSuccess) { goto loser;
} if (doublechecklen != *outputlen) { goto loser;
}
AES_DestroyContext(cx, PR_TRUE);
cx = NULL; if (memcmp(doublecheck, input, inputlen) != 0) { goto loser;
}
rv = SECSuccess;
loser: if (cx != NULL) {
AES_DestroyContext(cx, PR_TRUE);
} return rv;
} /* * Perform the AES GCM tests. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_gcm(char *reqfn, int encrypt)
{ char buf[512]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "CIPHERTEXT = <320 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[128]; /* handle large gcm IV's */ unsignedchar plaintext[10 * 16]; /* 1 to 10 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[11 * 16]; /* 1 to 10 blocks + tag */ unsignedint ciphertextlen; unsignedchar aad[11 * 16]; /* 1 to 10 blocks + tag */ unsignedint aadlen = 0; unsignedint tagbits; unsignedint taglen = 0; unsignedint ivlen;
CK_NSS_GCM_PARAMS params;
SECStatus rv;
aesreq = fopen(reqfn, "r");
aesresp = stdout; while (fgets(buf, sizeof buf, aesreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, aesresp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(buf, "[Taglen", 7) == 0) { if (sscanf(buf, "[Taglen = %d]", &tagbits) != 1) { goto loser;
}
taglen = tagbits / 8;
} if (strncmp(buf, "[IVlen", 6) == 0) { if (sscanf(buf, "[IVlen = %d]", &ivlen) != 1) { goto loser;
}
ivlen = ivlen / 8;
}
fputs(buf, aesresp); continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "Count", 5) == 0) { /* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
keysize = 0;
memset(iv, 0, sizeof iv);
memset(plaintext, 0, sizeof plaintext);
plaintextlen = 0;
memset(ciphertext, 0, sizeof ciphertext);
ciphertextlen = 0;
fputs(buf, aesresp); continue;
} /* KEY = ... */ if (strncmp(buf, "Key", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
keysize = j;
fputs(buf, aesresp); continue;
} /* IV = ... */ if (strncmp(buf, "IV", 2) == 0) {
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, aesresp); continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PT", 2) == 0) { /* sanity check */ if (!encrypt) { goto loser;
}
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
fputs(buf, aesresp); continue;
} /* CIPHERTEXT = ... */ if (strncmp(buf, "CT", 2) == 0) { /* sanity check */ if (encrypt) { goto loser;
}
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &ciphertext[j]);
}
ciphertextlen = j;
fputs(buf, aesresp); continue;
} if (strncmp(buf, "AAD", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &aad[j]);
}
aadlen = j;
fputs(buf, aesresp); if (encrypt) { if (encrypt == 2) {
rv = RNG_GenerateGlobalRandomBytes(iv, ivlen); if (rv != SECSuccess) { goto loser;
}
}
params.pIv = iv;
params.ulIvLen = ivlen;
params.pAAD = aad;
params.ulAADLen = aadlen;
params.ulTagBits = tagbits;
rv = aes_encrypt_buf(NSS_AES_GCM, key, keysize,
(unsignedchar *)¶ms,
ciphertext, &ciphertextlen, sizeof ciphertext,
plaintext, plaintextlen); if (rv != SECSuccess) { goto loser;
}
/* * Perform the AES Known Answer Test (KAT) or Multi-block Message * Test (MMT) in ECB or CBC mode. The KAT (there are four types) * and MMT have the same structure: given the key and IV (CBC mode * only), encrypt the given plaintext or decrypt the given ciphertext. * So we can handle them the same way. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_kat_mmt(char *reqfn)
{ char buf[512]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "CIPHERTEXT = <320 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int mode = NSS_AES; /* NSS_AES (ECB) or NSS_AES_CBC */ int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[16]; /* for all modes except ECB */ unsignedchar plaintext[10 * 16]; /* 1 to 10 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[10 * 16]; /* 1 to 10 blocks */ unsignedint ciphertextlen;
SECStatus rv;
aesreq = fopen(reqfn, "r");
aesresp = stdout; while (fgets(buf, sizeof buf, aesreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, aesresp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
encrypt = 1;
} else {
encrypt = 0;
}
fputs(buf, aesresp); continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) {
mode = NSS_AES; /* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
keysize = 0;
memset(iv, 0, sizeof iv);
memset(plaintext, 0, sizeof plaintext);
plaintextlen = 0;
memset(ciphertext, 0, sizeof ciphertext);
ciphertextlen = 0;
fputs(buf, aesresp); continue;
} /* KEY = ... */ if (strncmp(buf, "KEY", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
keysize = j;
fputs(buf, aesresp); continue;
} /* IV = ... */ if (strncmp(buf, "IV", 2) == 0) {
mode = NSS_AES_CBC;
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, aesresp); continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (!encrypt) { goto loser;
}
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
/* * Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo * Test (MCT) in ECB and CBC modes.
*/ void
aes_mct_next_key(unsignedchar *key, unsignedint keysize, constunsignedchar *ciphertext_1, constunsignedchar *ciphertext)
{ int k;
switch (keysize) { case 16: /* 128-bit key */ /* Key[i+1] = Key[i] xor CT[j] */ for (k = 0; k < 16; k++) {
key[k] ^= ciphertext[k];
} break; case 24: /* 192-bit key */ /* * Key[i+1] = Key[i] xor (last 64-bits of * CT[j-1] || CT[j])
*/ for (k = 0; k < 8; k++) {
key[k] ^= ciphertext_1[k + 8];
} for (k = 8; k < 24; k++) {
key[k] ^= ciphertext[k - 8];
} break; case 32: /* 256-bit key */ /* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */ for (k = 0; k < 16; k++) {
key[k] ^= ciphertext_1[k];
} for (k = 16; k < 32; k++) {
key[k] ^= ciphertext[k - 16];
} break;
}
}
/* * Perform the AES Monte Carlo Test (MCT) in ECB mode. MCT exercises * our AES code in streaming mode because the plaintext or ciphertext * is generated block by block as we go, so we can't collect all the * plaintext or ciphertext in one buffer and encrypt or decrypt it in * one shot. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_ecb_mct(char *reqfn)
{ char buf[80]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "KEY = <64 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar plaintext[16]; /* PT[j] */ unsignedchar plaintext_1[16]; /* PT[j-1] */ unsignedchar ciphertext[16]; /* CT[j] */ unsignedchar ciphertext_1[16]; /* CT[j-1] */ unsignedchar doublecheck[16]; unsignedint outputlen;
AESContext *cx = NULL; /* the operation being tested */
AESContext *cx2 = NULL; /* the inverse operation done in parallel * to doublecheck our result.
*/
SECStatus rv;
aesreq = fopen(reqfn, "r");
aesresp = stdout; while (fgets(buf, sizeof buf, aesreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, aesresp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
encrypt = 1;
} else {
encrypt = 0;
}
fputs(buf, aesresp); continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) { /* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
keysize = 0;
memset(plaintext, 0, sizeof plaintext);
memset(ciphertext, 0, sizeof ciphertext); continue;
} /* KEY = ... */ if (strncmp(buf, "KEY", 3) == 0) { /* Key[0] = Key */
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
keysize = j; continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (!encrypt) { goto loser;
} /* PT[0] = PT */
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof plaintext; i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
/* * Perform the AES Monte Carlo Test (MCT) in CBC mode. MCT exercises * our AES code in streaming mode because the plaintext or ciphertext * is generated block by block as we go, so we can't collect all the * plaintext or ciphertext in one buffer and encrypt or decrypt it in * one shot. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_cbc_mct(char *reqfn)
{ char buf[80]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "KEY = <64 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[16]; unsignedchar plaintext[16]; /* PT[j] */ unsignedchar plaintext_1[16]; /* PT[j-1] */ unsignedchar ciphertext[16]; /* CT[j] */ unsignedchar ciphertext_1[16]; /* CT[j-1] */ unsignedchar doublecheck[16]; unsignedint outputlen;
AESContext *cx = NULL; /* the operation being tested */
AESContext *cx2 = NULL; /* the inverse operation done in parallel * to doublecheck our result.
*/
SECStatus rv;
aesreq = fopen(reqfn, "r");
aesresp = stdout; while (fgets(buf, sizeof buf, aesreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, aesresp); continue;
} /* [ENCRYPT] or [DECRYPT] */ if (buf[0] == '[') { if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
encrypt = 1;
} else {
encrypt = 0;
}
fputs(buf, aesresp); continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) { /* zeroize the variables for the test with this data set */
memset(key, 0, sizeof key);
keysize = 0;
memset(iv, 0, sizeof iv);
memset(plaintext, 0, sizeof plaintext);
memset(ciphertext, 0, sizeof ciphertext); continue;
} /* KEY = ... */ if (strncmp(buf, "KEY", 3) == 0) { /* Key[0] = Key */
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
keysize = j; continue;
} /* IV = ... */ if (strncmp(buf, "IV", 2) == 0) { /* IV[0] = IV */
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
} continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (!encrypt) { goto loser;
} /* PT[0] = PT */
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof plaintext; i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.