summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-02-09 16:21:43 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-02-09 16:21:43 +0000
commitb3d8022eddb3c6c3e840054fcf3dcd77d1c3c2be (patch)
treeac71caa838796bc99cf591ed113f3694e66d6c0c /crypto
parent632d83f0a3fbda2e7f4e556183792597b7db88fc (diff)
Add GCM IV generator. Add some FIPS restrictions to GCM. Update fips_gcmtest.
Diffstat (limited to 'crypto')
-rw-r--r--crypto/evp/e_aes.c83
-rw-r--r--crypto/evp/evp.h2
2 files changed, 75 insertions, 10 deletions
diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c
index ed21d0a923..4206fd0da4 100644
--- a/crypto/evp/e_aes.c
+++ b/crypto/evp/e_aes.c
@@ -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;
}
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index f42bc2687a..042dc1c577 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -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
{