2 * Copyright (C) 2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include <openssl/opensslv.h>
18 #if OPENSSL_VERSION_NUMBER >= 0x1000100fL
20 #include "openssl_gcm.h"
22 #include <openssl/evp.h>
23 #include <crypto/iv/iv_gen_seq.h>
25 /** as defined in RFC 4106 */
28 #define NONCE_LEN (IV_LEN + SALT_LEN)
30 typedef struct private_aead_t private_aead_t
;
33 * Private data of aead_t
35 struct private_aead_t
{
53 * Size of the integrity check value
65 const EVP_CIPHER
*cipher
;
69 * Do the actual en/decryption in an EVP context
71 static bool crypt(private_aead_t
*this, chunk_t data
, chunk_t assoc
, chunk_t iv
,
75 u_char nonce
[NONCE_LEN
];
79 memcpy(nonce
, this->salt
, SALT_LEN
);
80 memcpy(nonce
+ SALT_LEN
, iv
.ptr
, IV_LEN
);
82 EVP_CIPHER_CTX_init(&ctx
);
83 EVP_CIPHER_CTX_set_padding(&ctx
, 0);
84 if (!EVP_CipherInit_ex(&ctx
, this->cipher
, NULL
, NULL
, NULL
, enc
) ||
85 !EVP_CIPHER_CTX_ctrl(&ctx
, EVP_CTRL_GCM_SET_IVLEN
, NONCE_LEN
, NULL
) ||
86 !EVP_CipherInit_ex(&ctx
, NULL
, NULL
, this->key
.ptr
, nonce
, enc
))
90 if (!enc
&& !EVP_CIPHER_CTX_ctrl(&ctx
, EVP_CTRL_GCM_SET_TAG
, this->icv_size
,
92 { /* set ICV for verification on decryption */
95 if (assoc
.len
&& !EVP_CipherUpdate(&ctx
, NULL
, &len
, assoc
.ptr
, assoc
.len
))
96 { /* set AAD if specified */
99 if (!EVP_CipherUpdate(&ctx
, out
, &len
, data
.ptr
, data
.len
) ||
100 !EVP_CipherFinal_ex(&ctx
, out
+ len
, &len
))
101 { /* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
104 if (enc
&& !EVP_CIPHER_CTX_ctrl(&ctx
, EVP_CTRL_GCM_GET_TAG
, this->icv_size
,
106 { /* copy back the ICV when encrypting */
112 EVP_CIPHER_CTX_cleanup(&ctx
);
116 METHOD(aead_t
, encrypt
, bool,
117 private_aead_t
*this, chunk_t plain
, chunk_t assoc
, chunk_t iv
,
125 *encrypted
= chunk_alloc(plain
.len
+ this->icv_size
);
126 out
= encrypted
->ptr
;
128 return crypt(this, plain
, assoc
, iv
, out
, 1);
131 METHOD(aead_t
, decrypt
, bool,
132 private_aead_t
*this, chunk_t encrypted
, chunk_t assoc
, chunk_t iv
,
137 if (encrypted
.len
< this->icv_size
)
141 encrypted
.len
-= this->icv_size
;
146 *plain
= chunk_alloc(encrypted
.len
);
149 return crypt(this, encrypted
, assoc
, iv
, out
, 0);
152 METHOD(aead_t
, get_block_size
, size_t,
153 private_aead_t
*this)
155 return this->cipher
->block_size
;
158 METHOD(aead_t
, get_icv_size
, size_t,
159 private_aead_t
*this)
161 return this->icv_size
;
164 METHOD(aead_t
, get_iv_size
, size_t,
165 private_aead_t
*this)
170 METHOD(aead_t
, get_iv_gen
, iv_gen_t
*,
171 private_aead_t
*this)
176 METHOD(aead_t
, get_key_size
, size_t,
177 private_aead_t
*this)
179 return this->key
.len
+ SALT_LEN
;
182 METHOD(aead_t
, set_key
, bool,
183 private_aead_t
*this, chunk_t key
)
185 if (key
.len
!= get_key_size(this))
189 memcpy(this->salt
, key
.ptr
+ key
.len
- SALT_LEN
, SALT_LEN
);
190 memcpy(this->key
.ptr
, key
.ptr
, this->key
.len
);
194 METHOD(aead_t
, destroy
, void,
195 private_aead_t
*this)
197 chunk_clear(&this->key
);
198 this->iv_gen
->destroy(this->iv_gen
);
203 * Described in header
205 aead_t
*openssl_gcm_create(encryption_algorithm_t algo
, size_t key_size
)
207 private_aead_t
*this;
213 .get_block_size
= _get_block_size
,
214 .get_icv_size
= _get_icv_size
,
215 .get_iv_size
= _get_iv_size
,
216 .get_iv_gen
= _get_iv_gen
,
217 .get_key_size
= _get_key_size
,
225 case ENCR_AES_GCM_ICV8
:
228 case ENCR_AES_GCM_ICV12
:
231 case ENCR_AES_GCM_ICV16
:
241 case ENCR_AES_GCM_ICV8
:
242 case ENCR_AES_GCM_ICV12
:
243 case ENCR_AES_GCM_ICV16
:
250 this->cipher
= EVP_get_cipherbyname("aes-128-gcm");
253 this->cipher
= EVP_get_cipherbyname("aes-192-gcm");
256 this->cipher
= EVP_get_cipherbyname("aes-256-gcm");
274 this->key
= chunk_alloc(key_size
);
275 this->iv_gen
= iv_gen_seq_create();
277 return &this->public;
280 #endif /* OPENSSL_VERSION_NUMBER */