1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * AES SIV (RFC 5297) 3e5b75505Sopenharmony_ci * Copyright (c) 2013 Cozybit, Inc. 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "aes.h" 13e5b75505Sopenharmony_ci#include "aes_wrap.h" 14e5b75505Sopenharmony_ci#include "aes_siv.h" 15e5b75505Sopenharmony_ci 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_cistatic const u8 zero[AES_BLOCK_SIZE]; 18e5b75505Sopenharmony_ci 19e5b75505Sopenharmony_ci 20e5b75505Sopenharmony_cistatic void dbl(u8 *pad) 21e5b75505Sopenharmony_ci{ 22e5b75505Sopenharmony_ci int i, carry; 23e5b75505Sopenharmony_ci 24e5b75505Sopenharmony_ci carry = pad[0] & 0x80; 25e5b75505Sopenharmony_ci for (i = 0; i < AES_BLOCK_SIZE - 1; i++) 26e5b75505Sopenharmony_ci pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); 27e5b75505Sopenharmony_ci pad[AES_BLOCK_SIZE - 1] <<= 1; 28e5b75505Sopenharmony_ci if (carry) 29e5b75505Sopenharmony_ci pad[AES_BLOCK_SIZE - 1] ^= 0x87; 30e5b75505Sopenharmony_ci} 31e5b75505Sopenharmony_ci 32e5b75505Sopenharmony_ci 33e5b75505Sopenharmony_cistatic void xor(u8 *a, const u8 *b) 34e5b75505Sopenharmony_ci{ 35e5b75505Sopenharmony_ci int i; 36e5b75505Sopenharmony_ci 37e5b75505Sopenharmony_ci for (i = 0; i < AES_BLOCK_SIZE; i++) 38e5b75505Sopenharmony_ci *a++ ^= *b++; 39e5b75505Sopenharmony_ci} 40e5b75505Sopenharmony_ci 41e5b75505Sopenharmony_ci 42e5b75505Sopenharmony_cistatic void xorend(u8 *a, int alen, const u8 *b, int blen) 43e5b75505Sopenharmony_ci{ 44e5b75505Sopenharmony_ci int i; 45e5b75505Sopenharmony_ci 46e5b75505Sopenharmony_ci if (alen < blen) 47e5b75505Sopenharmony_ci return; 48e5b75505Sopenharmony_ci 49e5b75505Sopenharmony_ci for (i = 0; i < blen; i++) 50e5b75505Sopenharmony_ci a[alen - blen + i] ^= b[i]; 51e5b75505Sopenharmony_ci} 52e5b75505Sopenharmony_ci 53e5b75505Sopenharmony_ci 54e5b75505Sopenharmony_cistatic void pad_block(u8 *pad, const u8 *addr, size_t len) 55e5b75505Sopenharmony_ci{ 56e5b75505Sopenharmony_ci os_memset(pad, 0, AES_BLOCK_SIZE); 57e5b75505Sopenharmony_ci os_memcpy(pad, addr, len); 58e5b75505Sopenharmony_ci 59e5b75505Sopenharmony_ci if (len < AES_BLOCK_SIZE) 60e5b75505Sopenharmony_ci pad[len] = 0x80; 61e5b75505Sopenharmony_ci} 62e5b75505Sopenharmony_ci 63e5b75505Sopenharmony_ci 64e5b75505Sopenharmony_cistatic int aes_s2v(const u8 *key, size_t key_len, 65e5b75505Sopenharmony_ci size_t num_elem, const u8 *addr[], size_t *len, u8 *mac) 66e5b75505Sopenharmony_ci{ 67e5b75505Sopenharmony_ci u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE]; 68e5b75505Sopenharmony_ci u8 *buf = NULL; 69e5b75505Sopenharmony_ci int ret; 70e5b75505Sopenharmony_ci size_t i; 71e5b75505Sopenharmony_ci const u8 *data[1]; 72e5b75505Sopenharmony_ci size_t data_len[1]; 73e5b75505Sopenharmony_ci 74e5b75505Sopenharmony_ci if (!num_elem) { 75e5b75505Sopenharmony_ci os_memcpy(tmp, zero, sizeof(zero)); 76e5b75505Sopenharmony_ci tmp[AES_BLOCK_SIZE - 1] = 1; 77e5b75505Sopenharmony_ci data[0] = tmp; 78e5b75505Sopenharmony_ci data_len[0] = sizeof(tmp); 79e5b75505Sopenharmony_ci return omac1_aes_vector(key, key_len, 1, data, data_len, mac); 80e5b75505Sopenharmony_ci } 81e5b75505Sopenharmony_ci 82e5b75505Sopenharmony_ci data[0] = zero; 83e5b75505Sopenharmony_ci data_len[0] = sizeof(zero); 84e5b75505Sopenharmony_ci ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp); 85e5b75505Sopenharmony_ci if (ret) 86e5b75505Sopenharmony_ci return ret; 87e5b75505Sopenharmony_ci 88e5b75505Sopenharmony_ci for (i = 0; i < num_elem - 1; i++) { 89e5b75505Sopenharmony_ci ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i], 90e5b75505Sopenharmony_ci tmp2); 91e5b75505Sopenharmony_ci if (ret) 92e5b75505Sopenharmony_ci return ret; 93e5b75505Sopenharmony_ci 94e5b75505Sopenharmony_ci dbl(tmp); 95e5b75505Sopenharmony_ci xor(tmp, tmp2); 96e5b75505Sopenharmony_ci } 97e5b75505Sopenharmony_ci if (len[i] >= AES_BLOCK_SIZE) { 98e5b75505Sopenharmony_ci buf = os_memdup(addr[i], len[i]); 99e5b75505Sopenharmony_ci if (!buf) 100e5b75505Sopenharmony_ci return -ENOMEM; 101e5b75505Sopenharmony_ci 102e5b75505Sopenharmony_ci xorend(buf, len[i], tmp, AES_BLOCK_SIZE); 103e5b75505Sopenharmony_ci data[0] = buf; 104e5b75505Sopenharmony_ci ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac); 105e5b75505Sopenharmony_ci bin_clear_free(buf, len[i]); 106e5b75505Sopenharmony_ci return ret; 107e5b75505Sopenharmony_ci } 108e5b75505Sopenharmony_ci 109e5b75505Sopenharmony_ci dbl(tmp); 110e5b75505Sopenharmony_ci pad_block(tmp2, addr[i], len[i]); 111e5b75505Sopenharmony_ci xor(tmp, tmp2); 112e5b75505Sopenharmony_ci 113e5b75505Sopenharmony_ci data[0] = tmp; 114e5b75505Sopenharmony_ci data_len[0] = sizeof(tmp); 115e5b75505Sopenharmony_ci return omac1_aes_vector(key, key_len, 1, data, data_len, mac); 116e5b75505Sopenharmony_ci} 117e5b75505Sopenharmony_ci 118e5b75505Sopenharmony_ci 119e5b75505Sopenharmony_ciint aes_siv_encrypt(const u8 *key, size_t key_len, 120e5b75505Sopenharmony_ci const u8 *pw, size_t pwlen, 121e5b75505Sopenharmony_ci size_t num_elem, const u8 *addr[], const size_t *len, 122e5b75505Sopenharmony_ci u8 *out) 123e5b75505Sopenharmony_ci{ 124e5b75505Sopenharmony_ci const u8 *_addr[6]; 125e5b75505Sopenharmony_ci size_t _len[6]; 126e5b75505Sopenharmony_ci const u8 *k1, *k2; 127e5b75505Sopenharmony_ci u8 v[AES_BLOCK_SIZE]; 128e5b75505Sopenharmony_ci size_t i; 129e5b75505Sopenharmony_ci u8 *iv, *crypt_pw; 130e5b75505Sopenharmony_ci 131e5b75505Sopenharmony_ci if (num_elem > ARRAY_SIZE(_addr) - 1 || 132e5b75505Sopenharmony_ci (key_len != 32 && key_len != 48 && key_len != 64)) 133e5b75505Sopenharmony_ci return -1; 134e5b75505Sopenharmony_ci 135e5b75505Sopenharmony_ci key_len /= 2; 136e5b75505Sopenharmony_ci k1 = key; 137e5b75505Sopenharmony_ci k2 = key + key_len; 138e5b75505Sopenharmony_ci 139e5b75505Sopenharmony_ci for (i = 0; i < num_elem; i++) { 140e5b75505Sopenharmony_ci _addr[i] = addr[i]; 141e5b75505Sopenharmony_ci _len[i] = len[i]; 142e5b75505Sopenharmony_ci } 143e5b75505Sopenharmony_ci _addr[num_elem] = pw; 144e5b75505Sopenharmony_ci _len[num_elem] = pwlen; 145e5b75505Sopenharmony_ci 146e5b75505Sopenharmony_ci if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v)) 147e5b75505Sopenharmony_ci return -1; 148e5b75505Sopenharmony_ci 149e5b75505Sopenharmony_ci iv = out; 150e5b75505Sopenharmony_ci crypt_pw = out + AES_BLOCK_SIZE; 151e5b75505Sopenharmony_ci 152e5b75505Sopenharmony_ci os_memcpy(iv, v, AES_BLOCK_SIZE); 153e5b75505Sopenharmony_ci os_memcpy(crypt_pw, pw, pwlen); 154e5b75505Sopenharmony_ci 155e5b75505Sopenharmony_ci /* zero out 63rd and 31st bits of ctr (from right) */ 156e5b75505Sopenharmony_ci v[8] &= 0x7f; 157e5b75505Sopenharmony_ci v[12] &= 0x7f; 158e5b75505Sopenharmony_ci return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen); 159e5b75505Sopenharmony_ci} 160e5b75505Sopenharmony_ci 161e5b75505Sopenharmony_ci 162e5b75505Sopenharmony_ciint aes_siv_decrypt(const u8 *key, size_t key_len, 163e5b75505Sopenharmony_ci const u8 *iv_crypt, size_t iv_c_len, 164e5b75505Sopenharmony_ci size_t num_elem, const u8 *addr[], const size_t *len, 165e5b75505Sopenharmony_ci u8 *out) 166e5b75505Sopenharmony_ci{ 167e5b75505Sopenharmony_ci const u8 *_addr[6]; 168e5b75505Sopenharmony_ci size_t _len[6]; 169e5b75505Sopenharmony_ci const u8 *k1, *k2; 170e5b75505Sopenharmony_ci size_t crypt_len; 171e5b75505Sopenharmony_ci size_t i; 172e5b75505Sopenharmony_ci int ret; 173e5b75505Sopenharmony_ci u8 iv[AES_BLOCK_SIZE]; 174e5b75505Sopenharmony_ci u8 check[AES_BLOCK_SIZE]; 175e5b75505Sopenharmony_ci 176e5b75505Sopenharmony_ci if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 || 177e5b75505Sopenharmony_ci (key_len != 32 && key_len != 48 && key_len != 64)) 178e5b75505Sopenharmony_ci return -1; 179e5b75505Sopenharmony_ci crypt_len = iv_c_len - AES_BLOCK_SIZE; 180e5b75505Sopenharmony_ci key_len /= 2; 181e5b75505Sopenharmony_ci k1 = key; 182e5b75505Sopenharmony_ci k2 = key + key_len; 183e5b75505Sopenharmony_ci 184e5b75505Sopenharmony_ci for (i = 0; i < num_elem; i++) { 185e5b75505Sopenharmony_ci _addr[i] = addr[i]; 186e5b75505Sopenharmony_ci _len[i] = len[i]; 187e5b75505Sopenharmony_ci } 188e5b75505Sopenharmony_ci _addr[num_elem] = out; 189e5b75505Sopenharmony_ci _len[num_elem] = crypt_len; 190e5b75505Sopenharmony_ci 191e5b75505Sopenharmony_ci os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE); 192e5b75505Sopenharmony_ci os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len); 193e5b75505Sopenharmony_ci 194e5b75505Sopenharmony_ci iv[8] &= 0x7f; 195e5b75505Sopenharmony_ci iv[12] &= 0x7f; 196e5b75505Sopenharmony_ci 197e5b75505Sopenharmony_ci ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len); 198e5b75505Sopenharmony_ci if (ret) 199e5b75505Sopenharmony_ci return ret; 200e5b75505Sopenharmony_ci 201e5b75505Sopenharmony_ci ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check); 202e5b75505Sopenharmony_ci if (ret) 203e5b75505Sopenharmony_ci return ret; 204e5b75505Sopenharmony_ci if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0) 205e5b75505Sopenharmony_ci return 0; 206e5b75505Sopenharmony_ci 207e5b75505Sopenharmony_ci return -1; 208e5b75505Sopenharmony_ci} 209