Add GCM IV generator. Add some FIPS restrictions to GCM. Update fips_gcmtest.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 9 Feb 2011 16:21:43 +0000 (16:21 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 9 Feb 2011 16:21:43 +0000 (16:21 +0000)
CHANGES
crypto/evp/e_aes.c
crypto/evp/evp.h
fips/aes/fips_gcmtest.c

diff --git a/CHANGES b/CHANGES
index 05d95a8..36bbb2d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Add some FIPS mode restrictions to GCM. Add internal IV generator.
+     Update fips_gcmtest to use IV generator.
+     [Steve Henson]
+
   *) Initial, experimental EVP support for AES-GCM. AAD can be input by
      setting output buffer to NULL. The *Final function must be
      called although it will not retrieve any additional data. The tag
index ed21d0a..4206fd0 100644 (file)
@@ -59,6 +59,7 @@
 #include <openssl/aes.h>
 #include "evp_locl.h"
 #include <openssl/modes.h>
+#include <openssl/rand.h>
 
 static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                                        const unsigned char *iv, int enc);
@@ -197,11 +198,15 @@ typedef struct
        int iv_set;
        /* Pointer to GCM128_CTX: FIXME actual structure later */
        GCM128_CONTEXT *gcm;
+       /* Temporary IV store */
+       unsigned char *iv;
        /* IV length */
        int ivlen;
        /* Tag to verify */
        unsigned char tag[16];
        int taglen;
+       /* It is OK to generate IVs */
+       int iv_gen;
        } EVP_AES_GCM_CTX;
 
 static int aes_gcm_cleanup(EVP_CIPHER_CTX *c)
@@ -209,9 +214,25 @@ static int aes_gcm_cleanup(EVP_CIPHER_CTX *c)
        EVP_AES_GCM_CTX *gctx = c->cipher_data;
        if (gctx->gcm)
                CRYPTO_gcm128_release(gctx->gcm);
+       if (gctx->iv != c->iv)
+               OPENSSL_free(gctx->iv);
        return 1;
        }
 
+/* increment counter (64-bit int) by 1 */
+static void ctr64_inc(unsigned char *counter) {
+       int n=8;
+       unsigned char  c;
+
+       do {
+               --n;
+               c = counter[n];
+               ++c;
+               counter[n] = c;
+               if (c) return;
+       } while (n);
+}
+
 static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
        {
        EVP_AES_GCM_CTX *gctx = c->cipher_data;
@@ -222,12 +243,28 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
                gctx->key_set = 0;
                gctx->iv_set = 0;
                gctx->ivlen = c->cipher->iv_len;
+               gctx->iv = c->iv;
                gctx->taglen = -1;
+               gctx->iv_gen = 0;
                return 1;
 
        case EVP_CTRL_GCM_SET_IVLEN:
                if (arg <= 0)
                        return 0;
+#ifdef OPENSSL_FIPS
+               if (FIPS_mode() && !(c->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW)
+                                                && arg < 12)
+                       return 0;
+#endif
+               /* Allocate memory for IV if needed */
+               if ((arg > EVP_MAX_IV_LENGTH) && (arg > gctx->ivlen))
+                       {
+                       if (gctx->iv != c->iv)
+                               OPENSSL_free(gctx->iv);
+                       gctx->iv = OPENSSL_malloc(arg);
+                       if (!gctx->iv)
+                               return 0;
+                       }
                gctx->ivlen = arg;
                return 1;
 
@@ -244,6 +281,39 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
                memcpy(ptr, gctx->tag, arg);
                return 1;
 
+       case EVP_CTRL_GCM_SET_IV_FIXED:
+               /* Special case: -1 length restores whole IV */
+               if (arg == -1)
+                       {
+                       memcpy(gctx->iv, ptr, gctx->ivlen);
+                       gctx->iv_gen = 1;
+                       return 1;
+                       }
+               /* Fixed field must be at least 4 bytes and invocation field
+                * at least 8.
+                */
+               if ((arg < 4) || (gctx->ivlen - arg) < 8)
+                       return 0;
+               if (arg)
+                       memcpy(gctx->iv, ptr, arg);
+               if (RAND_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0)
+                       return 0;
+               gctx->iv_gen = 1;
+               return 1;
+
+       case EVP_CTRL_GCM_IV_GEN:
+               if (gctx->iv_gen == 0 || gctx->key_set == 0)
+                       return 0;
+               CRYPTO_gcm128_setiv(gctx->gcm, gctx->iv, gctx->ivlen);
+               memcpy(ptr, gctx->iv, gctx->ivlen);
+               /* Invocation field will be at least 8 bytes in size and
+                * so no need to check wrap around or increment more than
+                * last 8 bytes.
+                */
+               ctr64_inc(gctx->iv + gctx->ivlen - 8);
+               gctx->iv_set = 1;
+               return 1;
+
        default:
                return -1;
 
@@ -272,7 +342,7 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                 * saved IV.
                 */
                if (iv == NULL && gctx->iv_set)
-                       iv = ctx->iv;
+                       iv = gctx->iv;
                if (iv)
                        {
                        CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen);
@@ -286,16 +356,9 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                if (gctx->key_set)
                        CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen);
                else
-                       {
-                       /* If IV is too large for EVP_CIPHER_CTX buffer
-                        * return an error. This can be avoided by either
-                        * setting the key first or key and iv simultaneously.
-                        */
-                       if (gctx->ivlen > EVP_MAX_IV_LENGTH)
-                               return 0;
-                       memcpy(ctx->iv, iv, gctx->ivlen);
-                       }
+                       memcpy(gctx->iv, iv, gctx->ivlen);
                gctx->iv_set = 1;
+               gctx->iv_gen = 0;
                }
        return 1;
        }
index f42bc26..042dc1c 100644 (file)
@@ -374,6 +374,8 @@ struct evp_cipher_st
 #define        EVP_CTRL_GCM_SET_IVLEN          0x9
 #define        EVP_CTRL_GCM_GET_TAG            0x10
 #define        EVP_CTRL_GCM_SET_TAG            0x11
+#define                EVP_CTRL_GCM_SET_IV_FIXED       0x12
+#define                EVP_CTRL_GCM_IV_GEN             0x13
 
 typedef struct evp_cipher_info_st
        {
index f37d629..32bbf3b 100644 (file)
@@ -172,13 +172,31 @@ static void gcmtest(int encrypt)
                                exit(1);
                                }
                        }
-               /* FIXME: need intenal IV generation */
-               if (encrypt && iv && pt && aad)
+               if (encrypt && pt && aad && (iv || encrypt==1))
                        {
                        tag = OPENSSL_malloc(taglen);
                        EVP_CipherInit_ex(&ctx, gcm, NULL, NULL, NULL, 1);
                        EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, ivlen, 0);
-                       EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
+                       if (encrypt == 1)
+                               {
+                               static unsigned char iv_fixed[4] = {1,2,3,4};
+                               if (!iv)
+                                       iv = OPENSSL_malloc(ivlen);
+                               EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1);
+                               EVP_CIPHER_CTX_ctrl(&ctx,
+                                               EVP_CTRL_GCM_SET_IV_FIXED,
+                                               4, iv_fixed);
+                               if (!EVP_CIPHER_CTX_ctrl(&ctx,
+                                       EVP_CTRL_GCM_IV_GEN, 0, iv))
+                                       {
+                                       fprintf(stderr, "IV gen error\n");
+                                       exit(1);
+                                       }
+                               OutputValue("IV", iv, ivlen, stdout, 0);
+                               }
+                       else
+                               EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
+
 
                        if (aadlen)
                                EVP_Cipher(&ctx, NULL, aad, aadlen);
@@ -254,6 +272,8 @@ int main(int argc,char **argv)
                exit(1);
        if(!strcmp(argv[1],"-encrypt"))
                encrypt = 1;
+       else if(!strcmp(argv[1],"-encryptIVext"))
+               encrypt = 2;
        else if(!strcmp(argv[1],"-decrypt"))
                encrypt = 0;
        else