+static int aes_gcm(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+ {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ /* If not set up, return error */
+ if (!gctx->iv_set && !gctx->key_set)
+ return -1;
+ if (!ctx->encrypt && gctx->taglen < 0)
+ return -1;
+ if (in)
+ {
+ if (out == NULL)
+ {
+ if (CRYPTO_gcm128_aad(gctx->gcm, in, len))
+ return -1;
+ }
+ else if (ctx->encrypt)
+ {
+ if (CRYPTO_gcm128_encrypt(gctx->gcm, in, out, len))
+ return -1;
+ }
+ else
+ {
+ if (CRYPTO_gcm128_decrypt(gctx->gcm, in, out, len))
+ return -1;
+ }
+ return len;
+ }
+ else
+ {
+ if (!ctx->encrypt)
+ {
+ if (CRYPTO_gcm128_finish(gctx->gcm,
+ gctx->tag, gctx->taglen) != 0)
+ return -1;
+ gctx->iv_set = 0;
+ return 0;
+ }
+ CRYPTO_gcm128_tag(gctx->gcm, gctx->tag, 16);
+ gctx->taglen = 16;
+ /* Don't reuse the IV */
+ gctx->iv_set = 0;
+ return 0;
+ }
+
+ }
+
+static const EVP_CIPHER aes_128_gcm_cipher=
+ {
+ NID_aes_128_gcm,1,16,12,
+ EVP_CIPH_GCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_gcm_init_key,
+ aes_gcm,
+ aes_gcm_cleanup,
+ sizeof(EVP_AES_GCM_CTX),
+ NULL,
+ NULL,
+ aes_gcm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_128_gcm (void)
+{ return &aes_128_gcm_cipher; }
+
+static const EVP_CIPHER aes_192_gcm_cipher=
+ {
+ NID_aes_128_gcm,1,24,12,
+ EVP_CIPH_GCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_gcm_init_key,
+ aes_gcm,
+ aes_gcm_cleanup,
+ sizeof(EVP_AES_GCM_CTX),
+ NULL,
+ NULL,
+ aes_gcm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_192_gcm (void)
+{ return &aes_192_gcm_cipher; }
+
+static const EVP_CIPHER aes_256_gcm_cipher=
+ {
+ NID_aes_128_gcm,1,32,12,
+ EVP_CIPH_GCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_gcm_init_key,
+ aes_gcm,
+ aes_gcm_cleanup,
+ sizeof(EVP_AES_GCM_CTX),
+ NULL,
+ NULL,
+ aes_gcm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_256_gcm (void)
+{ return &aes_256_gcm_cipher; }
+