e6bb9354c12f20af2707254738a8900f95adb307
[strongswan.git] / src / libstrongswan / plugins / af_alg / af_alg_prf.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "af_alg_prf.h"
17 #include "af_alg_ops.h"
18
19 typedef struct private_af_alg_prf_t private_af_alg_prf_t;
20
21 /**
22 * Private data of a af_alg_prf_t object.
23 */
24 struct private_af_alg_prf_t {
25
26 /**
27 * Public af_alg_prf_t interface.
28 */
29 af_alg_prf_t public;
30
31 /**
32 * AF_ALG operations
33 */
34 af_alg_ops_t *ops;
35
36 /**
37 * Size of the PRF output
38 */
39 size_t block_size;
40
41 /**
42 * Default key size
43 */
44 size_t key_size;
45
46 /**
47 * Using an XCBC algorithm?
48 */
49 bool xcbc;
50 };
51
52 /**
53 * Algorithm database
54 */
55 static struct {
56 pseudo_random_function_t id;
57 char *name;
58 size_t block_size;
59 bool xcbc;
60 } algs[] = {
61 {PRF_HMAC_SHA1, "hmac(sha1)", 20, FALSE, },
62 {PRF_HMAC_SHA2_256, "hmac(sha256)", 32, FALSE, },
63 {PRF_HMAC_MD5, "hmac(md5)", 16, FALSE, },
64 {PRF_HMAC_SHA2_384, "hmac(sha384)", 48, FALSE, },
65 {PRF_HMAC_SHA2_512, "hmac(sha512)", 64, FALSE, },
66 {PRF_AES128_XCBC, "xcbc(aes)", 16, TRUE, },
67 {PRF_CAMELLIA128_XCBC, "xcbc(camellia)", 16, TRUE, },
68 };
69
70 /**
71 * See header.
72 */
73 void af_alg_prf_probe()
74 {
75 af_alg_ops_t *ops;
76 int i;
77
78 for (i = 0; i < countof(algs); i++)
79 {
80 ops = af_alg_ops_create("hash", algs[i].name);
81 if (ops)
82 {
83 ops->destroy(ops);
84 lib->crypto->add_prf(lib->crypto, algs[i].id, "af_alg",
85 (prf_constructor_t)af_alg_prf_create);
86 }
87 }
88 }
89
90 /**
91 * Get the kernel algorithm string and block size for our identifier
92 */
93 static size_t lookup_alg(integrity_algorithm_t algo, char **name, bool *xcbc)
94 {
95 int i;
96
97 for (i = 0; i < countof(algs); i++)
98 {
99 if (algs[i].id == algo)
100 {
101 *name = algs[i].name;
102 *xcbc = algs[i].xcbc;
103 return algs[i].block_size;
104 }
105 }
106 return 0;
107 }
108
109 METHOD(prf_t, get_bytes, void,
110 private_af_alg_prf_t *this, chunk_t seed, u_int8_t *buffer)
111 {
112 this->ops->hash(this->ops, seed, buffer, this->block_size);
113 }
114
115 METHOD(prf_t, allocate_bytes, void,
116 private_af_alg_prf_t *this, chunk_t seed, chunk_t *chunk)
117 {
118 if (chunk)
119 {
120 *chunk = chunk_alloc(this->block_size);
121 get_bytes(this, seed, chunk->ptr);
122 }
123 else
124 {
125 get_bytes(this, seed, NULL);
126 }
127 }
128
129 METHOD(prf_t, get_block_size, size_t,
130 private_af_alg_prf_t *this)
131 {
132 return this->block_size;
133 }
134
135 METHOD(prf_t, get_key_size, size_t,
136 private_af_alg_prf_t *this)
137 {
138 return this->block_size;
139 }
140
141 METHOD(prf_t, set_key, void,
142 private_af_alg_prf_t *this, chunk_t key)
143 {
144 char buf[this->block_size];
145
146 if (this->xcbc)
147 {
148 /* The kernel currently does not support variable length XCBC keys,
149 * do RFC4434 key padding/reduction manually. */
150 if (key.len < this->block_size)
151 {
152 memset(buf, 0, this->block_size);
153 memcpy(buf, key.ptr, key.len);
154 key = chunk_from_thing(buf);
155 }
156 else if (key.len > this->block_size)
157 {
158 memset(buf, 0, this->block_size);
159 this->ops->set_key(this->ops, chunk_from_thing(buf));
160 this->ops->hash(this->ops, key, buf, this->block_size);
161 key = chunk_from_thing(buf);
162 }
163 }
164 this->ops->set_key(this->ops, key);
165 }
166
167 METHOD(prf_t, destroy, void,
168 private_af_alg_prf_t *this)
169 {
170 this->ops->destroy(this->ops);
171 free(this);
172 }
173
174 /*
175 * Described in header.
176 */
177 af_alg_prf_t *af_alg_prf_create(pseudo_random_function_t algo)
178 {
179 private_af_alg_prf_t *this;
180 size_t block_size;
181 bool xcbc;
182 char *name;
183
184 block_size = lookup_alg(algo, &name, &xcbc);
185 if (!block_size)
186 { /* not supported by kernel */
187 return NULL;
188 }
189
190 INIT(this,
191 .public = {
192 .prf = {
193 .get_bytes = _get_bytes,
194 .allocate_bytes = _allocate_bytes,
195 .get_block_size = _get_block_size,
196 .get_key_size = _get_key_size,
197 .set_key = _set_key,
198 .destroy = _destroy,
199 },
200 },
201 .ops = af_alg_ops_create("hash", name),
202 .block_size = block_size,
203 .xcbc = xcbc,
204 );
205 if (!this->ops)
206 {
207 free(this);
208 return NULL;
209 }
210 return &this->public;
211 }