1ebb5671cSchristos /*
2ebb5671cSchristos * Crypto wrapper for Linux kernel AF_ALG
3ebb5671cSchristos * Copyright (c) 2017, Jouni Malinen <j@w1.fi>
4ebb5671cSchristos *
5ebb5671cSchristos * This software may be distributed under the terms of the BSD license.
6ebb5671cSchristos * See README for more details.
7ebb5671cSchristos */
8ebb5671cSchristos
9ebb5671cSchristos #include "includes.h"
10ebb5671cSchristos #include <linux/if_alg.h>
11ebb5671cSchristos
12ebb5671cSchristos #include "common.h"
13ebb5671cSchristos #include "crypto.h"
14ebb5671cSchristos #include "md5.h"
15ebb5671cSchristos #include "sha1.h"
16ebb5671cSchristos #include "sha256.h"
17ebb5671cSchristos #include "sha384.h"
18ebb5671cSchristos #include "aes.h"
19ebb5671cSchristos
20ebb5671cSchristos
21ebb5671cSchristos #ifndef SOL_ALG
22ebb5671cSchristos #define SOL_ALG 279
23ebb5671cSchristos #endif /* SOL_ALG */
24ebb5671cSchristos
25ebb5671cSchristos
linux_af_alg_socket(const char * type,const char * name)26ebb5671cSchristos static int linux_af_alg_socket(const char *type, const char *name)
27ebb5671cSchristos {
28ebb5671cSchristos struct sockaddr_alg sa;
29ebb5671cSchristos int s;
30ebb5671cSchristos
31ebb5671cSchristos if (TEST_FAIL())
32ebb5671cSchristos return -1;
33ebb5671cSchristos
34ebb5671cSchristos s = socket(AF_ALG, SOCK_SEQPACKET, 0);
35ebb5671cSchristos if (s < 0) {
36ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: Failed to open AF_ALG socket: %s",
37ebb5671cSchristos __func__, strerror(errno));
38ebb5671cSchristos return -1;
39ebb5671cSchristos }
40ebb5671cSchristos
41ebb5671cSchristos os_memset(&sa, 0, sizeof(sa));
42ebb5671cSchristos sa.salg_family = AF_ALG;
43ebb5671cSchristos os_strlcpy((char *) sa.salg_type, type, sizeof(sa.salg_type));
44ebb5671cSchristos os_strlcpy((char *) sa.salg_name, name, sizeof(sa.salg_type));
45ebb5671cSchristos if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
46ebb5671cSchristos wpa_printf(MSG_ERROR,
47ebb5671cSchristos "%s: Failed to bind AF_ALG socket(%s,%s): %s",
48ebb5671cSchristos __func__, type, name, strerror(errno));
49ebb5671cSchristos close(s);
50ebb5671cSchristos return -1;
51ebb5671cSchristos }
52ebb5671cSchristos
53ebb5671cSchristos return s;
54ebb5671cSchristos }
55ebb5671cSchristos
56ebb5671cSchristos
linux_af_alg_hash_vector(const char * alg,const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac,size_t mac_len)57ebb5671cSchristos static int linux_af_alg_hash_vector(const char *alg, const u8 *key,
58ebb5671cSchristos size_t key_len, size_t num_elem,
59ebb5671cSchristos const u8 *addr[], const size_t *len,
60ebb5671cSchristos u8 *mac, size_t mac_len)
61ebb5671cSchristos {
62ebb5671cSchristos int s, t;
63ebb5671cSchristos size_t i;
64ebb5671cSchristos ssize_t res;
65ebb5671cSchristos int ret = -1;
66ebb5671cSchristos
67ebb5671cSchristos s = linux_af_alg_socket("hash", alg);
68ebb5671cSchristos if (s < 0)
69ebb5671cSchristos return -1;
70ebb5671cSchristos
71ebb5671cSchristos if (key && setsockopt(s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
72ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
73ebb5671cSchristos __func__, strerror(errno));
74ebb5671cSchristos close(s);
75ebb5671cSchristos return -1;
76ebb5671cSchristos }
77ebb5671cSchristos
78ebb5671cSchristos t = accept(s, NULL, NULL);
79ebb5671cSchristos if (t < 0) {
80ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
81ebb5671cSchristos __func__, strerror(errno));
82ebb5671cSchristos close(s);
83ebb5671cSchristos return -1;
84ebb5671cSchristos }
85ebb5671cSchristos
86ebb5671cSchristos for (i = 0; i < num_elem; i++) {
87ebb5671cSchristos res = send(t, addr[i], len[i], i + 1 < num_elem ? MSG_MORE : 0);
88ebb5671cSchristos if (res < 0) {
89ebb5671cSchristos wpa_printf(MSG_ERROR,
90ebb5671cSchristos "%s: send on AF_ALG socket failed: %s",
91ebb5671cSchristos __func__, strerror(errno));
92ebb5671cSchristos goto fail;
93ebb5671cSchristos }
94ebb5671cSchristos if ((size_t) res < len[i]) {
95ebb5671cSchristos wpa_printf(MSG_ERROR,
96ebb5671cSchristos "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
97ebb5671cSchristos __func__, (int) res, (int) len[i]);
98ebb5671cSchristos goto fail;
99ebb5671cSchristos }
100ebb5671cSchristos }
101ebb5671cSchristos
102ebb5671cSchristos res = recv(t, mac, mac_len, 0);
103ebb5671cSchristos if (res < 0) {
104ebb5671cSchristos wpa_printf(MSG_ERROR,
105ebb5671cSchristos "%s: recv on AF_ALG socket failed: %s",
106ebb5671cSchristos __func__, strerror(errno));
107ebb5671cSchristos goto fail;
108ebb5671cSchristos }
109ebb5671cSchristos if ((size_t) res < mac_len) {
110ebb5671cSchristos wpa_printf(MSG_ERROR,
111ebb5671cSchristos "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
112ebb5671cSchristos __func__, (int) res, (int) mac_len);
113ebb5671cSchristos goto fail;
114ebb5671cSchristos }
115ebb5671cSchristos
116ebb5671cSchristos ret = 0;
117ebb5671cSchristos fail:
118ebb5671cSchristos close(t);
119ebb5671cSchristos close(s);
120ebb5671cSchristos
121ebb5671cSchristos return ret;
122ebb5671cSchristos }
123ebb5671cSchristos
124ebb5671cSchristos
md4_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)125ebb5671cSchristos int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
126ebb5671cSchristos {
127ebb5671cSchristos return linux_af_alg_hash_vector("md4", NULL, 0, num_elem, addr, len,
128ebb5671cSchristos mac, 16);
129ebb5671cSchristos }
130ebb5671cSchristos
131ebb5671cSchristos
md5_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)132ebb5671cSchristos int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
133ebb5671cSchristos {
134ebb5671cSchristos return linux_af_alg_hash_vector("md5", NULL, 0, num_elem, addr, len,
135ebb5671cSchristos mac, MD5_MAC_LEN);
136ebb5671cSchristos }
137ebb5671cSchristos
138ebb5671cSchristos
sha1_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)139ebb5671cSchristos int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
140ebb5671cSchristos u8 *mac)
141ebb5671cSchristos {
142ebb5671cSchristos return linux_af_alg_hash_vector("sha1", NULL, 0, num_elem, addr, len,
143ebb5671cSchristos mac, SHA1_MAC_LEN);
144ebb5671cSchristos }
145ebb5671cSchristos
146ebb5671cSchristos
sha256_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)147ebb5671cSchristos int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
148ebb5671cSchristos u8 *mac)
149ebb5671cSchristos {
150ebb5671cSchristos return linux_af_alg_hash_vector("sha256", NULL, 0, num_elem, addr, len,
151ebb5671cSchristos mac, SHA256_MAC_LEN);
152ebb5671cSchristos }
153ebb5671cSchristos
154ebb5671cSchristos
sha384_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)155ebb5671cSchristos int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
156ebb5671cSchristos u8 *mac)
157ebb5671cSchristos {
158ebb5671cSchristos return linux_af_alg_hash_vector("sha384", NULL, 0, num_elem, addr, len,
159ebb5671cSchristos mac, SHA384_MAC_LEN);
160ebb5671cSchristos }
161ebb5671cSchristos
162ebb5671cSchristos
sha512_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)163ebb5671cSchristos int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
164ebb5671cSchristos u8 *mac)
165ebb5671cSchristos {
166ebb5671cSchristos return linux_af_alg_hash_vector("sha512", NULL, 0, num_elem, addr, len,
167ebb5671cSchristos mac, 64);
168ebb5671cSchristos }
169ebb5671cSchristos
170ebb5671cSchristos
hmac_md5_vector(const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)171ebb5671cSchristos int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
172ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
173ebb5671cSchristos {
174ebb5671cSchristos return linux_af_alg_hash_vector("hmac(md5)", key, key_len, num_elem,
175ebb5671cSchristos addr, len, mac, 16);
176ebb5671cSchristos }
177ebb5671cSchristos
178ebb5671cSchristos
hmac_md5(const u8 * key,size_t key_len,const u8 * data,size_t data_len,u8 * mac)179ebb5671cSchristos int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
180ebb5671cSchristos u8 *mac)
181ebb5671cSchristos {
182ebb5671cSchristos return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
183ebb5671cSchristos }
184ebb5671cSchristos
185ebb5671cSchristos
hmac_sha1_vector(const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)186ebb5671cSchristos int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
187ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
188ebb5671cSchristos {
189ebb5671cSchristos return linux_af_alg_hash_vector("hmac(sha1)", key, key_len, num_elem,
190ebb5671cSchristos addr, len, mac, SHA1_MAC_LEN);
191ebb5671cSchristos }
192ebb5671cSchristos
193ebb5671cSchristos
hmac_sha1(const u8 * key,size_t key_len,const u8 * data,size_t data_len,u8 * mac)194ebb5671cSchristos int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
195ebb5671cSchristos u8 *mac)
196ebb5671cSchristos {
197ebb5671cSchristos return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
198ebb5671cSchristos }
199ebb5671cSchristos
200ebb5671cSchristos
hmac_sha256_vector(const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)201ebb5671cSchristos int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
202ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
203ebb5671cSchristos {
204ebb5671cSchristos return linux_af_alg_hash_vector("hmac(sha256)", key, key_len, num_elem,
205ebb5671cSchristos addr, len, mac, SHA256_MAC_LEN);
206ebb5671cSchristos }
207ebb5671cSchristos
208ebb5671cSchristos
hmac_sha256(const u8 * key,size_t key_len,const u8 * data,size_t data_len,u8 * mac)209ebb5671cSchristos int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
210ebb5671cSchristos size_t data_len, u8 *mac)
211ebb5671cSchristos {
212ebb5671cSchristos return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
213ebb5671cSchristos }
214ebb5671cSchristos
215ebb5671cSchristos
hmac_sha384_vector(const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)216ebb5671cSchristos int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
217ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
218ebb5671cSchristos {
219ebb5671cSchristos return linux_af_alg_hash_vector("hmac(sha384)", key, key_len, num_elem,
220ebb5671cSchristos addr, len, mac, SHA384_MAC_LEN);
221ebb5671cSchristos }
222ebb5671cSchristos
223ebb5671cSchristos
hmac_sha384(const u8 * key,size_t key_len,const u8 * data,size_t data_len,u8 * mac)224ebb5671cSchristos int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
225ebb5671cSchristos size_t data_len, u8 *mac)
226ebb5671cSchristos {
227ebb5671cSchristos return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
228ebb5671cSchristos }
229ebb5671cSchristos
230ebb5671cSchristos
231ebb5671cSchristos struct crypto_hash {
232ebb5671cSchristos int s;
233ebb5671cSchristos int t;
234ebb5671cSchristos size_t mac_len;
235ebb5671cSchristos int failed;
236ebb5671cSchristos };
237ebb5671cSchristos
238ebb5671cSchristos
crypto_hash_init(enum crypto_hash_alg alg,const u8 * key,size_t key_len)239ebb5671cSchristos struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
240ebb5671cSchristos size_t key_len)
241ebb5671cSchristos {
242ebb5671cSchristos struct crypto_hash *ctx;
243ebb5671cSchristos const char *name;
244ebb5671cSchristos
245ebb5671cSchristos ctx = os_zalloc(sizeof(*ctx));
246ebb5671cSchristos if (!ctx)
247ebb5671cSchristos return NULL;
248ebb5671cSchristos
249ebb5671cSchristos switch (alg) {
250ebb5671cSchristos case CRYPTO_HASH_ALG_MD5:
251ebb5671cSchristos name = "md5";
252ebb5671cSchristos ctx->mac_len = MD5_MAC_LEN;
253ebb5671cSchristos break;
254ebb5671cSchristos case CRYPTO_HASH_ALG_SHA1:
255ebb5671cSchristos name = "sha1";
256ebb5671cSchristos ctx->mac_len = SHA1_MAC_LEN;
257ebb5671cSchristos break;
258ebb5671cSchristos case CRYPTO_HASH_ALG_HMAC_MD5:
259ebb5671cSchristos name = "hmac(md5)";
260ebb5671cSchristos ctx->mac_len = MD5_MAC_LEN;
261ebb5671cSchristos break;
262ebb5671cSchristos case CRYPTO_HASH_ALG_HMAC_SHA1:
263ebb5671cSchristos name = "hmac(sha1)";
264ebb5671cSchristos ctx->mac_len = SHA1_MAC_LEN;
265ebb5671cSchristos break;
266ebb5671cSchristos case CRYPTO_HASH_ALG_SHA256:
267ebb5671cSchristos name = "sha256";
268ebb5671cSchristos ctx->mac_len = SHA256_MAC_LEN;
269ebb5671cSchristos break;
270ebb5671cSchristos case CRYPTO_HASH_ALG_HMAC_SHA256:
271ebb5671cSchristos name = "hmac(sha256)";
272ebb5671cSchristos ctx->mac_len = SHA256_MAC_LEN;
273ebb5671cSchristos break;
274ebb5671cSchristos case CRYPTO_HASH_ALG_SHA384:
275ebb5671cSchristos name = "sha384";
276ebb5671cSchristos ctx->mac_len = SHA384_MAC_LEN;
277ebb5671cSchristos break;
278ebb5671cSchristos case CRYPTO_HASH_ALG_SHA512:
279ebb5671cSchristos name = "sha512";
280ebb5671cSchristos ctx->mac_len = 64;
281ebb5671cSchristos break;
282ebb5671cSchristos default:
283ebb5671cSchristos os_free(ctx);
284ebb5671cSchristos return NULL;
285ebb5671cSchristos }
286ebb5671cSchristos
287ebb5671cSchristos ctx->s = linux_af_alg_socket("hash", name);
288ebb5671cSchristos if (ctx->s < 0) {
289ebb5671cSchristos os_free(ctx);
290ebb5671cSchristos return NULL;
291ebb5671cSchristos }
292ebb5671cSchristos
293ebb5671cSchristos if (key && key_len &&
294ebb5671cSchristos setsockopt(ctx->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
295ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
296ebb5671cSchristos __func__, strerror(errno));
297ebb5671cSchristos close(ctx->s);
298ebb5671cSchristos os_free(ctx);
299ebb5671cSchristos return NULL;
300ebb5671cSchristos }
301ebb5671cSchristos
302ebb5671cSchristos ctx->t = accept(ctx->s, NULL, NULL);
303ebb5671cSchristos if (ctx->t < 0) {
304ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
305ebb5671cSchristos __func__, strerror(errno));
306ebb5671cSchristos close(ctx->s);
307ebb5671cSchristos os_free(ctx);
308ebb5671cSchristos return NULL;
309ebb5671cSchristos }
310ebb5671cSchristos
311ebb5671cSchristos return ctx;
312ebb5671cSchristos }
313ebb5671cSchristos
314ebb5671cSchristos
crypto_hash_update(struct crypto_hash * ctx,const u8 * data,size_t len)315ebb5671cSchristos void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
316ebb5671cSchristos {
317ebb5671cSchristos ssize_t res;
318ebb5671cSchristos
319ebb5671cSchristos if (!ctx)
320ebb5671cSchristos return;
321ebb5671cSchristos
322ebb5671cSchristos res = send(ctx->t, data, len, MSG_MORE);
323ebb5671cSchristos if (res < 0) {
324ebb5671cSchristos wpa_printf(MSG_ERROR,
325ebb5671cSchristos "%s: send on AF_ALG socket failed: %s",
326ebb5671cSchristos __func__, strerror(errno));
327ebb5671cSchristos ctx->failed = 1;
328ebb5671cSchristos return;
329ebb5671cSchristos }
330ebb5671cSchristos if ((size_t) res < len) {
331ebb5671cSchristos wpa_printf(MSG_ERROR,
332ebb5671cSchristos "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
333ebb5671cSchristos __func__, (int) res, (int) len);
334ebb5671cSchristos ctx->failed = 1;
335ebb5671cSchristos return;
336ebb5671cSchristos }
337ebb5671cSchristos }
338ebb5671cSchristos
339ebb5671cSchristos
crypto_hash_deinit(struct crypto_hash * ctx)340ebb5671cSchristos static void crypto_hash_deinit(struct crypto_hash *ctx)
341ebb5671cSchristos {
342ebb5671cSchristos close(ctx->s);
343ebb5671cSchristos close(ctx->t);
344ebb5671cSchristos os_free(ctx);
345ebb5671cSchristos }
346ebb5671cSchristos
347ebb5671cSchristos
crypto_hash_finish(struct crypto_hash * ctx,u8 * mac,size_t * len)348ebb5671cSchristos int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
349ebb5671cSchristos {
350ebb5671cSchristos ssize_t res;
351ebb5671cSchristos
352ebb5671cSchristos if (!ctx)
353ebb5671cSchristos return -2;
354ebb5671cSchristos
355ebb5671cSchristos if (!mac || !len) {
356ebb5671cSchristos crypto_hash_deinit(ctx);
357ebb5671cSchristos return 0;
358ebb5671cSchristos }
359ebb5671cSchristos
360ebb5671cSchristos if (ctx->failed) {
361ebb5671cSchristos crypto_hash_deinit(ctx);
362ebb5671cSchristos return -2;
363ebb5671cSchristos }
364ebb5671cSchristos
365ebb5671cSchristos if (*len < ctx->mac_len) {
366ebb5671cSchristos crypto_hash_deinit(ctx);
367ebb5671cSchristos *len = ctx->mac_len;
368ebb5671cSchristos return -1;
369ebb5671cSchristos }
370ebb5671cSchristos *len = ctx->mac_len;
371ebb5671cSchristos
372ebb5671cSchristos res = recv(ctx->t, mac, ctx->mac_len, 0);
373ebb5671cSchristos if (res < 0) {
374ebb5671cSchristos wpa_printf(MSG_ERROR,
375ebb5671cSchristos "%s: recv on AF_ALG socket failed: %s",
376ebb5671cSchristos __func__, strerror(errno));
377ebb5671cSchristos crypto_hash_deinit(ctx);
378ebb5671cSchristos return -2;
379ebb5671cSchristos }
380ebb5671cSchristos if ((size_t) res < ctx->mac_len) {
381ebb5671cSchristos wpa_printf(MSG_ERROR,
382ebb5671cSchristos "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
383ebb5671cSchristos __func__, (int) res, (int) ctx->mac_len);
384ebb5671cSchristos crypto_hash_deinit(ctx);
385ebb5671cSchristos return -2;
386ebb5671cSchristos }
387ebb5671cSchristos
388ebb5671cSchristos crypto_hash_deinit(ctx);
389*0d69f216Schristos
390*0d69f216Schristos if (TEST_FAIL())
391*0d69f216Schristos return -1;
392ebb5671cSchristos return 0;
393ebb5671cSchristos }
394ebb5671cSchristos
395ebb5671cSchristos
396ebb5671cSchristos struct linux_af_alg_skcipher {
397ebb5671cSchristos int s;
398ebb5671cSchristos int t;
399ebb5671cSchristos };
400ebb5671cSchristos
401ebb5671cSchristos
linux_af_alg_skcipher_deinit(struct linux_af_alg_skcipher * skcipher)402ebb5671cSchristos static void linux_af_alg_skcipher_deinit(struct linux_af_alg_skcipher *skcipher)
403ebb5671cSchristos {
404ebb5671cSchristos if (!skcipher)
405ebb5671cSchristos return;
406ebb5671cSchristos if (skcipher->s >= 0)
407ebb5671cSchristos close(skcipher->s);
408ebb5671cSchristos if (skcipher->t >= 0)
409ebb5671cSchristos close(skcipher->t);
410ebb5671cSchristos os_free(skcipher);
411ebb5671cSchristos }
412ebb5671cSchristos
413ebb5671cSchristos
414ebb5671cSchristos static struct linux_af_alg_skcipher *
linux_af_alg_skcipher(const char * alg,const u8 * key,size_t key_len)415ebb5671cSchristos linux_af_alg_skcipher(const char *alg, const u8 *key, size_t key_len)
416ebb5671cSchristos {
417ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
418ebb5671cSchristos
419ebb5671cSchristos skcipher = os_zalloc(sizeof(*skcipher));
420ebb5671cSchristos if (!skcipher)
421ebb5671cSchristos goto fail;
422ebb5671cSchristos skcipher->t = -1;
423ebb5671cSchristos
424ebb5671cSchristos skcipher->s = linux_af_alg_socket("skcipher", alg);
425ebb5671cSchristos if (skcipher->s < 0)
426ebb5671cSchristos goto fail;
427ebb5671cSchristos
428ebb5671cSchristos if (setsockopt(skcipher->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
429ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
430ebb5671cSchristos __func__, strerror(errno));
431ebb5671cSchristos goto fail;
432ebb5671cSchristos }
433ebb5671cSchristos
434ebb5671cSchristos skcipher->t = accept(skcipher->s, NULL, NULL);
435ebb5671cSchristos if (skcipher->t < 0) {
436ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
437ebb5671cSchristos __func__, strerror(errno));
438ebb5671cSchristos goto fail;
439ebb5671cSchristos }
440ebb5671cSchristos
441ebb5671cSchristos return skcipher;
442ebb5671cSchristos fail:
443ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
444ebb5671cSchristos return NULL;
445ebb5671cSchristos }
446ebb5671cSchristos
447ebb5671cSchristos
linux_af_alg_skcipher_oper(struct linux_af_alg_skcipher * skcipher,int enc,const u8 * in,u8 * out)448ebb5671cSchristos static int linux_af_alg_skcipher_oper(struct linux_af_alg_skcipher *skcipher,
449ebb5671cSchristos int enc, const u8 *in, u8 *out)
450ebb5671cSchristos {
451ebb5671cSchristos char buf[CMSG_SPACE(sizeof(u32))];
452ebb5671cSchristos struct iovec io[1];
453ebb5671cSchristos struct msghdr msg;
454ebb5671cSchristos struct cmsghdr *hdr;
455ebb5671cSchristos ssize_t ret;
456ebb5671cSchristos u32 *op;
457ebb5671cSchristos
458ebb5671cSchristos io[0].iov_base = (void *) in;
459ebb5671cSchristos io[0].iov_len = AES_BLOCK_SIZE;
460ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
461ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
462ebb5671cSchristos msg.msg_control = buf;
463ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32));
464ebb5671cSchristos msg.msg_iov = io;
465ebb5671cSchristos msg.msg_iovlen = 1;
466ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
467ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
468ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
469ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
470ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
471ebb5671cSchristos *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
472ebb5671cSchristos
473ebb5671cSchristos ret = sendmsg(skcipher->t, &msg, 0);
474ebb5671cSchristos if (ret < 0) {
475ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
476ebb5671cSchristos __func__, strerror(errno));
477ebb5671cSchristos return -1;
478ebb5671cSchristos }
479ebb5671cSchristos
480ebb5671cSchristos ret = read(skcipher->t, out, AES_BLOCK_SIZE);
481ebb5671cSchristos if (ret < 0) {
482ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: read failed: %s",
483ebb5671cSchristos __func__, strerror(errno));
484ebb5671cSchristos return -1;
485ebb5671cSchristos }
486ebb5671cSchristos if (ret < AES_BLOCK_SIZE) {
487ebb5671cSchristos wpa_printf(MSG_ERROR,
488ebb5671cSchristos "%s: read did not return full data (%d/%d)",
489ebb5671cSchristos __func__, (int) ret, AES_BLOCK_SIZE);
490ebb5671cSchristos return -1;
491ebb5671cSchristos }
492ebb5671cSchristos
493ebb5671cSchristos return 0;
494ebb5671cSchristos }
495ebb5671cSchristos
496ebb5671cSchristos
aes_encrypt_init(const u8 * key,size_t len)497ebb5671cSchristos void * aes_encrypt_init(const u8 *key, size_t len)
498ebb5671cSchristos {
499ebb5671cSchristos return linux_af_alg_skcipher("ecb(aes)", key, len);
500ebb5671cSchristos }
501ebb5671cSchristos
502ebb5671cSchristos
aes_encrypt(void * ctx,const u8 * plain,u8 * crypt)503ebb5671cSchristos int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
504ebb5671cSchristos {
505ebb5671cSchristos struct linux_af_alg_skcipher *skcipher = ctx;
506ebb5671cSchristos
507ebb5671cSchristos return linux_af_alg_skcipher_oper(skcipher, 1, plain, crypt);
508ebb5671cSchristos }
509ebb5671cSchristos
510ebb5671cSchristos
aes_encrypt_deinit(void * ctx)511ebb5671cSchristos void aes_encrypt_deinit(void *ctx)
512ebb5671cSchristos {
513ebb5671cSchristos linux_af_alg_skcipher_deinit(ctx);
514ebb5671cSchristos }
515ebb5671cSchristos
516ebb5671cSchristos
aes_decrypt_init(const u8 * key,size_t len)517ebb5671cSchristos void * aes_decrypt_init(const u8 *key, size_t len)
518ebb5671cSchristos {
519ebb5671cSchristos return linux_af_alg_skcipher("ecb(aes)", key, len);
520ebb5671cSchristos }
521ebb5671cSchristos
522ebb5671cSchristos
aes_decrypt(void * ctx,const u8 * crypt,u8 * plain)523ebb5671cSchristos int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
524ebb5671cSchristos {
525ebb5671cSchristos struct linux_af_alg_skcipher *skcipher = ctx;
526ebb5671cSchristos
527ebb5671cSchristos return linux_af_alg_skcipher_oper(skcipher, 0, crypt, plain);
528ebb5671cSchristos }
529ebb5671cSchristos
530ebb5671cSchristos
aes_decrypt_deinit(void * ctx)531ebb5671cSchristos void aes_decrypt_deinit(void *ctx)
532ebb5671cSchristos {
533ebb5671cSchristos linux_af_alg_skcipher_deinit(ctx);
534ebb5671cSchristos }
535ebb5671cSchristos
536ebb5671cSchristos
rc4_skip(const u8 * key,size_t keylen,size_t skip,u8 * data,size_t data_len)537ebb5671cSchristos int rc4_skip(const u8 *key, size_t keylen, size_t skip,
538ebb5671cSchristos u8 *data, size_t data_len)
539ebb5671cSchristos {
540ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
541ebb5671cSchristos u8 *skip_buf;
542ebb5671cSchristos char buf[CMSG_SPACE(sizeof(u32))];
543ebb5671cSchristos struct iovec io[2];
544ebb5671cSchristos struct msghdr msg;
545ebb5671cSchristos struct cmsghdr *hdr;
546ebb5671cSchristos ssize_t ret;
547ebb5671cSchristos u32 *op;
548ebb5671cSchristos
549ebb5671cSchristos skip_buf = os_zalloc(skip + 1);
550ebb5671cSchristos if (!skip_buf)
551ebb5671cSchristos return -1;
552ebb5671cSchristos skcipher = linux_af_alg_skcipher("ecb(arc4)", key, keylen);
553ebb5671cSchristos if (!skcipher) {
554ebb5671cSchristos os_free(skip_buf);
555ebb5671cSchristos return -1;
556ebb5671cSchristos }
557ebb5671cSchristos
558ebb5671cSchristos io[0].iov_base = skip_buf;
559ebb5671cSchristos io[0].iov_len = skip;
560ebb5671cSchristos io[1].iov_base = data;
561ebb5671cSchristos io[1].iov_len = data_len;
562ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
563ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
564ebb5671cSchristos msg.msg_control = buf;
565ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32));
566ebb5671cSchristos msg.msg_iov = io;
567ebb5671cSchristos msg.msg_iovlen = 2;
568ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
569ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
570ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
571ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
572ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
573ebb5671cSchristos *op = ALG_OP_ENCRYPT;
574ebb5671cSchristos
575ebb5671cSchristos ret = sendmsg(skcipher->t, &msg, 0);
576ebb5671cSchristos if (ret < 0) {
577ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
578ebb5671cSchristos __func__, strerror(errno));
579ebb5671cSchristos os_free(skip_buf);
580ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
581ebb5671cSchristos return -1;
582ebb5671cSchristos }
583ebb5671cSchristos os_free(skip_buf);
584ebb5671cSchristos
585ebb5671cSchristos msg.msg_control = NULL;
586ebb5671cSchristos msg.msg_controllen = 0;
587ebb5671cSchristos ret = recvmsg(skcipher->t, &msg, 0);
588ebb5671cSchristos if (ret < 0) {
589ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
590ebb5671cSchristos __func__, strerror(errno));
591ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
592ebb5671cSchristos return -1;
593ebb5671cSchristos }
594ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
595ebb5671cSchristos
596ebb5671cSchristos if ((size_t) ret < skip + data_len) {
597ebb5671cSchristos wpa_printf(MSG_ERROR,
598ebb5671cSchristos "%s: recvmsg did not return full data (%d/%d)",
599ebb5671cSchristos __func__, (int) ret, (int) (skip + data_len));
600ebb5671cSchristos return -1;
601ebb5671cSchristos }
602ebb5671cSchristos
603ebb5671cSchristos return 0;
604ebb5671cSchristos }
605ebb5671cSchristos
606ebb5671cSchristos
des_encrypt(const u8 * clear,const u8 * key,u8 * cypher)607ebb5671cSchristos int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
608ebb5671cSchristos {
609ebb5671cSchristos u8 pkey[8], next, tmp;
610ebb5671cSchristos int i;
611ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
612ebb5671cSchristos char buf[CMSG_SPACE(sizeof(u32))];
613ebb5671cSchristos struct iovec io[1];
614ebb5671cSchristos struct msghdr msg;
615ebb5671cSchristos struct cmsghdr *hdr;
616ebb5671cSchristos ssize_t ret;
617ebb5671cSchristos u32 *op;
618ebb5671cSchristos int res = -1;
619ebb5671cSchristos
620ebb5671cSchristos /* Add parity bits to the key */
621ebb5671cSchristos next = 0;
622ebb5671cSchristos for (i = 0; i < 7; i++) {
623ebb5671cSchristos tmp = key[i];
624ebb5671cSchristos pkey[i] = (tmp >> i) | next | 1;
625ebb5671cSchristos next = tmp << (7 - i);
626ebb5671cSchristos }
627ebb5671cSchristos pkey[i] = next | 1;
628ebb5671cSchristos
629ebb5671cSchristos skcipher = linux_af_alg_skcipher("ecb(des)", pkey, sizeof(pkey));
630ebb5671cSchristos if (!skcipher)
631ebb5671cSchristos goto fail;
632ebb5671cSchristos
633ebb5671cSchristos io[0].iov_base = (void *) clear;
634ebb5671cSchristos io[0].iov_len = 8;
635ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
636ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
637ebb5671cSchristos msg.msg_control = buf;
638ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32));
639ebb5671cSchristos msg.msg_iov = io;
640ebb5671cSchristos msg.msg_iovlen = 1;
641ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
642ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
643ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
644ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
645ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
646ebb5671cSchristos *op = ALG_OP_ENCRYPT;
647ebb5671cSchristos
648ebb5671cSchristos ret = sendmsg(skcipher->t, &msg, 0);
649ebb5671cSchristos if (ret < 0) {
650ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
651ebb5671cSchristos __func__, strerror(errno));
652ebb5671cSchristos goto fail;
653ebb5671cSchristos }
654ebb5671cSchristos
655ebb5671cSchristos ret = read(skcipher->t, cypher, 8);
656ebb5671cSchristos if (ret < 0) {
657ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: read failed: %s",
658ebb5671cSchristos __func__, strerror(errno));
659ebb5671cSchristos goto fail;
660ebb5671cSchristos }
661ebb5671cSchristos if (ret < 8) {
662ebb5671cSchristos wpa_printf(MSG_ERROR,
663ebb5671cSchristos "%s: read did not return full data (%d/8)",
664ebb5671cSchristos __func__, (int) ret);
665ebb5671cSchristos goto fail;
666ebb5671cSchristos }
667ebb5671cSchristos
668ebb5671cSchristos res = 0;
669ebb5671cSchristos fail:
670ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
671ebb5671cSchristos return res;
672ebb5671cSchristos }
673ebb5671cSchristos
674ebb5671cSchristos
aes_128_cbc_oper(const u8 * key,int enc,const u8 * iv,u8 * data,size_t data_len)675ebb5671cSchristos static int aes_128_cbc_oper(const u8 *key, int enc, const u8 *iv,
676ebb5671cSchristos u8 *data, size_t data_len)
677ebb5671cSchristos {
678ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
679ebb5671cSchristos char buf[100];
680ebb5671cSchristos struct iovec io[1];
681ebb5671cSchristos struct msghdr msg;
682ebb5671cSchristos struct cmsghdr *hdr;
683ebb5671cSchristos ssize_t ret;
684ebb5671cSchristos u32 *op;
685ebb5671cSchristos struct af_alg_iv *alg_iv;
686ebb5671cSchristos size_t iv_len = AES_BLOCK_SIZE;
687ebb5671cSchristos
688ebb5671cSchristos skcipher = linux_af_alg_skcipher("cbc(aes)", key, 16);
689ebb5671cSchristos if (!skcipher)
690ebb5671cSchristos return -1;
691ebb5671cSchristos
692ebb5671cSchristos io[0].iov_base = (void *) data;
693ebb5671cSchristos io[0].iov_len = data_len;
694ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
695ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
696ebb5671cSchristos msg.msg_control = buf;
697ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
698ebb5671cSchristos CMSG_SPACE(sizeof(*alg_iv) + iv_len);
699ebb5671cSchristos msg.msg_iov = io;
700ebb5671cSchristos msg.msg_iovlen = 1;
701ebb5671cSchristos
702ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
703ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
704ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
705ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
706ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
707ebb5671cSchristos *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
708ebb5671cSchristos
709ebb5671cSchristos hdr = CMSG_NXTHDR(&msg, hdr);
710ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
711ebb5671cSchristos hdr->cmsg_type = ALG_SET_IV;
712ebb5671cSchristos hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
713ebb5671cSchristos alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
714ebb5671cSchristos alg_iv->ivlen = iv_len;
715ebb5671cSchristos os_memcpy(alg_iv->iv, iv, iv_len);
716ebb5671cSchristos
717ebb5671cSchristos ret = sendmsg(skcipher->t, &msg, 0);
718ebb5671cSchristos if (ret < 0) {
719ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
720ebb5671cSchristos __func__, strerror(errno));
721ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
722ebb5671cSchristos return -1;
723ebb5671cSchristos }
724ebb5671cSchristos
725ebb5671cSchristos ret = recvmsg(skcipher->t, &msg, 0);
726ebb5671cSchristos if (ret < 0) {
727ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
728ebb5671cSchristos __func__, strerror(errno));
729ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
730ebb5671cSchristos return -1;
731ebb5671cSchristos }
732ebb5671cSchristos if ((size_t) ret < data_len) {
733ebb5671cSchristos wpa_printf(MSG_ERROR,
734ebb5671cSchristos "%s: recvmsg not return full data (%d/%d)",
735ebb5671cSchristos __func__, (int) ret, (int) data_len);
736ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
737ebb5671cSchristos return -1;
738ebb5671cSchristos }
739ebb5671cSchristos
740ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
741ebb5671cSchristos return 0;
742ebb5671cSchristos }
743ebb5671cSchristos
744ebb5671cSchristos
aes_128_cbc_encrypt(const u8 * key,const u8 * iv,u8 * data,size_t data_len)745ebb5671cSchristos int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
746ebb5671cSchristos {
747ebb5671cSchristos return aes_128_cbc_oper(key, 1, iv, data, data_len);
748ebb5671cSchristos }
749ebb5671cSchristos
750ebb5671cSchristos
aes_128_cbc_decrypt(const u8 * key,const u8 * iv,u8 * data,size_t data_len)751ebb5671cSchristos int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
752ebb5671cSchristos {
753ebb5671cSchristos return aes_128_cbc_oper(key, 0, iv, data, data_len);
754ebb5671cSchristos }
755ebb5671cSchristos
756ebb5671cSchristos
omac1_aes_vector(const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)757ebb5671cSchristos int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
758ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
759ebb5671cSchristos {
760ebb5671cSchristos return linux_af_alg_hash_vector("cmac(aes)", key, key_len, num_elem,
761ebb5671cSchristos addr, len, mac, AES_BLOCK_SIZE);
762ebb5671cSchristos }
763ebb5671cSchristos
764ebb5671cSchristos
omac1_aes_128_vector(const u8 * key,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)765ebb5671cSchristos int omac1_aes_128_vector(const u8 *key, size_t num_elem,
766ebb5671cSchristos const u8 *addr[], const size_t *len, u8 *mac)
767ebb5671cSchristos {
768ebb5671cSchristos return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
769ebb5671cSchristos }
770ebb5671cSchristos
771ebb5671cSchristos
omac1_aes_128(const u8 * key,const u8 * data,size_t data_len,u8 * mac)772ebb5671cSchristos int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
773ebb5671cSchristos {
774ebb5671cSchristos return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
775ebb5671cSchristos }
776ebb5671cSchristos
777ebb5671cSchristos
omac1_aes_256(const u8 * key,const u8 * data,size_t data_len,u8 * mac)778ebb5671cSchristos int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
779ebb5671cSchristos {
780ebb5671cSchristos return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
781ebb5671cSchristos }
782ebb5671cSchristos
783ebb5671cSchristos
aes_unwrap(const u8 * kek,size_t kek_len,int n,const u8 * cipher,u8 * plain)784ebb5671cSchristos int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
785ebb5671cSchristos u8 *plain)
786ebb5671cSchristos {
787ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
788ebb5671cSchristos char buf[100];
789ebb5671cSchristos struct iovec io[1];
790ebb5671cSchristos struct msghdr msg;
791ebb5671cSchristos struct cmsghdr *hdr;
792ebb5671cSchristos ssize_t ret;
793ebb5671cSchristos u32 *op;
794ebb5671cSchristos struct af_alg_iv *alg_iv;
795ebb5671cSchristos size_t iv_len = 8;
796ebb5671cSchristos
797ebb5671cSchristos skcipher = linux_af_alg_skcipher("kw(aes)", kek, kek_len);
798ebb5671cSchristos if (!skcipher)
799ebb5671cSchristos return -1;
800ebb5671cSchristos
801ebb5671cSchristos io[0].iov_base = (void *) (cipher + iv_len);
802ebb5671cSchristos io[0].iov_len = n * 8;
803ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
804ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
805ebb5671cSchristos msg.msg_control = buf;
806ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
807ebb5671cSchristos CMSG_SPACE(sizeof(*alg_iv) + iv_len);
808ebb5671cSchristos msg.msg_iov = io;
809ebb5671cSchristos msg.msg_iovlen = 1;
810ebb5671cSchristos
811ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
812ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
813ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
814ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
815ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
816ebb5671cSchristos *op = ALG_OP_DECRYPT;
817ebb5671cSchristos
818ebb5671cSchristos hdr = CMSG_NXTHDR(&msg, hdr);
819ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
820ebb5671cSchristos hdr->cmsg_type = ALG_SET_IV;
821ebb5671cSchristos hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
822ebb5671cSchristos alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
823ebb5671cSchristos alg_iv->ivlen = iv_len;
824ebb5671cSchristos os_memcpy(alg_iv->iv, cipher, iv_len);
825ebb5671cSchristos
826ebb5671cSchristos ret = sendmsg(skcipher->t, &msg, 0);
827ebb5671cSchristos if (ret < 0) {
828ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
829ebb5671cSchristos __func__, strerror(errno));
830ebb5671cSchristos return -1;
831ebb5671cSchristos }
832ebb5671cSchristos
833ebb5671cSchristos ret = read(skcipher->t, plain, n * 8);
834ebb5671cSchristos if (ret < 0) {
835ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: read failed: %s",
836ebb5671cSchristos __func__, strerror(errno));
837ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
838ebb5671cSchristos return -1;
839ebb5671cSchristos }
840ebb5671cSchristos if (ret < n * 8) {
841ebb5671cSchristos wpa_printf(MSG_ERROR,
842ebb5671cSchristos "%s: read not return full data (%d/%d)",
843ebb5671cSchristos __func__, (int) ret, n * 8);
844ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
845ebb5671cSchristos return -1;
846ebb5671cSchristos }
847ebb5671cSchristos
848ebb5671cSchristos linux_af_alg_skcipher_deinit(skcipher);
849ebb5671cSchristos return 0;
850ebb5671cSchristos }
851ebb5671cSchristos
852ebb5671cSchristos
853ebb5671cSchristos struct crypto_cipher {
854ebb5671cSchristos struct linux_af_alg_skcipher *skcipher;
855ebb5671cSchristos };
856ebb5671cSchristos
857ebb5671cSchristos
crypto_cipher_init(enum crypto_cipher_alg alg,const u8 * iv,const u8 * key,size_t key_len)858ebb5671cSchristos struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
859ebb5671cSchristos const u8 *iv, const u8 *key,
860ebb5671cSchristos size_t key_len)
861ebb5671cSchristos {
862ebb5671cSchristos struct crypto_cipher *ctx;
863ebb5671cSchristos const char *name;
864ebb5671cSchristos struct af_alg_iv *alg_iv;
865ebb5671cSchristos size_t iv_len = 0;
866ebb5671cSchristos char buf[100];
867ebb5671cSchristos struct msghdr msg;
868ebb5671cSchristos struct cmsghdr *hdr;
869ebb5671cSchristos ssize_t ret;
870ebb5671cSchristos
871ebb5671cSchristos ctx = os_zalloc(sizeof(*ctx));
872ebb5671cSchristos if (!ctx)
873ebb5671cSchristos return NULL;
874ebb5671cSchristos
875ebb5671cSchristos switch (alg) {
876ebb5671cSchristos case CRYPTO_CIPHER_ALG_RC4:
877ebb5671cSchristos name = "ecb(arc4)";
878ebb5671cSchristos break;
879ebb5671cSchristos case CRYPTO_CIPHER_ALG_AES:
880ebb5671cSchristos name = "cbc(aes)";
881ebb5671cSchristos iv_len = AES_BLOCK_SIZE;
882ebb5671cSchristos break;
883ebb5671cSchristos case CRYPTO_CIPHER_ALG_3DES:
884ebb5671cSchristos name = "cbc(des3_ede)";
885ebb5671cSchristos iv_len = 8;
886ebb5671cSchristos break;
887ebb5671cSchristos case CRYPTO_CIPHER_ALG_DES:
888ebb5671cSchristos name = "cbc(des)";
889ebb5671cSchristos iv_len = 8;
890ebb5671cSchristos break;
891ebb5671cSchristos default:
892ebb5671cSchristos os_free(ctx);
893ebb5671cSchristos return NULL;
894ebb5671cSchristos }
895ebb5671cSchristos
896ebb5671cSchristos ctx->skcipher = linux_af_alg_skcipher(name, key, key_len);
897ebb5671cSchristos if (!ctx->skcipher) {
898ebb5671cSchristos os_free(ctx);
899ebb5671cSchristos return NULL;
900ebb5671cSchristos }
901ebb5671cSchristos
902ebb5671cSchristos if (iv && iv_len) {
903ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
904ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
905ebb5671cSchristos msg.msg_control = buf;
906ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
907ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
908ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
909ebb5671cSchristos hdr->cmsg_type = ALG_SET_IV;
910ebb5671cSchristos hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
911ebb5671cSchristos alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
912ebb5671cSchristos alg_iv->ivlen = iv_len;
913ebb5671cSchristos os_memcpy(alg_iv->iv, iv, iv_len);
914ebb5671cSchristos
915ebb5671cSchristos ret = sendmsg(ctx->skcipher->t, &msg, 0);
916ebb5671cSchristos if (ret < 0) {
917ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
918ebb5671cSchristos __func__, strerror(errno));
919ebb5671cSchristos linux_af_alg_skcipher_deinit(ctx->skcipher);
920ebb5671cSchristos os_free(ctx);
921ebb5671cSchristos return NULL;
922ebb5671cSchristos }
923ebb5671cSchristos }
924ebb5671cSchristos
925ebb5671cSchristos return ctx;
926ebb5671cSchristos }
927ebb5671cSchristos
928ebb5671cSchristos
crypto_cipher_oper(struct crypto_cipher * ctx,u32 type,const u8 * in,u8 * out,size_t len)929ebb5671cSchristos static int crypto_cipher_oper(struct crypto_cipher *ctx, u32 type, const u8 *in,
930ebb5671cSchristos u8 *out, size_t len)
931ebb5671cSchristos {
932ebb5671cSchristos char buf[CMSG_SPACE(sizeof(u32))];
933ebb5671cSchristos struct iovec io[1];
934ebb5671cSchristos struct msghdr msg;
935ebb5671cSchristos struct cmsghdr *hdr;
936ebb5671cSchristos ssize_t ret;
937ebb5671cSchristos u32 *op;
938ebb5671cSchristos
939ebb5671cSchristos io[0].iov_base = (void *) in;
940ebb5671cSchristos io[0].iov_len = len;
941ebb5671cSchristos os_memset(&msg, 0, sizeof(msg));
942ebb5671cSchristos os_memset(buf, 0, sizeof(buf));
943ebb5671cSchristos msg.msg_control = buf;
944ebb5671cSchristos msg.msg_controllen = CMSG_SPACE(sizeof(u32));
945ebb5671cSchristos msg.msg_iov = io;
946ebb5671cSchristos msg.msg_iovlen = 1;
947ebb5671cSchristos hdr = CMSG_FIRSTHDR(&msg);
948ebb5671cSchristos hdr->cmsg_level = SOL_ALG;
949ebb5671cSchristos hdr->cmsg_type = ALG_SET_OP;
950ebb5671cSchristos hdr->cmsg_len = CMSG_LEN(sizeof(u32));
951ebb5671cSchristos op = (u32 *) CMSG_DATA(hdr);
952ebb5671cSchristos *op = type;
953ebb5671cSchristos
954ebb5671cSchristos ret = sendmsg(ctx->skcipher->t, &msg, 0);
955ebb5671cSchristos if (ret < 0) {
956ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
957ebb5671cSchristos __func__, strerror(errno));
958ebb5671cSchristos return -1;
959ebb5671cSchristos }
960ebb5671cSchristos
961ebb5671cSchristos ret = read(ctx->skcipher->t, out, len);
962ebb5671cSchristos if (ret < 0) {
963ebb5671cSchristos wpa_printf(MSG_ERROR, "%s: read failed: %s",
964ebb5671cSchristos __func__, strerror(errno));
965ebb5671cSchristos return -1;
966ebb5671cSchristos }
967ebb5671cSchristos if (ret < (ssize_t) len) {
968ebb5671cSchristos wpa_printf(MSG_ERROR,
969ebb5671cSchristos "%s: read did not return full data (%d/%d)",
970ebb5671cSchristos __func__, (int) ret, (int) len);
971ebb5671cSchristos return -1;
972ebb5671cSchristos }
973ebb5671cSchristos
974ebb5671cSchristos return 0;
975ebb5671cSchristos }
976ebb5671cSchristos
977ebb5671cSchristos
crypto_cipher_encrypt(struct crypto_cipher * ctx,const u8 * plain,u8 * crypt,size_t len)978ebb5671cSchristos int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
979ebb5671cSchristos u8 *crypt, size_t len)
980ebb5671cSchristos {
981ebb5671cSchristos return crypto_cipher_oper(ctx, ALG_OP_ENCRYPT, plain, crypt, len);
982ebb5671cSchristos }
983ebb5671cSchristos
984ebb5671cSchristos
crypto_cipher_decrypt(struct crypto_cipher * ctx,const u8 * crypt,u8 * plain,size_t len)985ebb5671cSchristos int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
986ebb5671cSchristos u8 *plain, size_t len)
987ebb5671cSchristos {
988ebb5671cSchristos return crypto_cipher_oper(ctx, ALG_OP_DECRYPT, crypt, plain, len);
989ebb5671cSchristos }
990ebb5671cSchristos
991ebb5671cSchristos
crypto_cipher_deinit(struct crypto_cipher * ctx)992ebb5671cSchristos void crypto_cipher_deinit(struct crypto_cipher *ctx)
993ebb5671cSchristos {
994ebb5671cSchristos if (ctx) {
995ebb5671cSchristos linux_af_alg_skcipher_deinit(ctx->skcipher);
996ebb5671cSchristos os_free(ctx);
997ebb5671cSchristos }
998ebb5671cSchristos }
999ebb5671cSchristos
1000ebb5671cSchristos
crypto_global_init(void)1001ebb5671cSchristos int crypto_global_init(void)
1002ebb5671cSchristos {
1003ebb5671cSchristos return 0;
1004ebb5671cSchristos }
1005ebb5671cSchristos
1006ebb5671cSchristos
crypto_global_deinit(void)1007ebb5671cSchristos void crypto_global_deinit(void)
1008ebb5671cSchristos {
1009ebb5671cSchristos }
1010