123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- * AES SIV (RFC 5297)
- * Copyright (c) 2013 Cozybit, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "includes.h"
- #include "common.h"
- #include "aes.h"
- #include "aes_wrap.h"
- #include "aes_siv.h"
- static const u8 zero[AES_BLOCK_SIZE];
- static void dbl(u8 *pad)
- {
- int i, carry;
- carry = pad[0] & 0x80;
- for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
- pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
- pad[AES_BLOCK_SIZE - 1] <<= 1;
- if (carry)
- pad[AES_BLOCK_SIZE - 1] ^= 0x87;
- }
- static void xor(u8 *a, const u8 *b)
- {
- int i;
- for (i = 0; i < AES_BLOCK_SIZE; i++)
- *a++ ^= *b++;
- }
- static void xorend(u8 *a, int alen, const u8 *b, int blen)
- {
- int i;
- if (alen < blen)
- return;
- for (i = 0; i < blen; i++)
- a[alen - blen + i] ^= b[i];
- }
- static void pad_block(u8 *pad, const u8 *addr, size_t len)
- {
- os_memset(pad, 0, AES_BLOCK_SIZE);
- os_memcpy(pad, addr, len);
- if (len < AES_BLOCK_SIZE)
- pad[len] = 0x80;
- }
- static int aes_s2v(const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
- {
- u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
- u8 *buf = NULL;
- int ret;
- size_t i;
- const u8 *data[1];
- size_t data_len[1];
- if (!num_elem) {
- os_memcpy(tmp, zero, sizeof(zero));
- tmp[AES_BLOCK_SIZE - 1] = 1;
- data[0] = tmp;
- data_len[0] = sizeof(tmp);
- return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
- }
- data[0] = zero;
- data_len[0] = sizeof(zero);
- ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
- if (ret)
- return ret;
- for (i = 0; i < num_elem - 1; i++) {
- ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
- tmp2);
- if (ret)
- return ret;
- dbl(tmp);
- xor(tmp, tmp2);
- }
- if (len[i] >= AES_BLOCK_SIZE) {
- buf = os_malloc(len[i]);
- if (!buf)
- return -ENOMEM;
- os_memcpy(buf, addr[i], len[i]);
- xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
- data[0] = buf;
- ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
- bin_clear_free(buf, len[i]);
- return ret;
- }
- dbl(tmp);
- pad_block(tmp2, addr[i], len[i]);
- xor(tmp, tmp2);
- data[0] = tmp;
- data_len[0] = sizeof(tmp);
- return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
- }
- int aes_siv_encrypt(const u8 *key, size_t key_len,
- const u8 *pw, size_t pwlen,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *out)
- {
- const u8 *_addr[6];
- size_t _len[6];
- const u8 *k1, *k2;
- u8 v[AES_BLOCK_SIZE];
- size_t i;
- u8 *iv, *crypt_pw;
- if (num_elem > ARRAY_SIZE(_addr) - 1 ||
- (key_len != 32 && key_len != 48 && key_len != 64))
- return -1;
- key_len /= 2;
- k1 = key;
- k2 = key + key_len;
- for (i = 0; i < num_elem; i++) {
- _addr[i] = addr[i];
- _len[i] = len[i];
- }
- _addr[num_elem] = pw;
- _len[num_elem] = pwlen;
- if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
- return -1;
- iv = out;
- crypt_pw = out + AES_BLOCK_SIZE;
- os_memcpy(iv, v, AES_BLOCK_SIZE);
- os_memcpy(crypt_pw, pw, pwlen);
- /* zero out 63rd and 31st bits of ctr (from right) */
- v[8] &= 0x7f;
- v[12] &= 0x7f;
- return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
- }
- int aes_siv_decrypt(const u8 *key, size_t key_len,
- const u8 *iv_crypt, size_t iv_c_len,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *out)
- {
- const u8 *_addr[6];
- size_t _len[6];
- const u8 *k1, *k2;
- size_t crypt_len;
- size_t i;
- int ret;
- u8 iv[AES_BLOCK_SIZE];
- u8 check[AES_BLOCK_SIZE];
- if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
- (key_len != 32 && key_len != 48 && key_len != 64))
- return -1;
- crypt_len = iv_c_len - AES_BLOCK_SIZE;
- key_len /= 2;
- k1 = key;
- k2 = key + key_len;
- for (i = 0; i < num_elem; i++) {
- _addr[i] = addr[i];
- _len[i] = len[i];
- }
- _addr[num_elem] = out;
- _len[num_elem] = crypt_len;
- os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
- os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
- iv[8] &= 0x7f;
- iv[12] &= 0x7f;
- ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
- if (ret)
- return ret;
- ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
- if (ret)
- return ret;
- if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
- return 0;
- return -1;
- }
|