charon-nm: Allow using fixed source ports
[strongswan.git] / src / libstrongswan / crypto / aead.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "aead.h"
20
21 #include <utils/debug.h>
22 #include <crypto/iv/iv_gen_rand.h>
23
24 typedef struct private_aead_t private_aead_t;
25
26 /**
27 * Private data of an aead_t object.
28 */
29 struct private_aead_t {
30
31 /**
32 * Public aead_t interface.
33 */
34 aead_t public;
35
36 /**
37 * traditional crypter
38 */
39 crypter_t *crypter;
40
41 /**
42 * traditional signer
43 */
44 signer_t *signer;
45
46 /**
47 * IV generator
48 */
49 iv_gen_t *iv_gen;
50 };
51
52 METHOD(aead_t, encrypt, bool,
53 private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
54 chunk_t *encrypted)
55 {
56 chunk_t encr, sig;
57
58 if (!this->signer->get_signature(this->signer, assoc, NULL) ||
59 !this->signer->get_signature(this->signer, iv, NULL))
60 {
61 return FALSE;
62 }
63
64 if (encrypted)
65 {
66 if (!this->crypter->encrypt(this->crypter, plain, iv, &encr))
67 {
68 return FALSE;
69 }
70 if (!this->signer->allocate_signature(this->signer, encr, &sig))
71 {
72 free(encr.ptr);
73 return FALSE;
74 }
75 *encrypted = chunk_cat("cmm", iv, encr, sig);
76 }
77 else
78 {
79 if (!this->crypter->encrypt(this->crypter, plain, iv, NULL) ||
80 !this->signer->get_signature(this->signer,
81 plain, plain.ptr + plain.len))
82 {
83 return FALSE;
84 }
85 }
86 return TRUE;
87 }
88
89 METHOD(aead_t, decrypt, bool,
90 private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
91 chunk_t *plain)
92 {
93 chunk_t sig;
94 size_t bs;
95
96 bs = this->crypter->get_block_size(this->crypter);
97 sig.len = this->signer->get_block_size(this->signer);
98 if (sig.len > encrypted.len || (encrypted.len - sig.len) % bs)
99 {
100 DBG1(DBG_LIB, "invalid encrypted data length %d with block size %d",
101 encrypted.len - sig.len, bs);
102 return FALSE;
103 }
104 chunk_split(encrypted, "mm", encrypted.len - sig.len,
105 &encrypted, sig.len, &sig);
106
107 if (!this->signer->get_signature(this->signer, assoc, NULL) ||
108 !this->signer->get_signature(this->signer, iv, NULL))
109 {
110 return FALSE;
111 }
112 if (!this->signer->verify_signature(this->signer, encrypted, sig))
113 {
114 DBG1(DBG_LIB, "MAC verification failed");
115 return FALSE;
116 }
117 return this->crypter->decrypt(this->crypter, encrypted, iv, plain);
118 }
119
120 METHOD(aead_t, get_block_size, size_t,
121 private_aead_t *this)
122 {
123 return this->crypter->get_block_size(this->crypter);
124 }
125
126 METHOD(aead_t, get_icv_size, size_t,
127 private_aead_t *this)
128 {
129 return this->signer->get_block_size(this->signer);
130 }
131
132 METHOD(aead_t, get_iv_size, size_t,
133 private_aead_t *this)
134 {
135 return this->crypter->get_iv_size(this->crypter);
136 }
137
138 METHOD(aead_t, get_iv_gen, iv_gen_t*,
139 private_aead_t *this)
140 {
141 return this->iv_gen;
142 }
143
144 METHOD(aead_t, get_key_size, size_t,
145 private_aead_t *this)
146 {
147 return this->crypter->get_key_size(this->crypter) +
148 this->signer->get_key_size(this->signer);
149 }
150
151 METHOD(aead_t, set_key, bool,
152 private_aead_t *this, chunk_t key)
153 {
154 chunk_t sig, enc;
155
156 chunk_split(key, "mm", this->signer->get_key_size(this->signer), &sig,
157 this->crypter->get_key_size(this->crypter), &enc);
158
159 return this->signer->set_key(this->signer, sig) &&
160 this->crypter->set_key(this->crypter, enc);
161 }
162
163 METHOD(aead_t, destroy, void,
164 private_aead_t *this)
165 {
166 this->iv_gen->destroy(this->iv_gen);
167 this->crypter->destroy(this->crypter);
168 this->signer->destroy(this->signer);
169 free(this);
170 }
171
172 /**
173 * See header
174 */
175 aead_t *aead_create(crypter_t *crypter, signer_t *signer, iv_gen_t *iv_gen)
176 {
177 private_aead_t *this;
178
179 INIT(this,
180 .public = {
181 .encrypt = _encrypt,
182 .decrypt = _decrypt,
183 .get_block_size = _get_block_size,
184 .get_icv_size = _get_icv_size,
185 .get_iv_size = _get_iv_size,
186 .get_iv_gen = _get_iv_gen,
187 .get_key_size = _get_key_size,
188 .set_key = _set_key,
189 .destroy = _destroy,
190 },
191 .crypter = crypter,
192 .signer = signer,
193 .iv_gen = iv_gen,
194 );
195
196 return &this->public;
197 }