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