185732ac8SCy Schubert /* 285732ac8SCy Schubert * Crypto wrapper for Linux kernel AF_ALG 385732ac8SCy Schubert * Copyright (c) 2017, Jouni Malinen <j@w1.fi> 485732ac8SCy Schubert * 585732ac8SCy Schubert * This software may be distributed under the terms of the BSD license. 685732ac8SCy Schubert * See README for more details. 785732ac8SCy Schubert */ 885732ac8SCy Schubert 985732ac8SCy Schubert #include "includes.h" 1085732ac8SCy Schubert #include <linux/if_alg.h> 1185732ac8SCy Schubert 1285732ac8SCy Schubert #include "common.h" 1385732ac8SCy Schubert #include "crypto.h" 1485732ac8SCy Schubert #include "md5.h" 1585732ac8SCy Schubert #include "sha1.h" 1685732ac8SCy Schubert #include "sha256.h" 1785732ac8SCy Schubert #include "sha384.h" 1885732ac8SCy Schubert #include "aes.h" 1985732ac8SCy Schubert 2085732ac8SCy Schubert 2185732ac8SCy Schubert #ifndef SOL_ALG 2285732ac8SCy Schubert #define SOL_ALG 279 2385732ac8SCy Schubert #endif /* SOL_ALG */ 2485732ac8SCy Schubert 2585732ac8SCy Schubert 2685732ac8SCy Schubert static int linux_af_alg_socket(const char *type, const char *name) 2785732ac8SCy Schubert { 2885732ac8SCy Schubert struct sockaddr_alg sa; 2985732ac8SCy Schubert int s; 3085732ac8SCy Schubert 3185732ac8SCy Schubert if (TEST_FAIL()) 3285732ac8SCy Schubert return -1; 3385732ac8SCy Schubert 3485732ac8SCy Schubert s = socket(AF_ALG, SOCK_SEQPACKET, 0); 3585732ac8SCy Schubert if (s < 0) { 3685732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: Failed to open AF_ALG socket: %s", 3785732ac8SCy Schubert __func__, strerror(errno)); 3885732ac8SCy Schubert return -1; 3985732ac8SCy Schubert } 4085732ac8SCy Schubert 4185732ac8SCy Schubert os_memset(&sa, 0, sizeof(sa)); 4285732ac8SCy Schubert sa.salg_family = AF_ALG; 4385732ac8SCy Schubert os_strlcpy((char *) sa.salg_type, type, sizeof(sa.salg_type)); 4485732ac8SCy Schubert os_strlcpy((char *) sa.salg_name, name, sizeof(sa.salg_type)); 4585732ac8SCy Schubert if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 4685732ac8SCy Schubert wpa_printf(MSG_ERROR, 4785732ac8SCy Schubert "%s: Failed to bind AF_ALG socket(%s,%s): %s", 4885732ac8SCy Schubert __func__, type, name, strerror(errno)); 4985732ac8SCy Schubert close(s); 5085732ac8SCy Schubert return -1; 5185732ac8SCy Schubert } 5285732ac8SCy Schubert 5385732ac8SCy Schubert return s; 5485732ac8SCy Schubert } 5585732ac8SCy Schubert 5685732ac8SCy Schubert 5785732ac8SCy Schubert static int linux_af_alg_hash_vector(const char *alg, const u8 *key, 5885732ac8SCy Schubert size_t key_len, size_t num_elem, 5985732ac8SCy Schubert const u8 *addr[], const size_t *len, 6085732ac8SCy Schubert u8 *mac, size_t mac_len) 6185732ac8SCy Schubert { 6285732ac8SCy Schubert int s, t; 6385732ac8SCy Schubert size_t i; 6485732ac8SCy Schubert ssize_t res; 6585732ac8SCy Schubert int ret = -1; 6685732ac8SCy Schubert 6785732ac8SCy Schubert s = linux_af_alg_socket("hash", alg); 6885732ac8SCy Schubert if (s < 0) 6985732ac8SCy Schubert return -1; 7085732ac8SCy Schubert 7185732ac8SCy Schubert if (key && setsockopt(s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) { 7285732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s", 7385732ac8SCy Schubert __func__, strerror(errno)); 7485732ac8SCy Schubert close(s); 7585732ac8SCy Schubert return -1; 7685732ac8SCy Schubert } 7785732ac8SCy Schubert 7885732ac8SCy Schubert t = accept(s, NULL, NULL); 7985732ac8SCy Schubert if (t < 0) { 8085732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s", 8185732ac8SCy Schubert __func__, strerror(errno)); 8285732ac8SCy Schubert close(s); 8385732ac8SCy Schubert return -1; 8485732ac8SCy Schubert } 8585732ac8SCy Schubert 8685732ac8SCy Schubert for (i = 0; i < num_elem; i++) { 8785732ac8SCy Schubert res = send(t, addr[i], len[i], i + 1 < num_elem ? MSG_MORE : 0); 8885732ac8SCy Schubert if (res < 0) { 8985732ac8SCy Schubert wpa_printf(MSG_ERROR, 9085732ac8SCy Schubert "%s: send on AF_ALG socket failed: %s", 9185732ac8SCy Schubert __func__, strerror(errno)); 9285732ac8SCy Schubert goto fail; 9385732ac8SCy Schubert } 9485732ac8SCy Schubert if ((size_t) res < len[i]) { 9585732ac8SCy Schubert wpa_printf(MSG_ERROR, 9685732ac8SCy Schubert "%s: send on AF_ALG socket did not accept full buffer (%d/%d)", 9785732ac8SCy Schubert __func__, (int) res, (int) len[i]); 9885732ac8SCy Schubert goto fail; 9985732ac8SCy Schubert } 10085732ac8SCy Schubert } 10185732ac8SCy Schubert 10285732ac8SCy Schubert res = recv(t, mac, mac_len, 0); 10385732ac8SCy Schubert if (res < 0) { 10485732ac8SCy Schubert wpa_printf(MSG_ERROR, 10585732ac8SCy Schubert "%s: recv on AF_ALG socket failed: %s", 10685732ac8SCy Schubert __func__, strerror(errno)); 10785732ac8SCy Schubert goto fail; 10885732ac8SCy Schubert } 10985732ac8SCy Schubert if ((size_t) res < mac_len) { 11085732ac8SCy Schubert wpa_printf(MSG_ERROR, 11185732ac8SCy Schubert "%s: recv on AF_ALG socket did not return full buffer (%d/%d)", 11285732ac8SCy Schubert __func__, (int) res, (int) mac_len); 11385732ac8SCy Schubert goto fail; 11485732ac8SCy Schubert } 11585732ac8SCy Schubert 11685732ac8SCy Schubert ret = 0; 11785732ac8SCy Schubert fail: 11885732ac8SCy Schubert close(t); 11985732ac8SCy Schubert close(s); 12085732ac8SCy Schubert 12185732ac8SCy Schubert return ret; 12285732ac8SCy Schubert } 12385732ac8SCy Schubert 12485732ac8SCy Schubert 12585732ac8SCy Schubert int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 12685732ac8SCy Schubert { 12785732ac8SCy Schubert return linux_af_alg_hash_vector("md4", NULL, 0, num_elem, addr, len, 12885732ac8SCy Schubert mac, 16); 12985732ac8SCy Schubert } 13085732ac8SCy Schubert 13185732ac8SCy Schubert 13285732ac8SCy Schubert int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 13385732ac8SCy Schubert { 13485732ac8SCy Schubert return linux_af_alg_hash_vector("md5", NULL, 0, num_elem, addr, len, 13585732ac8SCy Schubert mac, MD5_MAC_LEN); 13685732ac8SCy Schubert } 13785732ac8SCy Schubert 13885732ac8SCy Schubert 13985732ac8SCy Schubert int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, 14085732ac8SCy Schubert u8 *mac) 14185732ac8SCy Schubert { 14285732ac8SCy Schubert return linux_af_alg_hash_vector("sha1", NULL, 0, num_elem, addr, len, 14385732ac8SCy Schubert mac, SHA1_MAC_LEN); 14485732ac8SCy Schubert } 14585732ac8SCy Schubert 14685732ac8SCy Schubert 14785732ac8SCy Schubert int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, 14885732ac8SCy Schubert u8 *mac) 14985732ac8SCy Schubert { 15085732ac8SCy Schubert return linux_af_alg_hash_vector("sha256", NULL, 0, num_elem, addr, len, 15185732ac8SCy Schubert mac, SHA256_MAC_LEN); 15285732ac8SCy Schubert } 15385732ac8SCy Schubert 15485732ac8SCy Schubert 15585732ac8SCy Schubert int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, 15685732ac8SCy Schubert u8 *mac) 15785732ac8SCy Schubert { 15885732ac8SCy Schubert return linux_af_alg_hash_vector("sha384", NULL, 0, num_elem, addr, len, 15985732ac8SCy Schubert mac, SHA384_MAC_LEN); 16085732ac8SCy Schubert } 16185732ac8SCy Schubert 16285732ac8SCy Schubert 16385732ac8SCy Schubert int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, 16485732ac8SCy Schubert u8 *mac) 16585732ac8SCy Schubert { 16685732ac8SCy Schubert return linux_af_alg_hash_vector("sha512", NULL, 0, num_elem, addr, len, 16785732ac8SCy Schubert mac, 64); 16885732ac8SCy Schubert } 16985732ac8SCy Schubert 17085732ac8SCy Schubert 17185732ac8SCy Schubert int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, 17285732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 17385732ac8SCy Schubert { 17485732ac8SCy Schubert return linux_af_alg_hash_vector("hmac(md5)", key, key_len, num_elem, 17585732ac8SCy Schubert addr, len, mac, 16); 17685732ac8SCy Schubert } 17785732ac8SCy Schubert 17885732ac8SCy Schubert 17985732ac8SCy Schubert int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, 18085732ac8SCy Schubert u8 *mac) 18185732ac8SCy Schubert { 18285732ac8SCy Schubert return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); 18385732ac8SCy Schubert } 18485732ac8SCy Schubert 18585732ac8SCy Schubert 18685732ac8SCy Schubert int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, 18785732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 18885732ac8SCy Schubert { 18985732ac8SCy Schubert return linux_af_alg_hash_vector("hmac(sha1)", key, key_len, num_elem, 19085732ac8SCy Schubert addr, len, mac, SHA1_MAC_LEN); 19185732ac8SCy Schubert } 19285732ac8SCy Schubert 19385732ac8SCy Schubert 19485732ac8SCy Schubert int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, 19585732ac8SCy Schubert u8 *mac) 19685732ac8SCy Schubert { 19785732ac8SCy Schubert return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); 19885732ac8SCy Schubert } 19985732ac8SCy Schubert 20085732ac8SCy Schubert 20185732ac8SCy Schubert int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, 20285732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 20385732ac8SCy Schubert { 20485732ac8SCy Schubert return linux_af_alg_hash_vector("hmac(sha256)", key, key_len, num_elem, 20585732ac8SCy Schubert addr, len, mac, SHA256_MAC_LEN); 20685732ac8SCy Schubert } 20785732ac8SCy Schubert 20885732ac8SCy Schubert 20985732ac8SCy Schubert int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, 21085732ac8SCy Schubert size_t data_len, u8 *mac) 21185732ac8SCy Schubert { 21285732ac8SCy Schubert return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); 21385732ac8SCy Schubert } 21485732ac8SCy Schubert 21585732ac8SCy Schubert 21685732ac8SCy Schubert int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, 21785732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 21885732ac8SCy Schubert { 21985732ac8SCy Schubert return linux_af_alg_hash_vector("hmac(sha384)", key, key_len, num_elem, 22085732ac8SCy Schubert addr, len, mac, SHA384_MAC_LEN); 22185732ac8SCy Schubert } 22285732ac8SCy Schubert 22385732ac8SCy Schubert 22485732ac8SCy Schubert int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, 22585732ac8SCy Schubert size_t data_len, u8 *mac) 22685732ac8SCy Schubert { 22785732ac8SCy Schubert return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac); 22885732ac8SCy Schubert } 22985732ac8SCy Schubert 23085732ac8SCy Schubert 23185732ac8SCy Schubert struct crypto_hash { 23285732ac8SCy Schubert int s; 23385732ac8SCy Schubert int t; 23485732ac8SCy Schubert size_t mac_len; 23585732ac8SCy Schubert int failed; 23685732ac8SCy Schubert }; 23785732ac8SCy Schubert 23885732ac8SCy Schubert 23985732ac8SCy Schubert struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, 24085732ac8SCy Schubert size_t key_len) 24185732ac8SCy Schubert { 24285732ac8SCy Schubert struct crypto_hash *ctx; 24385732ac8SCy Schubert const char *name; 24485732ac8SCy Schubert 24585732ac8SCy Schubert ctx = os_zalloc(sizeof(*ctx)); 24685732ac8SCy Schubert if (!ctx) 24785732ac8SCy Schubert return NULL; 24885732ac8SCy Schubert 24985732ac8SCy Schubert switch (alg) { 25085732ac8SCy Schubert case CRYPTO_HASH_ALG_MD5: 25185732ac8SCy Schubert name = "md5"; 25285732ac8SCy Schubert ctx->mac_len = MD5_MAC_LEN; 25385732ac8SCy Schubert break; 25485732ac8SCy Schubert case CRYPTO_HASH_ALG_SHA1: 25585732ac8SCy Schubert name = "sha1"; 25685732ac8SCy Schubert ctx->mac_len = SHA1_MAC_LEN; 25785732ac8SCy Schubert break; 25885732ac8SCy Schubert case CRYPTO_HASH_ALG_HMAC_MD5: 25985732ac8SCy Schubert name = "hmac(md5)"; 26085732ac8SCy Schubert ctx->mac_len = MD5_MAC_LEN; 26185732ac8SCy Schubert break; 26285732ac8SCy Schubert case CRYPTO_HASH_ALG_HMAC_SHA1: 26385732ac8SCy Schubert name = "hmac(sha1)"; 26485732ac8SCy Schubert ctx->mac_len = SHA1_MAC_LEN; 26585732ac8SCy Schubert break; 26685732ac8SCy Schubert case CRYPTO_HASH_ALG_SHA256: 26785732ac8SCy Schubert name = "sha256"; 26885732ac8SCy Schubert ctx->mac_len = SHA256_MAC_LEN; 26985732ac8SCy Schubert break; 27085732ac8SCy Schubert case CRYPTO_HASH_ALG_HMAC_SHA256: 27185732ac8SCy Schubert name = "hmac(sha256)"; 27285732ac8SCy Schubert ctx->mac_len = SHA256_MAC_LEN; 27385732ac8SCy Schubert break; 27485732ac8SCy Schubert case CRYPTO_HASH_ALG_SHA384: 27585732ac8SCy Schubert name = "sha384"; 27685732ac8SCy Schubert ctx->mac_len = SHA384_MAC_LEN; 27785732ac8SCy Schubert break; 27885732ac8SCy Schubert case CRYPTO_HASH_ALG_SHA512: 27985732ac8SCy Schubert name = "sha512"; 28085732ac8SCy Schubert ctx->mac_len = 64; 28185732ac8SCy Schubert break; 28285732ac8SCy Schubert default: 28385732ac8SCy Schubert os_free(ctx); 28485732ac8SCy Schubert return NULL; 28585732ac8SCy Schubert } 28685732ac8SCy Schubert 28785732ac8SCy Schubert ctx->s = linux_af_alg_socket("hash", name); 28885732ac8SCy Schubert if (ctx->s < 0) { 28985732ac8SCy Schubert os_free(ctx); 29085732ac8SCy Schubert return NULL; 29185732ac8SCy Schubert } 29285732ac8SCy Schubert 29385732ac8SCy Schubert if (key && key_len && 29485732ac8SCy Schubert setsockopt(ctx->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) { 29585732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s", 29685732ac8SCy Schubert __func__, strerror(errno)); 29785732ac8SCy Schubert close(ctx->s); 29885732ac8SCy Schubert os_free(ctx); 29985732ac8SCy Schubert return NULL; 30085732ac8SCy Schubert } 30185732ac8SCy Schubert 30285732ac8SCy Schubert ctx->t = accept(ctx->s, NULL, NULL); 30385732ac8SCy Schubert if (ctx->t < 0) { 30485732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s", 30585732ac8SCy Schubert __func__, strerror(errno)); 30685732ac8SCy Schubert close(ctx->s); 30785732ac8SCy Schubert os_free(ctx); 30885732ac8SCy Schubert return NULL; 30985732ac8SCy Schubert } 31085732ac8SCy Schubert 31185732ac8SCy Schubert return ctx; 31285732ac8SCy Schubert } 31385732ac8SCy Schubert 31485732ac8SCy Schubert 31585732ac8SCy Schubert void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) 31685732ac8SCy Schubert { 31785732ac8SCy Schubert ssize_t res; 31885732ac8SCy Schubert 31985732ac8SCy Schubert if (!ctx) 32085732ac8SCy Schubert return; 32185732ac8SCy Schubert 32285732ac8SCy Schubert res = send(ctx->t, data, len, MSG_MORE); 32385732ac8SCy Schubert if (res < 0) { 32485732ac8SCy Schubert wpa_printf(MSG_ERROR, 32585732ac8SCy Schubert "%s: send on AF_ALG socket failed: %s", 32685732ac8SCy Schubert __func__, strerror(errno)); 32785732ac8SCy Schubert ctx->failed = 1; 32885732ac8SCy Schubert return; 32985732ac8SCy Schubert } 33085732ac8SCy Schubert if ((size_t) res < len) { 33185732ac8SCy Schubert wpa_printf(MSG_ERROR, 33285732ac8SCy Schubert "%s: send on AF_ALG socket did not accept full buffer (%d/%d)", 33385732ac8SCy Schubert __func__, (int) res, (int) len); 33485732ac8SCy Schubert ctx->failed = 1; 33585732ac8SCy Schubert return; 33685732ac8SCy Schubert } 33785732ac8SCy Schubert } 33885732ac8SCy Schubert 33985732ac8SCy Schubert 34085732ac8SCy Schubert static void crypto_hash_deinit(struct crypto_hash *ctx) 34185732ac8SCy Schubert { 34285732ac8SCy Schubert close(ctx->s); 34385732ac8SCy Schubert close(ctx->t); 34485732ac8SCy Schubert os_free(ctx); 34585732ac8SCy Schubert } 34685732ac8SCy Schubert 34785732ac8SCy Schubert 34885732ac8SCy Schubert int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) 34985732ac8SCy Schubert { 35085732ac8SCy Schubert ssize_t res; 35185732ac8SCy Schubert 35285732ac8SCy Schubert if (!ctx) 35385732ac8SCy Schubert return -2; 35485732ac8SCy Schubert 35585732ac8SCy Schubert if (!mac || !len) { 35685732ac8SCy Schubert crypto_hash_deinit(ctx); 35785732ac8SCy Schubert return 0; 35885732ac8SCy Schubert } 35985732ac8SCy Schubert 36085732ac8SCy Schubert if (ctx->failed) { 36185732ac8SCy Schubert crypto_hash_deinit(ctx); 36285732ac8SCy Schubert return -2; 36385732ac8SCy Schubert } 36485732ac8SCy Schubert 36585732ac8SCy Schubert if (*len < ctx->mac_len) { 36685732ac8SCy Schubert crypto_hash_deinit(ctx); 36785732ac8SCy Schubert *len = ctx->mac_len; 36885732ac8SCy Schubert return -1; 36985732ac8SCy Schubert } 37085732ac8SCy Schubert *len = ctx->mac_len; 37185732ac8SCy Schubert 37285732ac8SCy Schubert res = recv(ctx->t, mac, ctx->mac_len, 0); 37385732ac8SCy Schubert if (res < 0) { 37485732ac8SCy Schubert wpa_printf(MSG_ERROR, 37585732ac8SCy Schubert "%s: recv on AF_ALG socket failed: %s", 37685732ac8SCy Schubert __func__, strerror(errno)); 37785732ac8SCy Schubert crypto_hash_deinit(ctx); 37885732ac8SCy Schubert return -2; 37985732ac8SCy Schubert } 38085732ac8SCy Schubert if ((size_t) res < ctx->mac_len) { 38185732ac8SCy Schubert wpa_printf(MSG_ERROR, 38285732ac8SCy Schubert "%s: recv on AF_ALG socket did not return full buffer (%d/%d)", 38385732ac8SCy Schubert __func__, (int) res, (int) ctx->mac_len); 38485732ac8SCy Schubert crypto_hash_deinit(ctx); 38585732ac8SCy Schubert return -2; 38685732ac8SCy Schubert } 38785732ac8SCy Schubert 38885732ac8SCy Schubert crypto_hash_deinit(ctx); 3894bc52338SCy Schubert 3904bc52338SCy Schubert if (TEST_FAIL()) 3914bc52338SCy Schubert return -1; 39285732ac8SCy Schubert return 0; 39385732ac8SCy Schubert } 39485732ac8SCy Schubert 39585732ac8SCy Schubert 39685732ac8SCy Schubert struct linux_af_alg_skcipher { 39785732ac8SCy Schubert int s; 39885732ac8SCy Schubert int t; 39985732ac8SCy Schubert }; 40085732ac8SCy Schubert 40185732ac8SCy Schubert 40285732ac8SCy Schubert static void linux_af_alg_skcipher_deinit(struct linux_af_alg_skcipher *skcipher) 40385732ac8SCy Schubert { 40485732ac8SCy Schubert if (!skcipher) 40585732ac8SCy Schubert return; 40685732ac8SCy Schubert if (skcipher->s >= 0) 40785732ac8SCy Schubert close(skcipher->s); 40885732ac8SCy Schubert if (skcipher->t >= 0) 40985732ac8SCy Schubert close(skcipher->t); 41085732ac8SCy Schubert os_free(skcipher); 41185732ac8SCy Schubert } 41285732ac8SCy Schubert 41385732ac8SCy Schubert 41485732ac8SCy Schubert static struct linux_af_alg_skcipher * 41585732ac8SCy Schubert linux_af_alg_skcipher(const char *alg, const u8 *key, size_t key_len) 41685732ac8SCy Schubert { 41785732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 41885732ac8SCy Schubert 41985732ac8SCy Schubert skcipher = os_zalloc(sizeof(*skcipher)); 42085732ac8SCy Schubert if (!skcipher) 42185732ac8SCy Schubert goto fail; 42285732ac8SCy Schubert skcipher->t = -1; 42385732ac8SCy Schubert 42485732ac8SCy Schubert skcipher->s = linux_af_alg_socket("skcipher", alg); 42585732ac8SCy Schubert if (skcipher->s < 0) 42685732ac8SCy Schubert goto fail; 42785732ac8SCy Schubert 42885732ac8SCy Schubert if (setsockopt(skcipher->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) { 42985732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s", 43085732ac8SCy Schubert __func__, strerror(errno)); 43185732ac8SCy Schubert goto fail; 43285732ac8SCy Schubert } 43385732ac8SCy Schubert 43485732ac8SCy Schubert skcipher->t = accept(skcipher->s, NULL, NULL); 43585732ac8SCy Schubert if (skcipher->t < 0) { 43685732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s", 43785732ac8SCy Schubert __func__, strerror(errno)); 43885732ac8SCy Schubert goto fail; 43985732ac8SCy Schubert } 44085732ac8SCy Schubert 44185732ac8SCy Schubert return skcipher; 44285732ac8SCy Schubert fail: 44385732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 44485732ac8SCy Schubert return NULL; 44585732ac8SCy Schubert } 44685732ac8SCy Schubert 44785732ac8SCy Schubert 44885732ac8SCy Schubert static int linux_af_alg_skcipher_oper(struct linux_af_alg_skcipher *skcipher, 44985732ac8SCy Schubert int enc, const u8 *in, u8 *out) 45085732ac8SCy Schubert { 45185732ac8SCy Schubert char buf[CMSG_SPACE(sizeof(u32))]; 45285732ac8SCy Schubert struct iovec io[1]; 45385732ac8SCy Schubert struct msghdr msg; 45485732ac8SCy Schubert struct cmsghdr *hdr; 45585732ac8SCy Schubert ssize_t ret; 45685732ac8SCy Schubert u32 *op; 45785732ac8SCy Schubert 45885732ac8SCy Schubert io[0].iov_base = (void *) in; 45985732ac8SCy Schubert io[0].iov_len = AES_BLOCK_SIZE; 46085732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 46185732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 46285732ac8SCy Schubert msg.msg_control = buf; 46385732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)); 46485732ac8SCy Schubert msg.msg_iov = io; 46585732ac8SCy Schubert msg.msg_iovlen = 1; 46685732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 46785732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 46885732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 46985732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 47085732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 47185732ac8SCy Schubert *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT; 47285732ac8SCy Schubert 47385732ac8SCy Schubert ret = sendmsg(skcipher->t, &msg, 0); 47485732ac8SCy Schubert if (ret < 0) { 47585732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 47685732ac8SCy Schubert __func__, strerror(errno)); 47785732ac8SCy Schubert return -1; 47885732ac8SCy Schubert } 47985732ac8SCy Schubert 48085732ac8SCy Schubert ret = read(skcipher->t, out, AES_BLOCK_SIZE); 48185732ac8SCy Schubert if (ret < 0) { 48285732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: read failed: %s", 48385732ac8SCy Schubert __func__, strerror(errno)); 48485732ac8SCy Schubert return -1; 48585732ac8SCy Schubert } 48685732ac8SCy Schubert if (ret < AES_BLOCK_SIZE) { 48785732ac8SCy Schubert wpa_printf(MSG_ERROR, 48885732ac8SCy Schubert "%s: read did not return full data (%d/%d)", 48985732ac8SCy Schubert __func__, (int) ret, AES_BLOCK_SIZE); 49085732ac8SCy Schubert return -1; 49185732ac8SCy Schubert } 49285732ac8SCy Schubert 49385732ac8SCy Schubert return 0; 49485732ac8SCy Schubert } 49585732ac8SCy Schubert 49685732ac8SCy Schubert 49785732ac8SCy Schubert void * aes_encrypt_init(const u8 *key, size_t len) 49885732ac8SCy Schubert { 49985732ac8SCy Schubert return linux_af_alg_skcipher("ecb(aes)", key, len); 50085732ac8SCy Schubert } 50185732ac8SCy Schubert 50285732ac8SCy Schubert 50385732ac8SCy Schubert int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) 50485732ac8SCy Schubert { 50585732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher = ctx; 50685732ac8SCy Schubert 50785732ac8SCy Schubert return linux_af_alg_skcipher_oper(skcipher, 1, plain, crypt); 50885732ac8SCy Schubert } 50985732ac8SCy Schubert 51085732ac8SCy Schubert 51185732ac8SCy Schubert void aes_encrypt_deinit(void *ctx) 51285732ac8SCy Schubert { 51385732ac8SCy Schubert linux_af_alg_skcipher_deinit(ctx); 51485732ac8SCy Schubert } 51585732ac8SCy Schubert 51685732ac8SCy Schubert 51785732ac8SCy Schubert void * aes_decrypt_init(const u8 *key, size_t len) 51885732ac8SCy Schubert { 51985732ac8SCy Schubert return linux_af_alg_skcipher("ecb(aes)", key, len); 52085732ac8SCy Schubert } 52185732ac8SCy Schubert 52285732ac8SCy Schubert 52385732ac8SCy Schubert int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) 52485732ac8SCy Schubert { 52585732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher = ctx; 52685732ac8SCy Schubert 52785732ac8SCy Schubert return linux_af_alg_skcipher_oper(skcipher, 0, crypt, plain); 52885732ac8SCy Schubert } 52985732ac8SCy Schubert 53085732ac8SCy Schubert 53185732ac8SCy Schubert void aes_decrypt_deinit(void *ctx) 53285732ac8SCy Schubert { 53385732ac8SCy Schubert linux_af_alg_skcipher_deinit(ctx); 53485732ac8SCy Schubert } 53585732ac8SCy Schubert 53685732ac8SCy Schubert 53785732ac8SCy Schubert int rc4_skip(const u8 *key, size_t keylen, size_t skip, 53885732ac8SCy Schubert u8 *data, size_t data_len) 53985732ac8SCy Schubert { 54085732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 54185732ac8SCy Schubert u8 *skip_buf; 54285732ac8SCy Schubert char buf[CMSG_SPACE(sizeof(u32))]; 54385732ac8SCy Schubert struct iovec io[2]; 54485732ac8SCy Schubert struct msghdr msg; 54585732ac8SCy Schubert struct cmsghdr *hdr; 54685732ac8SCy Schubert ssize_t ret; 54785732ac8SCy Schubert u32 *op; 54885732ac8SCy Schubert 54985732ac8SCy Schubert skip_buf = os_zalloc(skip + 1); 55085732ac8SCy Schubert if (!skip_buf) 55185732ac8SCy Schubert return -1; 55285732ac8SCy Schubert skcipher = linux_af_alg_skcipher("ecb(arc4)", key, keylen); 55385732ac8SCy Schubert if (!skcipher) { 55485732ac8SCy Schubert os_free(skip_buf); 55585732ac8SCy Schubert return -1; 55685732ac8SCy Schubert } 55785732ac8SCy Schubert 55885732ac8SCy Schubert io[0].iov_base = skip_buf; 55985732ac8SCy Schubert io[0].iov_len = skip; 56085732ac8SCy Schubert io[1].iov_base = data; 56185732ac8SCy Schubert io[1].iov_len = data_len; 56285732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 56385732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 56485732ac8SCy Schubert msg.msg_control = buf; 56585732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)); 56685732ac8SCy Schubert msg.msg_iov = io; 56785732ac8SCy Schubert msg.msg_iovlen = 2; 56885732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 56985732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 57085732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 57185732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 57285732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 57385732ac8SCy Schubert *op = ALG_OP_ENCRYPT; 57485732ac8SCy Schubert 57585732ac8SCy Schubert ret = sendmsg(skcipher->t, &msg, 0); 57685732ac8SCy Schubert if (ret < 0) { 57785732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 57885732ac8SCy Schubert __func__, strerror(errno)); 57985732ac8SCy Schubert os_free(skip_buf); 58085732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 58185732ac8SCy Schubert return -1; 58285732ac8SCy Schubert } 58385732ac8SCy Schubert os_free(skip_buf); 58485732ac8SCy Schubert 58585732ac8SCy Schubert msg.msg_control = NULL; 58685732ac8SCy Schubert msg.msg_controllen = 0; 58785732ac8SCy Schubert ret = recvmsg(skcipher->t, &msg, 0); 58885732ac8SCy Schubert if (ret < 0) { 58985732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s", 59085732ac8SCy Schubert __func__, strerror(errno)); 59185732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 59285732ac8SCy Schubert return -1; 59385732ac8SCy Schubert } 59485732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 59585732ac8SCy Schubert 59685732ac8SCy Schubert if ((size_t) ret < skip + data_len) { 59785732ac8SCy Schubert wpa_printf(MSG_ERROR, 59885732ac8SCy Schubert "%s: recvmsg did not return full data (%d/%d)", 59985732ac8SCy Schubert __func__, (int) ret, (int) (skip + data_len)); 60085732ac8SCy Schubert return -1; 60185732ac8SCy Schubert } 60285732ac8SCy Schubert 60385732ac8SCy Schubert return 0; 60485732ac8SCy Schubert } 60585732ac8SCy Schubert 60685732ac8SCy Schubert 60785732ac8SCy Schubert int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) 60885732ac8SCy Schubert { 60985732ac8SCy Schubert u8 pkey[8], next, tmp; 61085732ac8SCy Schubert int i; 61185732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 61285732ac8SCy Schubert char buf[CMSG_SPACE(sizeof(u32))]; 61385732ac8SCy Schubert struct iovec io[1]; 61485732ac8SCy Schubert struct msghdr msg; 61585732ac8SCy Schubert struct cmsghdr *hdr; 61685732ac8SCy Schubert ssize_t ret; 61785732ac8SCy Schubert u32 *op; 61885732ac8SCy Schubert int res = -1; 61985732ac8SCy Schubert 62085732ac8SCy Schubert /* Add parity bits to the key */ 62185732ac8SCy Schubert next = 0; 62285732ac8SCy Schubert for (i = 0; i < 7; i++) { 62385732ac8SCy Schubert tmp = key[i]; 62485732ac8SCy Schubert pkey[i] = (tmp >> i) | next | 1; 62585732ac8SCy Schubert next = tmp << (7 - i); 62685732ac8SCy Schubert } 62785732ac8SCy Schubert pkey[i] = next | 1; 62885732ac8SCy Schubert 62985732ac8SCy Schubert skcipher = linux_af_alg_skcipher("ecb(des)", pkey, sizeof(pkey)); 63085732ac8SCy Schubert if (!skcipher) 63185732ac8SCy Schubert goto fail; 63285732ac8SCy Schubert 63385732ac8SCy Schubert io[0].iov_base = (void *) clear; 63485732ac8SCy Schubert io[0].iov_len = 8; 63585732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 63685732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 63785732ac8SCy Schubert msg.msg_control = buf; 63885732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)); 63985732ac8SCy Schubert msg.msg_iov = io; 64085732ac8SCy Schubert msg.msg_iovlen = 1; 64185732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 64285732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 64385732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 64485732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 64585732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 64685732ac8SCy Schubert *op = ALG_OP_ENCRYPT; 64785732ac8SCy Schubert 64885732ac8SCy Schubert ret = sendmsg(skcipher->t, &msg, 0); 64985732ac8SCy Schubert if (ret < 0) { 65085732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 65185732ac8SCy Schubert __func__, strerror(errno)); 65285732ac8SCy Schubert goto fail; 65385732ac8SCy Schubert } 65485732ac8SCy Schubert 65585732ac8SCy Schubert ret = read(skcipher->t, cypher, 8); 65685732ac8SCy Schubert if (ret < 0) { 65785732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: read failed: %s", 65885732ac8SCy Schubert __func__, strerror(errno)); 65985732ac8SCy Schubert goto fail; 66085732ac8SCy Schubert } 66185732ac8SCy Schubert if (ret < 8) { 66285732ac8SCy Schubert wpa_printf(MSG_ERROR, 66385732ac8SCy Schubert "%s: read did not return full data (%d/8)", 66485732ac8SCy Schubert __func__, (int) ret); 66585732ac8SCy Schubert goto fail; 66685732ac8SCy Schubert } 66785732ac8SCy Schubert 66885732ac8SCy Schubert res = 0; 66985732ac8SCy Schubert fail: 67085732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 67185732ac8SCy Schubert return res; 67285732ac8SCy Schubert } 67385732ac8SCy Schubert 67485732ac8SCy Schubert 67585732ac8SCy Schubert static int aes_128_cbc_oper(const u8 *key, int enc, const u8 *iv, 67685732ac8SCy Schubert u8 *data, size_t data_len) 67785732ac8SCy Schubert { 67885732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 67985732ac8SCy Schubert char buf[100]; 68085732ac8SCy Schubert struct iovec io[1]; 68185732ac8SCy Schubert struct msghdr msg; 68285732ac8SCy Schubert struct cmsghdr *hdr; 68385732ac8SCy Schubert ssize_t ret; 68485732ac8SCy Schubert u32 *op; 68585732ac8SCy Schubert struct af_alg_iv *alg_iv; 68685732ac8SCy Schubert size_t iv_len = AES_BLOCK_SIZE; 68785732ac8SCy Schubert 68885732ac8SCy Schubert skcipher = linux_af_alg_skcipher("cbc(aes)", key, 16); 68985732ac8SCy Schubert if (!skcipher) 69085732ac8SCy Schubert return -1; 69185732ac8SCy Schubert 69285732ac8SCy Schubert io[0].iov_base = (void *) data; 69385732ac8SCy Schubert io[0].iov_len = data_len; 69485732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 69585732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 69685732ac8SCy Schubert msg.msg_control = buf; 69785732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)) + 69885732ac8SCy Schubert CMSG_SPACE(sizeof(*alg_iv) + iv_len); 69985732ac8SCy Schubert msg.msg_iov = io; 70085732ac8SCy Schubert msg.msg_iovlen = 1; 70185732ac8SCy Schubert 70285732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 70385732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 70485732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 70585732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 70685732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 70785732ac8SCy Schubert *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT; 70885732ac8SCy Schubert 70985732ac8SCy Schubert hdr = CMSG_NXTHDR(&msg, hdr); 71085732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 71185732ac8SCy Schubert hdr->cmsg_type = ALG_SET_IV; 71285732ac8SCy Schubert hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len); 71385732ac8SCy Schubert alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr); 71485732ac8SCy Schubert alg_iv->ivlen = iv_len; 71585732ac8SCy Schubert os_memcpy(alg_iv->iv, iv, iv_len); 71685732ac8SCy Schubert 71785732ac8SCy Schubert ret = sendmsg(skcipher->t, &msg, 0); 71885732ac8SCy Schubert if (ret < 0) { 71985732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 72085732ac8SCy Schubert __func__, strerror(errno)); 72185732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 72285732ac8SCy Schubert return -1; 72385732ac8SCy Schubert } 72485732ac8SCy Schubert 72585732ac8SCy Schubert ret = recvmsg(skcipher->t, &msg, 0); 72685732ac8SCy Schubert if (ret < 0) { 72785732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s", 72885732ac8SCy Schubert __func__, strerror(errno)); 72985732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 73085732ac8SCy Schubert return -1; 73185732ac8SCy Schubert } 73285732ac8SCy Schubert if ((size_t) ret < data_len) { 73385732ac8SCy Schubert wpa_printf(MSG_ERROR, 73485732ac8SCy Schubert "%s: recvmsg not return full data (%d/%d)", 73585732ac8SCy Schubert __func__, (int) ret, (int) data_len); 73685732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 73785732ac8SCy Schubert return -1; 73885732ac8SCy Schubert } 73985732ac8SCy Schubert 74085732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 74185732ac8SCy Schubert return 0; 74285732ac8SCy Schubert } 74385732ac8SCy Schubert 74485732ac8SCy Schubert 74585732ac8SCy Schubert int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) 74685732ac8SCy Schubert { 74785732ac8SCy Schubert return aes_128_cbc_oper(key, 1, iv, data, data_len); 74885732ac8SCy Schubert } 74985732ac8SCy Schubert 75085732ac8SCy Schubert 75185732ac8SCy Schubert int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) 75285732ac8SCy Schubert { 75385732ac8SCy Schubert return aes_128_cbc_oper(key, 0, iv, data, data_len); 75485732ac8SCy Schubert } 75585732ac8SCy Schubert 75685732ac8SCy Schubert 75785732ac8SCy Schubert int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, 75885732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 75985732ac8SCy Schubert { 76085732ac8SCy Schubert return linux_af_alg_hash_vector("cmac(aes)", key, key_len, num_elem, 76185732ac8SCy Schubert addr, len, mac, AES_BLOCK_SIZE); 76285732ac8SCy Schubert } 76385732ac8SCy Schubert 76485732ac8SCy Schubert 76585732ac8SCy Schubert int omac1_aes_128_vector(const u8 *key, size_t num_elem, 76685732ac8SCy Schubert const u8 *addr[], const size_t *len, u8 *mac) 76785732ac8SCy Schubert { 76885732ac8SCy Schubert return omac1_aes_vector(key, 16, num_elem, addr, len, mac); 76985732ac8SCy Schubert } 77085732ac8SCy Schubert 77185732ac8SCy Schubert 77285732ac8SCy Schubert int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) 77385732ac8SCy Schubert { 77485732ac8SCy Schubert return omac1_aes_128_vector(key, 1, &data, &data_len, mac); 77585732ac8SCy Schubert } 77685732ac8SCy Schubert 77785732ac8SCy Schubert 77885732ac8SCy Schubert int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) 77985732ac8SCy Schubert { 78085732ac8SCy Schubert return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); 78185732ac8SCy Schubert } 78285732ac8SCy Schubert 78385732ac8SCy Schubert 78485732ac8SCy Schubert int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, 78585732ac8SCy Schubert u8 *plain) 78685732ac8SCy Schubert { 78785732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 78885732ac8SCy Schubert char buf[100]; 78985732ac8SCy Schubert struct iovec io[1]; 79085732ac8SCy Schubert struct msghdr msg; 79185732ac8SCy Schubert struct cmsghdr *hdr; 79285732ac8SCy Schubert ssize_t ret; 79385732ac8SCy Schubert u32 *op; 79485732ac8SCy Schubert struct af_alg_iv *alg_iv; 79585732ac8SCy Schubert size_t iv_len = 8; 79685732ac8SCy Schubert 79785732ac8SCy Schubert skcipher = linux_af_alg_skcipher("kw(aes)", kek, kek_len); 79885732ac8SCy Schubert if (!skcipher) 79985732ac8SCy Schubert return -1; 80085732ac8SCy Schubert 80185732ac8SCy Schubert io[0].iov_base = (void *) (cipher + iv_len); 80285732ac8SCy Schubert io[0].iov_len = n * 8; 80385732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 80485732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 80585732ac8SCy Schubert msg.msg_control = buf; 80685732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)) + 80785732ac8SCy Schubert CMSG_SPACE(sizeof(*alg_iv) + iv_len); 80885732ac8SCy Schubert msg.msg_iov = io; 80985732ac8SCy Schubert msg.msg_iovlen = 1; 81085732ac8SCy Schubert 81185732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 81285732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 81385732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 81485732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 81585732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 81685732ac8SCy Schubert *op = ALG_OP_DECRYPT; 81785732ac8SCy Schubert 81885732ac8SCy Schubert hdr = CMSG_NXTHDR(&msg, hdr); 81985732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 82085732ac8SCy Schubert hdr->cmsg_type = ALG_SET_IV; 82185732ac8SCy Schubert hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len); 82285732ac8SCy Schubert alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr); 82385732ac8SCy Schubert alg_iv->ivlen = iv_len; 82485732ac8SCy Schubert os_memcpy(alg_iv->iv, cipher, iv_len); 82585732ac8SCy Schubert 82685732ac8SCy Schubert ret = sendmsg(skcipher->t, &msg, 0); 82785732ac8SCy Schubert if (ret < 0) { 82885732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 82985732ac8SCy Schubert __func__, strerror(errno)); 83085732ac8SCy Schubert return -1; 83185732ac8SCy Schubert } 83285732ac8SCy Schubert 83385732ac8SCy Schubert ret = read(skcipher->t, plain, n * 8); 83485732ac8SCy Schubert if (ret < 0) { 83585732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: read failed: %s", 83685732ac8SCy Schubert __func__, strerror(errno)); 83785732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 83885732ac8SCy Schubert return -1; 83985732ac8SCy Schubert } 84085732ac8SCy Schubert if (ret < n * 8) { 84185732ac8SCy Schubert wpa_printf(MSG_ERROR, 84285732ac8SCy Schubert "%s: read not return full data (%d/%d)", 84385732ac8SCy Schubert __func__, (int) ret, n * 8); 84485732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 84585732ac8SCy Schubert return -1; 84685732ac8SCy Schubert } 84785732ac8SCy Schubert 84885732ac8SCy Schubert linux_af_alg_skcipher_deinit(skcipher); 84985732ac8SCy Schubert return 0; 85085732ac8SCy Schubert } 85185732ac8SCy Schubert 85285732ac8SCy Schubert 85385732ac8SCy Schubert struct crypto_cipher { 85485732ac8SCy Schubert struct linux_af_alg_skcipher *skcipher; 85585732ac8SCy Schubert }; 85685732ac8SCy Schubert 85785732ac8SCy Schubert 85885732ac8SCy Schubert struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, 85985732ac8SCy Schubert const u8 *iv, const u8 *key, 86085732ac8SCy Schubert size_t key_len) 86185732ac8SCy Schubert { 86285732ac8SCy Schubert struct crypto_cipher *ctx; 86385732ac8SCy Schubert const char *name; 86485732ac8SCy Schubert struct af_alg_iv *alg_iv; 86585732ac8SCy Schubert size_t iv_len = 0; 86685732ac8SCy Schubert char buf[100]; 86785732ac8SCy Schubert struct msghdr msg; 86885732ac8SCy Schubert struct cmsghdr *hdr; 86985732ac8SCy Schubert ssize_t ret; 87085732ac8SCy Schubert 87185732ac8SCy Schubert ctx = os_zalloc(sizeof(*ctx)); 87285732ac8SCy Schubert if (!ctx) 87385732ac8SCy Schubert return NULL; 87485732ac8SCy Schubert 87585732ac8SCy Schubert switch (alg) { 87685732ac8SCy Schubert case CRYPTO_CIPHER_ALG_RC4: 87785732ac8SCy Schubert name = "ecb(arc4)"; 87885732ac8SCy Schubert break; 87985732ac8SCy Schubert case CRYPTO_CIPHER_ALG_AES: 88085732ac8SCy Schubert name = "cbc(aes)"; 88185732ac8SCy Schubert iv_len = AES_BLOCK_SIZE; 88285732ac8SCy Schubert break; 88385732ac8SCy Schubert case CRYPTO_CIPHER_ALG_3DES: 88485732ac8SCy Schubert name = "cbc(des3_ede)"; 88585732ac8SCy Schubert iv_len = 8; 88685732ac8SCy Schubert break; 88785732ac8SCy Schubert case CRYPTO_CIPHER_ALG_DES: 88885732ac8SCy Schubert name = "cbc(des)"; 88985732ac8SCy Schubert iv_len = 8; 89085732ac8SCy Schubert break; 89185732ac8SCy Schubert default: 89285732ac8SCy Schubert os_free(ctx); 89385732ac8SCy Schubert return NULL; 89485732ac8SCy Schubert } 89585732ac8SCy Schubert 89685732ac8SCy Schubert ctx->skcipher = linux_af_alg_skcipher(name, key, key_len); 89785732ac8SCy Schubert if (!ctx->skcipher) { 89885732ac8SCy Schubert os_free(ctx); 89985732ac8SCy Schubert return NULL; 90085732ac8SCy Schubert } 90185732ac8SCy Schubert 90285732ac8SCy Schubert if (iv && iv_len) { 90385732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 90485732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 90585732ac8SCy Schubert msg.msg_control = buf; 90685732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(*alg_iv) + iv_len); 90785732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 90885732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 90985732ac8SCy Schubert hdr->cmsg_type = ALG_SET_IV; 91085732ac8SCy Schubert hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len); 91185732ac8SCy Schubert alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr); 91285732ac8SCy Schubert alg_iv->ivlen = iv_len; 91385732ac8SCy Schubert os_memcpy(alg_iv->iv, iv, iv_len); 91485732ac8SCy Schubert 91585732ac8SCy Schubert ret = sendmsg(ctx->skcipher->t, &msg, 0); 91685732ac8SCy Schubert if (ret < 0) { 91785732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 91885732ac8SCy Schubert __func__, strerror(errno)); 91985732ac8SCy Schubert linux_af_alg_skcipher_deinit(ctx->skcipher); 92085732ac8SCy Schubert os_free(ctx); 92185732ac8SCy Schubert return NULL; 92285732ac8SCy Schubert } 92385732ac8SCy Schubert } 92485732ac8SCy Schubert 92585732ac8SCy Schubert return ctx; 92685732ac8SCy Schubert } 92785732ac8SCy Schubert 92885732ac8SCy Schubert 92985732ac8SCy Schubert static int crypto_cipher_oper(struct crypto_cipher *ctx, u32 type, const u8 *in, 93085732ac8SCy Schubert u8 *out, size_t len) 93185732ac8SCy Schubert { 93285732ac8SCy Schubert char buf[CMSG_SPACE(sizeof(u32))]; 93385732ac8SCy Schubert struct iovec io[1]; 93485732ac8SCy Schubert struct msghdr msg; 93585732ac8SCy Schubert struct cmsghdr *hdr; 93685732ac8SCy Schubert ssize_t ret; 93785732ac8SCy Schubert u32 *op; 93885732ac8SCy Schubert 93985732ac8SCy Schubert io[0].iov_base = (void *) in; 94085732ac8SCy Schubert io[0].iov_len = len; 94185732ac8SCy Schubert os_memset(&msg, 0, sizeof(msg)); 94285732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 94385732ac8SCy Schubert msg.msg_control = buf; 94485732ac8SCy Schubert msg.msg_controllen = CMSG_SPACE(sizeof(u32)); 94585732ac8SCy Schubert msg.msg_iov = io; 94685732ac8SCy Schubert msg.msg_iovlen = 1; 94785732ac8SCy Schubert hdr = CMSG_FIRSTHDR(&msg); 94885732ac8SCy Schubert hdr->cmsg_level = SOL_ALG; 94985732ac8SCy Schubert hdr->cmsg_type = ALG_SET_OP; 95085732ac8SCy Schubert hdr->cmsg_len = CMSG_LEN(sizeof(u32)); 95185732ac8SCy Schubert op = (u32 *) CMSG_DATA(hdr); 95285732ac8SCy Schubert *op = type; 95385732ac8SCy Schubert 95485732ac8SCy Schubert ret = sendmsg(ctx->skcipher->t, &msg, 0); 95585732ac8SCy Schubert if (ret < 0) { 95685732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s", 95785732ac8SCy Schubert __func__, strerror(errno)); 95885732ac8SCy Schubert return -1; 95985732ac8SCy Schubert } 96085732ac8SCy Schubert 96185732ac8SCy Schubert ret = read(ctx->skcipher->t, out, len); 96285732ac8SCy Schubert if (ret < 0) { 96385732ac8SCy Schubert wpa_printf(MSG_ERROR, "%s: read failed: %s", 96485732ac8SCy Schubert __func__, strerror(errno)); 96585732ac8SCy Schubert return -1; 96685732ac8SCy Schubert } 96785732ac8SCy Schubert if (ret < (ssize_t) len) { 96885732ac8SCy Schubert wpa_printf(MSG_ERROR, 96985732ac8SCy Schubert "%s: read did not return full data (%d/%d)", 97085732ac8SCy Schubert __func__, (int) ret, (int) len); 97185732ac8SCy Schubert return -1; 97285732ac8SCy Schubert } 97385732ac8SCy Schubert 97485732ac8SCy Schubert return 0; 97585732ac8SCy Schubert } 97685732ac8SCy Schubert 97785732ac8SCy Schubert 97885732ac8SCy Schubert int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, 97985732ac8SCy Schubert u8 *crypt, size_t len) 98085732ac8SCy Schubert { 98185732ac8SCy Schubert return crypto_cipher_oper(ctx, ALG_OP_ENCRYPT, plain, crypt, len); 98285732ac8SCy Schubert } 98385732ac8SCy Schubert 98485732ac8SCy Schubert 98585732ac8SCy Schubert int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, 98685732ac8SCy Schubert u8 *plain, size_t len) 98785732ac8SCy Schubert { 98885732ac8SCy Schubert return crypto_cipher_oper(ctx, ALG_OP_DECRYPT, crypt, plain, len); 98985732ac8SCy Schubert } 99085732ac8SCy Schubert 99185732ac8SCy Schubert 99285732ac8SCy Schubert void crypto_cipher_deinit(struct crypto_cipher *ctx) 99385732ac8SCy Schubert { 99485732ac8SCy Schubert if (ctx) { 99585732ac8SCy Schubert linux_af_alg_skcipher_deinit(ctx->skcipher); 99685732ac8SCy Schubert os_free(ctx); 99785732ac8SCy Schubert } 99885732ac8SCy Schubert } 99985732ac8SCy Schubert 100085732ac8SCy Schubert 100185732ac8SCy Schubert int crypto_global_init(void) 100285732ac8SCy Schubert { 100385732ac8SCy Schubert return 0; 100485732ac8SCy Schubert } 100585732ac8SCy Schubert 100685732ac8SCy Schubert 100785732ac8SCy Schubert void crypto_global_deinit(void) 100885732ac8SCy Schubert { 100985732ac8SCy Schubert } 1010*a90b9d01SCy Schubert 1011*a90b9d01SCy Schubert 1012*a90b9d01SCy Schubert void crypto_unload(void) 1013*a90b9d01SCy Schubert { 1014*a90b9d01SCy Schubert } 1015