* ====================================================================
*/
+#define OPENSSL_FIPSAPI
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Make temporary keys K1 and K2 */
-static void make_kn(unsigned char *k1, unsigned char *l, int bl)
+static void make_kn(unsigned char *k1, const unsigned char *l, int bl)
{
int i;
+ unsigned char c = l[0], carry = c>>7, cnext;
+
/* Shift block to left, including carry */
- for (i = 0; i < bl; i++)
- {
- k1[i] = l[i] << 1;
- if (i < bl - 1 && l[i + 1] & 0x80)
- k1[i] |= 1;
- }
+ for (i = 0; i < bl-1; i++, c = cnext)
+ k1[i] = (c << 1) | ((cnext=l[i+1]) >> 7);
+
/* If MSB set fixup with R */
- if (l[0] & 0x80)
- k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b;
+ k1[i] = (c << 1) ^ ((0-carry)&(bl==16?0x87:0x1b));
}
CMAC_CTX *CMAC_CTX_new(void)
OPENSSL_free(ctx);
}
+int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in)
+ {
+ int bl;
+ if (in->nlast_block == -1)
+ return 0;
+ if (!EVP_CIPHER_CTX_copy(&out->cctx, &in->cctx))
+ return 0;
+ bl = M_EVP_CIPHER_CTX_block_size(&in->cctx);
+ memcpy(out->k1, in->k1, bl);
+ memcpy(out->k2, in->k2, bl);
+ memcpy(out->tbl, in->tbl, bl);
+ memcpy(out->last_block, in->last_block, bl);
+ out->nlast_block = in->nlast_block;
+ return 1;
+ }
+
int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
const EVP_CIPHER *cipher, ENGINE *impl)
{
- static unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH];
+ __fips_constseg
+ static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = {0};
/* All zeros means restart */
if (!key && !cipher && !impl && keylen == 0)
{
/* Not initialised */
- if (ctx->last_block == -1)
+ if (ctx->nlast_block == -1)
return 0;
- if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
+ if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
return 0;
- return 0;
+ memset(ctx->tbl, 0, M_EVP_CIPHER_CTX_block_size(&ctx->cctx));
+ ctx->nlast_block = 0;
+ return 1;
}
/* Initialiase context */
- if (cipher && !EVP_EncryptInit_ex(&ctx->cctx, cipher, impl, NULL, NULL))
+ if (cipher && !M_EVP_EncryptInit_ex(&ctx->cctx, cipher, impl, NULL, NULL))
return 0;
/* Non-NULL key means initialisation complete */
if (key)
{
int bl;
- if (!EVP_CIPHER_CTX_cipher(&ctx->cctx))
+ if (!M_EVP_CIPHER_CTX_cipher(&ctx->cctx))
return 0;
if (!EVP_CIPHER_CTX_set_key_length(&ctx->cctx, keylen))
return 0;
- if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv))
+ if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv))
return 0;
- bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+ bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, zero_iv, bl))
return 0;
make_kn(ctx->k1, ctx->tbl, bl);
make_kn(ctx->k2, ctx->k1, bl);
OPENSSL_cleanse(ctx->tbl, bl);
/* Reset context again ready for first data block */
- if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
+ if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
return 0;
+ /* Zero tbl so resume works */
+ memset(ctx->tbl, 0, bl);
ctx->nlast_block = 0;
}
return 1;
return 0;
if (dlen == 0)
return 1;
- bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+ bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
/* Copy into partial block if we need to */
if (ctx->nlast_block > 0)
{
}
-size_t CMAC_Final(CMAC_CTX *ctx, unsigned char *out)
+int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen)
{
int i, bl, lb;
if (ctx->nlast_block == -1)
return 0;
- bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+ bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
+ *poutlen = (size_t)bl;
+ if (!out)
+ return 1;
lb = ctx->nlast_block;
/* Is last block complete? */
if (lb == bl)
{
for (i = 0; i < bl; i++)
- ctx->last_block[i] ^= ctx->k1[i];
+ out[i] = ctx->last_block[i] ^ ctx->k1[i];
}
else
{
if (bl - lb > 1)
memset(ctx->last_block + lb + 1, 0, bl - lb - 1);
for (i = 0; i < bl; i++)
- ctx->last_block[i] ^= ctx->k2[i];
+ out[i] = ctx->last_block[i] ^ ctx->k2[i];
+ }
+ if (!EVP_Cipher(&ctx->cctx, out, out, bl))
+ {
+ OPENSSL_cleanse(out, bl);
+ return 0;
}
- if (!EVP_Cipher(&ctx->cctx, out, ctx->last_block, bl))
+ return 1;
+ }
+
+int CMAC_resume(CMAC_CTX *ctx)
+ {
+ if (ctx->nlast_block == -1)
return 0;
- return bl;
+ /* The buffer "tbl" containes the last fully encrypted block
+ * which is the last IV (or all zeroes if no last encrypted block).
+ * The last block has not been modified since CMAC_final().
+ * So reinitliasing using the last decrypted block will allow
+ * CMAC to continue after calling CMAC_Final().
+ */
+ return M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, ctx->tbl);
}