Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  fipstest.c   Sprache: C

 
/* 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/. */


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "secitem.h"
#include "blapi.h"
#include "nssutil.h"
#include "secerr.h"
#include "secder.h"
#include "secdig.h"
#include "secoid.h"
#include "ec.h"
#include "hasht.h"
#include "lowkeyi.h"
#include "softoken.h"
#include "pkcs11t.h"
#define __PASTE(x, y) x##y
#undef CK_PKCS11_FUNCTION_INFO
#undef CK_NEED_ARG_LIST
#define CK_EXTERN extern
#define CK_PKCS11_FUNCTION_INFO(func) \
    CK_RV __PASTE(NS, func)
#define CK_NEED_ARG_LIST 1
#include "pkcs11f.h"
#undef CK_PKCS11_FUNCTION_INFO
#undef CK_NEED_ARG_LIST
#undef __PASTE
#define SSL3_RANDOM_LENGTH 32

#if 0
#include "../../lib/freebl/mpi/mpi.h"
#endif
#define MATCH_OPENSSL 1
/*#define MATCH_NIST 1 */
#ifdef MATCH_NIST
#define VERBOSE_REASON 1
#endif

extern SECStatus
EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
extern SECStatus
EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
              const ECParams *srcParams);

#define ENCRYPT 1
#define DECRYPT 0
#define BYTE unsigned char
#define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001
#define RSA_MAX_TEST_MODULUS_BITS 4096
#define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS / 8
#define RSA_MAX_TEST_EXPONENT_BYTES 8
#define PQG_TEST_SEED_BYTES 20

SECStatus
hex_to_byteval(const char *c2, unsigned char *byteval)
{
    int i;
    unsigned char offset;
    *byteval = 0;
    for (i = 0; i < 2; i++) {
        if (c2[i] >= '0' && c2[i] <= '9') {
            offset = c2[i] - '0';
            *byteval |= offset << 4 * (1 - i);
        } else if (c2[i] >= 'a' && c2[i] <= 'f') {
            offset = c2[i] - 'a';
            *byteval |= (offset + 10) << 4 * (1 - i);
        } else if (c2[i] >= 'A' && c2[i] <= 'F') {
            offset = c2[i] - 'A';
            *byteval |= (offset + 10) << 4 * (1 - i);
        } else {
            return SECFailure;
        }
    }
    return SECSuccess;
}

SECStatus
byteval_to_hex(unsigned char byteval, char *c2, char a)
{
    int i;
    unsigned char offset;
    for (i = 0; i < 2; i++) {
        offset = (byteval >> 4 * (1 - i)) & 0x0f;
        if (offset < 10) {
            c2[i] = '0' + offset;
        } else {
            c2[i] = a + offset - 10;
        }
    }
    return SECSuccess;
}

void
to_hex_str(char *str, const unsigned char *buf, unsigned int len)
{
    unsigned int i;
    for (i = 0; i < len; i++) {
        byteval_to_hex(buf[i], &str[2 * i], 'a');
    }
    str[2 * len] = '\0';
}

void
to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len)
{
    unsigned int i;
    for (i = 0; i < len; i++) {
        byteval_to_hex(buf[i], &str[2 * i], 'A');
    }
    str[2 * len] = '\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(unsigned char *buf, unsigned int len, const char *str)
{
    unsigned int nxdigit; /* number of hex digits in str */
    unsigned int i;       /* index into buf */
    unsigned int j;       /* index into str */

    /* count the hex digits */
    nxdigit = 0;
    for (nxdigit = 0; isxdigit((unsigned char)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;
}

SECStatus
tdea_encrypt_buf(
    int mode,
    const unsigned char *key,
    const unsigned char *iv,
    unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
    const unsigned char *input, unsigned int inputlen)
{
    SECStatus rv = SECFailure;
    DESContext *cx;
    unsigned char doublecheck[8 * 20]; /* 1 to 20 blocks */
    unsigned int doublechecklen = 0;

    cx = DES_CreateContext(key, iv, mode, PR_TRUE);
    if (cx == NULL) {
        goto loser;
    }
    rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (*outputlen != inputlen) {
        goto loser;
    }
    DES_DestroyContext(cx, PR_TRUE);
    cx = NULL;

    /*
     * Doublecheck our result by decrypting the ciphertext and
     * compare the output with the input plaintext.
     */

    cx = DES_CreateContext(key, iv, mode, PR_FALSE);
    if (cx == NULL) {
        goto loser;
    }
    rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
                     output, *outputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (doublechecklen != *outputlen) {
        goto loser;
    }
    DES_DestroyContext(cx, PR_TRUE);
    cx = NULL;
    if (memcmp(doublecheck, input, inputlen) != 0) {
        goto loser;
    }
    rv = SECSuccess;

loser:
    if (cx != NULL) {
        DES_DestroyContext(cx, PR_TRUE);
    }
    return rv;
}

SECStatus
tdea_decrypt_buf(
    int mode,
    const unsigned char *key,
    const unsigned char *iv,
    unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
    const unsigned char *input, unsigned int inputlen)
{
    SECStatus rv = SECFailure;
    DESContext *cx;
    unsigned char doublecheck[8 * 20]; /* 1 to 20 blocks */
    unsigned int doublechecklen = 0;

    cx = DES_CreateContext(key, iv, mode, PR_FALSE);
    if (cx == NULL) {
        goto loser;
    }
    rv = DES_Decrypt(cx, output, outputlen, maxoutputlen,
                     input, inputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (*outputlen != inputlen) {
        goto loser;
    }
    DES_DestroyContext(cx, PR_TRUE);
    cx = NULL;

    /*
     * Doublecheck our result by encrypting the plaintext and
     * compare the output with the input ciphertext.
     */

    cx = DES_CreateContext(key, iv, mode, PR_TRUE);
    if (cx == NULL) {
        goto loser;
    }
    rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
                     output, *outputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (doublechecklen != *outputlen) {
        goto loser;
    }
    DES_DestroyContext(cx, PR_TRUE);
    cx = NULL;
    if (memcmp(doublecheck, input, inputlen) != 0) {
        goto loser;
    }
    rv = SECSuccess;

loser:
    if (cx != NULL) {
        DES_DestroyContext(cx, PR_TRUE);
    }
    return rv;
}

/*
 * 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 */
    unsigned char key[24];   /* TDEA 3 key bundle */
    unsigned int numKeys = 0;
    unsigned char iv[8];             /* for all modes except ECB */
    unsigned char plaintext[8 * 20]; /* 1 to 20 blocks */
    unsigned int plaintextlen;
    unsigned char ciphertext[8 * 20]; /* 1 to 20 blocks */
    unsigned int 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((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                    i++;
                }
                for (j = 0; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                    i++;
                }
                for (j = 0; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                    i++;
                }
                for (j = 8; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                    i++;
                }
                for (j = 16; isxdigit((unsigned char)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((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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;
            }

            fputs(buf, resp);
            fputs("CIPHERTEXT = ", resp);
            to_hex_str(buf, ciphertext, ciphertextlen);
            fputs(buf, resp);
            fputc('\n', resp);
            continue;
        }
        /* CIPHERTEXT = ... */
        if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
            /* sanity check */
            if (crypt != DECRYPT) {
                goto loser;
            }

            i = 10;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j]);
            }
            ciphertextlen = j;

            rv = tdea_decrypt_buf(mode, key,
                                  (mode == NSS_DES_EDE3) ? NULL : iv,
                                  plaintext, &plaintextlen, sizeof plaintext,
                                  ciphertext, ciphertextlen);
            if (rv != SECSuccess) {
                goto loser;
            }

            fputs(buf, resp);
            fputs("PLAINTEXT = ", resp);
            to_hex_str(buf, plaintext, plaintextlen);
            fputs(buf, resp);
            fputc('\n', resp);
            continue;
        }
    }

loser:
    fclose(req);
}

/*
 * 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(unsigned char *key,
                   const unsigned char *text_2, const unsigned char *text_1,
                   const unsigned char *text, unsigned int numKeys)
{
    int k;

    /* key1[i+1] = key1[i] xor PT/CT[j] */
    for (k = 0; k < 8; k++) {
        key[k] ^= text[k];
    }
    /* key2 */
    if (numKeys == 2 || numKeys == 3) {
        /* key2 independent */
        for (k = 8; k < 16; k++) {
            /* key2[i+1] = KEY2[i] xor PT/CT[j-1] */
            key[k] ^= text_1[k - 8];
        }
    } else {
        /* key2 == key 1 */
        for (k = 8; k < 16; k++) {
            /* key2[i+1] = KEY2[i] xor PT/CT[j] */
            key[k] = key[k - 8];
        }
    }
    /* key3 */
    if (numKeys == 1 || numKeys == 2) {
        /* key3 == key 1 */
        for (k = 16; k < 24; k++) {
            /* key3[i+1] = KEY3[i] xor PT/CT[j] */
            key[k] = key[k - 16];
        }
    } else {
        /* key3 independent */
        for (k = 16; k < 24; k++) {
            /* key3[i+1] = KEY3[i] xor PT/CT[j-2] */
            key[k] ^= text_2[k - 16];
        }
    }
    /* set the parity bits */
    for (k = 0; k < 24; k++) {
        key[k] = odd_parity(key[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, unsigned char *key, unsigned int numKeys,
              unsigned int crypt, unsigned char *inputtext,
              unsigned int inputlength, unsigned char *iv, FILE *resp)
{

    int i, j;
    unsigned char outputtext_1[8]; /* PT/CT[j-1] */
    unsigned char outputtext_2[8]; /* PT/CT[j-2] */
    char buf[80];                  /* holds one line from the input REQUEST file. */
    unsigned int outputlen;
    unsigned char outputtext[8];

    SECStatus rv;

    if (mode == NSS_DES_EDE3 && iv != NULL) {
        printf("IV must be NULL for NSS_DES_EDE3 mode");
        goto loser;
    } else if (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);
        }

        to_hex_str(buf, inputtext, inputlength);
        fputs(buf, resp);
        fputc('\n', resp);

        /* loop 10,000 times */
        for (j = 0; j < 10000; j++) {

            outputlen = 0;
            if (crypt == ENCRYPT) {
                /* inputtext == ciphertext outputtext == plaintext*/
                rv = tdea_encrypt_buf(mode, key,
                                      (mode ==
                                       NSS_DES_EDE3)
                                          ? NULL
                                          : iv,
                                      outputtext, &outputlen, 8,
                                      inputtext, 8);
            } else {
                /* inputtext == plaintext outputtext == ciphertext */
                rv = tdea_decrypt_buf(mode, key,
                                      (mode ==
                                       NSS_DES_EDE3)
                                          ? NULL
                                          : iv,
                                      outputtext, &outputlen, 8,
                                      inputtext, 8);
            }

            if (rv != SECSuccess) {
                goto loser;
            }
            if (outputlen != inputlength) {
                goto loser;
            }

            if (mode == NSS_DES_EDE3_CBC) {
                if (crypt == ENCRYPT) {
                    if (j == 0) {
                        /*P[j+1] = CV[0] */
                        memcpy(inputtext, iv, 8);
                    } else {
                        /* p[j+1] = C[j-1] */
                        memcpy(inputtext, outputtext_1, 8);
                    }
                    /* CV[j+1] = C[j] */
                    memcpy(iv, outputtext, 8);
                    if (j != 9999) {
                        /* save C[j-1] */
                        memcpy(outputtext_1, outputtext, 8);
                    }
                } else { /* DECRYPT */
                    /* CV[j+1] = C[j] */
                    memcpy(iv, inputtext, 8);
                    /* C[j+1] = P[j] */
                    memcpy(inputtext, outputtext, 8);
                }
            } else {
                /* ECB mode PT/CT[j+1] = CT/PT[j] */
                memcpy(inputtext, outputtext, 8);
            }

            /* 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 (crypt == ENCRYPT) {
            /* Output CT[j] */
            fputs("CIPHERTEXT = ", resp);
        } else {
            /* Output PT[j] */
            fputs("PLAINTEXT = ", resp);
        }
        to_hex_str(buf, outputtext, 8);
        fputs(buf, resp);
        fputc('\n', resp);

        /* Key[i+1] = Key[i] xor ...  outputtext_2 == PT/CT[j-2]
         *  outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j]
         */

        tdea_mct_next_keys(key, outputtext_2,
                           outputtext_1, outputtext, numKeys);

        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 */
    unsigned int crypt = 0; /* 1 means encrypt, 0 means decrypt */
    unsigned char key[24];  /* TDEA 3 key bundle */
    unsigned int numKeys = 0;
    unsigned char plaintext[8];  /* PT[j] */
    unsigned char ciphertext[8]; /* CT[j] */
    unsigned char 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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            numKeys = atoi(&buf[i]);
            continue;
        }
        /* KEY1 = ... */
        if (strncmp(buf, "KEY1", 4) == 0) {
            i = 4;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &key[j]);
            }
            continue;
        }
        /* KEY2 = ... */
        if (strncmp(buf, "KEY2", 4) == 0) {
            i = 4;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 8; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &key[j]);
            }
            continue;
        }
        /* KEY3 = ... */
        if (strncmp(buf, "KEY3", 4) == 0) {
            i = 4;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 16; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &key[j]);
            }
            continue;
        }

        /* IV = ... */
        if (strncmp(buf, "IV", 2) == 0) {
            i = 2;
            while (isspace((unsigned char)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 (crypt != ENCRYPT) {
                goto loser;
            }
            /* PT[0] = PT */
            i = 9;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; j < sizeof plaintext; i += 2, j++) {
                hex_to_byteval(&buf[i], &plaintext[j]);
            }

            /* do the Monte Carlo test */
            if (mode == NSS_DES_EDE3) {
                tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, plaintext, sizeof plaintext, NULL, resp);
            } else {
                tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, plaintext, sizeof plaintext, iv, resp);
            }
            continue;
        }
        /* CIPHERTEXT = ... */
        if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
            /* sanity check */
            if (crypt != DECRYPT) {
                goto loser;
            }
            /* CT[0] = CT */
            i = 10;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j]);
            }

            /* do the Monte Carlo test */
            if (mode == NSS_DES_EDE3) {
                tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, ciphertext, sizeof ciphertext, NULL, resp);
            } else {
                tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, ciphertext, sizeof ciphertext, iv, resp);
            }
            continue;
        }
    }

loser:
    fclose(req);
}

SECStatus
aes_encrypt_buf(
    int mode,
    const unsigned char *key, unsigned int keysize,
    const unsigned char *iv,
    unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
    const unsigned char *input, unsigned int inputlen)
{
    SECStatus rv = SECFailure;
    AESContext *cx;
    unsigned char doublecheck[10 * 16]; /* 1 to 10 blocks */
    unsigned int doublechecklen = 0;

    cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
    if (cx == NULL) {
        goto loser;
    }
    rv = AES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (*outputlen != inputlen) {
        goto loser;
    }
    AES_DestroyContext(cx, PR_TRUE);
    cx = NULL;

    /*
     * Doublecheck our result by decrypting the ciphertext and
     * compare the output with the input plaintext.
     */

    cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
    if (cx == NULL) {
        goto loser;
    }
    rv = AES_Decrypt(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;
}

SECStatus
aes_decrypt_buf(
    int mode,
    const unsigned char *key, unsigned int keysize,
    const unsigned char *iv,
    unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
    const unsigned char *input, unsigned int inputlen)
{
    SECStatus rv = SECFailure;
    AESContext *cx;
    unsigned char doublecheck[10 * 16]; /* 1 to 10 blocks */
    unsigned int doublechecklen = 0;

    cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
    if (cx == NULL) {
        goto loser;
    }
    rv = AES_Decrypt(cx, output, outputlen, maxoutputlen,
                     input, inputlen);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (*outputlen != inputlen) {
        goto loser;
    }
    AES_DestroyContext(cx, PR_TRUE);
    cx = NULL;

    /*
     * 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;
    unsigned char key[32]; /* 128, 192, or 256 bits */
    unsigned int keysize = 0;
    unsigned char iv[128];            /* handle large gcm IV's */
    unsigned char plaintext[10 * 16]; /* 1 to 10 blocks */
    unsigned int plaintextlen;
    unsigned char ciphertext[11 * 16]; /* 1 to 10 blocks + tag */
    unsigned int ciphertextlen;
    unsigned char aad[11 * 16]; /* 1 to 10 blocks + tag */
    unsigned int aadlen = 0;
    unsigned int tagbits;
    unsigned int taglen = 0;
    unsigned int 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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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,
                                     (unsigned char *)¶ms,
                                     ciphertext, &ciphertextlen, sizeof ciphertext,
                                     plaintext, plaintextlen);
                if (rv != SECSuccess) {
                    goto loser;
                }

                if (encrypt == 2) {
                    fputs("IV = ", aesresp);
                    to_hex_str(buf, iv, ivlen);
                    fputs(buf, aesresp);
                    fputc('\n', aesresp);
                }
                fputs("CT = ", aesresp);
                j = ciphertextlen - taglen;
                to_hex_str(buf, ciphertext, j);
                fputs(buf, aesresp);
                fputs("\nTag = ", aesresp);
                to_hex_str(buf, ciphertext + j, taglen);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
            }
            continue;
        }
        if (strncmp(buf, "Tag", 3) == 0) {
            /* sanity check */
            if (encrypt) {
                goto loser;
            }

            i = 3;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j + ciphertextlen]);
            }
            ciphertextlen += j;
            params.pIv = iv;
            params.ulIvLen = ivlen;
            params.pAAD = aad;
            params.ulAADLen = aadlen;
            params.ulTagBits = tagbits;
            rv = aes_decrypt_buf(NSS_AES_GCM, key, keysize,
                                 (unsigned char *)¶ms,
                                 plaintext, &plaintextlen, sizeof plaintext,
                                 ciphertext, ciphertextlen);
            fputs(buf, aesresp);
            if (rv != SECSuccess) {
                fprintf(aesresp, "FAIL\n");
            } else {
                fputs("PT = ", aesresp);
                to_hex_str(buf, plaintext, plaintextlen);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
            }
            continue;
        }
    }
loser:
    fclose(aesreq);
}

/*
 * 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 */
    unsigned char key[32]; /* 128, 192, or 256 bits */
    unsigned int keysize = 0;
    unsigned char iv[16];             /* for all modes except ECB */
    unsigned char plaintext[10 * 16]; /* 1 to 10 blocks */
    unsigned int plaintextlen;
    unsigned char ciphertext[10 * 16]; /* 1 to 10 blocks */
    unsigned int 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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &plaintext[j]);
            }
            plaintextlen = j;

            rv = aes_encrypt_buf(mode, key, keysize,
                                 (mode ==
                                  NSS_AES)
                                     ? NULL
                                     : iv,
                                 ciphertext, &ciphertextlen, sizeof ciphertext,
                                 plaintext, plaintextlen);
            if (rv != SECSuccess) {
                goto loser;
            }

            fputs(buf, aesresp);
            fputs("CIPHERTEXT = ", aesresp);
            to_hex_str(buf, ciphertext, ciphertextlen);
            fputs(buf, aesresp);
            fputc('\n', aesresp);
            continue;
        }
        /* CIPHERTEXT = ... */
        if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
            /* sanity check */
            if (encrypt) {
                goto loser;
            }

            i = 10;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j]);
            }
            ciphertextlen = j;

            rv = aes_decrypt_buf(mode, key, keysize,
                                 (mode ==
                                  NSS_AES)
                                     ? NULL
                                     : iv,
                                 plaintext, &plaintextlen, sizeof plaintext,
                                 ciphertext, ciphertextlen);
            if (rv != SECSuccess) {
                goto loser;
            }

            fputs(buf, aesresp);
            fputs("PLAINTEXT = ", aesresp);
            to_hex_str(buf, plaintext, plaintextlen);
            fputs(buf, aesresp);
            fputc('\n', aesresp);
            continue;
        }
    }
loser:
    fclose(aesreq);
}

/*
 * 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(unsigned char *key, unsigned int keysize,
                 const unsigned char *ciphertext_1, const unsigned char *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 */
    unsigned char key[32]; /* 128, 192, or 256 bits */
    unsigned int keysize = 0;
    unsigned char plaintext[16];    /* PT[j] */
    unsigned char plaintext_1[16];  /* PT[j-1] */
    unsigned char ciphertext[16];   /* CT[j] */
    unsigned char ciphertext_1[16]; /* CT[j-1] */
    unsigned char doublecheck[16];
    unsigned int 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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; j < sizeof plaintext; i += 2, j++) {
                hex_to_byteval(&buf[i], &plaintext[j]);
            }

            for (i = 0; i < 100; i++) {
                snprintf(buf, sizeof(buf), "COUNT = %d\n", i);
                fputs(buf, aesresp);
                /* Output Key[i] */
                fputs("KEY = ", aesresp);
                to_hex_str(buf, key, keysize);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output PT[0] */
                fputs("PLAINTEXT = ", aesresp);
                to_hex_str(buf, plaintext, sizeof plaintext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                cx = AES_CreateContext(key, NULL, NSS_AES,
                                       PR_TRUE, keysize, 16);
                if (cx == NULL) {
                    goto loser;
                }
                /*
                 * doublecheck our result by decrypting the result
                 * and comparing the output with the plaintext.
                 */

                cx2 = AES_CreateContext(key, NULL, NSS_AES,
                                        PR_FALSE, keysize, 16);
                if (cx2 == NULL) {
                    goto loser;
                }
                for (j = 0; j < 1000; j++) {
                    /* Save CT[j-1] */
                    memcpy(ciphertext_1, ciphertext, sizeof ciphertext);

                    /* CT[j] = AES(Key[i], PT[j]) */
                    outputlen = 0;
                    rv = AES_Encrypt(cx,
                                     ciphertext, &outputlen, sizeof ciphertext,
                                     plaintext, sizeof plaintext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof plaintext) {
                        goto loser;
                    }

                    /* doublecheck our result */
                    outputlen = 0;
                    rv = AES_Decrypt(cx2,
                                     doublecheck, &outputlen, sizeof doublecheck,
                                     ciphertext, sizeof ciphertext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof ciphertext) {
                        goto loser;
                    }
                    if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
                        goto loser;
                    }

                    /* PT[j+1] = CT[j] */
                    memcpy(plaintext, ciphertext, sizeof plaintext);
                }
                AES_DestroyContext(cx, PR_TRUE);
                cx = NULL;
                AES_DestroyContext(cx2, PR_TRUE);
                cx2 = NULL;

                /* Output CT[j] */
                fputs("CIPHERTEXT = ", aesresp);
                to_hex_str(buf, ciphertext, sizeof ciphertext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                /* Key[i+1] = Key[i] xor ... */
                aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
                /* PT[0] = CT[j] */
                /* done at the end of the for(j) loop */

                fputc('\n', aesresp);
            }

            continue;
        }
        /* CIPHERTEXT = ... */
        if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
            /* sanity check */
            if (encrypt) {
                goto loser;
            }
            /* CT[0] = CT */
            i = 10;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j]);
            }

            for (i = 0; i < 100; i++) {
                snprintf(buf, sizeof(buf), "COUNT = %d\n", i);
                fputs(buf, aesresp);
                /* Output Key[i] */
                fputs("KEY = ", aesresp);
                to_hex_str(buf, key, keysize);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output CT[0] */
                fputs("CIPHERTEXT = ", aesresp);
                to_hex_str(buf, ciphertext, sizeof ciphertext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                cx = AES_CreateContext(key, NULL, NSS_AES,
                                       PR_FALSE, keysize, 16);
                if (cx == NULL) {
                    goto loser;
                }
                /*
                 * doublecheck our result by encrypting the result
                 * and comparing the output with the ciphertext.
                 */

                cx2 = AES_CreateContext(key, NULL, NSS_AES,
                                        PR_TRUE, keysize, 16);
                if (cx2 == NULL) {
                    goto loser;
                }
                for (j = 0; j < 1000; j++) {
                    /* Save PT[j-1] */
                    memcpy(plaintext_1, plaintext, sizeof plaintext);

                    /* PT[j] = AES(Key[i], CT[j]) */
                    outputlen = 0;
                    rv = AES_Decrypt(cx,
                                     plaintext, &outputlen, sizeof plaintext,
                                     ciphertext, sizeof ciphertext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof ciphertext) {
                        goto loser;
                    }

                    /* doublecheck our result */
                    outputlen = 0;
                    rv = AES_Encrypt(cx2,
                                     doublecheck, &outputlen, sizeof doublecheck,
                                     plaintext, sizeof plaintext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof plaintext) {
                        goto loser;
                    }
                    if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
                        goto loser;
                    }

                    /* CT[j+1] = PT[j] */
                    memcpy(ciphertext, plaintext, sizeof ciphertext);
                }
                AES_DestroyContext(cx, PR_TRUE);
                cx = NULL;
                AES_DestroyContext(cx2, PR_TRUE);
                cx2 = NULL;

                /* Output PT[j] */
                fputs("PLAINTEXT = ", aesresp);
                to_hex_str(buf, plaintext, sizeof plaintext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                /* Key[i+1] = Key[i] xor ... */
                aes_mct_next_key(key, keysize, plaintext_1, plaintext);
                /* CT[0] = PT[j] */
                /* done at the end of the for(j) loop */

                fputc('\n', aesresp);
            }

            continue;
        }
    }
loser:
    if (cx != NULL) {
        AES_DestroyContext(cx, PR_TRUE);
    }
    if (cx2 != NULL) {
        AES_DestroyContext(cx2, PR_TRUE);
    }
    fclose(aesreq);
}

/*
 * 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 */
    unsigned char key[32]; /* 128, 192, or 256 bits */
    unsigned int keysize = 0;
    unsigned char iv[16];
    unsigned char plaintext[16];    /* PT[j] */
    unsigned char plaintext_1[16];  /* PT[j-1] */
    unsigned char ciphertext[16];   /* CT[j] */
    unsigned char ciphertext_1[16]; /* CT[j-1] */
    unsigned char doublecheck[16];
    unsigned int 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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)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((unsigned char)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((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; j < sizeof plaintext; i += 2, j++) {
                hex_to_byteval(&buf[i], &plaintext[j]);
            }

            for (i = 0; i < 100; i++) {
                snprintf(buf, sizeof(buf), "COUNT = %d\n", i);
                fputs(buf, aesresp);
                /* Output Key[i] */
                fputs("KEY = ", aesresp);
                to_hex_str(buf, key, keysize);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output IV[i] */
                fputs("IV = ", aesresp);
                to_hex_str(buf, iv, sizeof iv);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output PT[0] */
                fputs("PLAINTEXT = ", aesresp);
                to_hex_str(buf, plaintext, sizeof plaintext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                cx = AES_CreateContext(key, iv, NSS_AES_CBC,
                                       PR_TRUE, keysize, 16);
                if (cx == NULL) {
                    goto loser;
                }
                /*
                 * doublecheck our result by decrypting the result
                 * and comparing the output with the plaintext.
                 */

                cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
                                        PR_FALSE, keysize, 16);
                if (cx2 == NULL) {
                    goto loser;
                }
                /* CT[-1] = IV[i] */
                memcpy(ciphertext, iv, sizeof ciphertext);
                for (j = 0; j < 1000; j++) {
                    /* Save CT[j-1] */
                    memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
                    /*
                     * If ( j=0 )
                     *      CT[j] = AES(Key[i], IV[i], PT[j])
                     *      PT[j+1] = IV[i] (= CT[j-1])
                     * Else
                     *      CT[j] = AES(Key[i], PT[j])
                     *      PT[j+1] = CT[j-1]
                     */

                    outputlen = 0;
                    rv = AES_Encrypt(cx,
                                     ciphertext, &outputlen, sizeof ciphertext,
                                     plaintext, sizeof plaintext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof plaintext) {
                        goto loser;
                    }

                    /* doublecheck our result */
                    outputlen = 0;
                    rv = AES_Decrypt(cx2,
                                     doublecheck, &outputlen, sizeof doublecheck,
                                     ciphertext, sizeof ciphertext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof ciphertext) {
                        goto loser;
                    }
                    if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
                        goto loser;
                    }

                    memcpy(plaintext, ciphertext_1, sizeof plaintext);
                }
                AES_DestroyContext(cx, PR_TRUE);
                cx = NULL;
                AES_DestroyContext(cx2, PR_TRUE);
                cx2 = NULL;

                /* Output CT[j] */
                fputs("CIPHERTEXT = ", aesresp);
                to_hex_str(buf, ciphertext, sizeof ciphertext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                /* Key[i+1] = Key[i] xor ... */
                aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
                /* IV[i+1] = CT[j] */
                memcpy(iv, ciphertext, sizeof iv);
                /* PT[0] = CT[j-1] */
                /* done at the end of the for(j) loop */

                fputc('\n', aesresp);
            }

            continue;
        }
        /* CIPHERTEXT = ... */
        if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
            /* sanity check */
            if (encrypt) {
                goto loser;
            }
            /* CT[0] = CT */
            i = 10;
            while (isspace((unsigned char)buf[i]) || buf[i] == '=') {
                i++;
            }
            for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) {
                hex_to_byteval(&buf[i], &ciphertext[j]);
            }

            for (i = 0; i < 100; i++) {
                snprintf(buf, sizeof(buf), "COUNT = %d\n", i);
                fputs(buf, aesresp);
                /* Output Key[i] */
                fputs("KEY = ", aesresp);
                to_hex_str(buf, key, keysize);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output IV[i] */
                fputs("IV = ", aesresp);
                to_hex_str(buf, iv, sizeof iv);
                fputs(buf, aesresp);
                fputc('\n', aesresp);
                /* Output CT[0] */
                fputs("CIPHERTEXT = ", aesresp);
                to_hex_str(buf, ciphertext, sizeof ciphertext);
                fputs(buf, aesresp);
                fputc('\n', aesresp);

                cx = AES_CreateContext(key, iv, NSS_AES_CBC,
                                       PR_FALSE, keysize, 16);
                if (cx == NULL) {
                    goto loser;
                }
                /*
                 * doublecheck our result by encrypting the result
                 * and comparing the output with the ciphertext.
                 */

                cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
                                        PR_TRUE, keysize, 16);
                if (cx2 == NULL) {
                    goto loser;
                }
                /* PT[-1] = IV[i] */
                memcpy(plaintext, iv, sizeof plaintext);
                for (j = 0; j < 1000; j++) {
                    /* Save PT[j-1] */
                    memcpy(plaintext_1, plaintext, sizeof plaintext);
                    /*
                     * If ( j=0 )
                     *      PT[j] = AES(Key[i], IV[i], CT[j])
                     *      CT[j+1] = IV[i] (= PT[j-1])
                     * Else
                     *      PT[j] = AES(Key[i], CT[j])
                     *      CT[j+1] = PT[j-1]
                     */

                    outputlen = 0;
                    rv = AES_Decrypt(cx,
                                     plaintext, &outputlen, sizeof plaintext,
                                     ciphertext, sizeof ciphertext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof ciphertext) {
                        goto loser;
                    }

                    /* doublecheck our result */
                    outputlen = 0;
                    rv = AES_Encrypt(cx2,
                                     doublecheck, &outputlen, sizeof doublecheck,
                                     plaintext, sizeof plaintext);
                    if (rv != SECSuccess) {
                        goto loser;
                    }
                    if (outputlen != sizeof plaintext) {
                        goto loser;
                    }
                    if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
                        goto loser;
                    }

                    memcpy(ciphertext, plaintext_1, sizeof ciphertext);
                }
                AES_DestroyContext(cx, PR_TRUE);
                cx = NULL;
                AES_DestroyContext(cx2, PR_TRUE);
                cx2 = NULL;

                /* Output PT[j] */
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=71 G=81

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge