]>
Commit | Line | Data |
---|---|---|
0c1f3509 MG |
1 | #include <assert.h> |
2 | #include <stdint.h> | |
3 | #include <stdlib.h> | |
4 | #include <string.h> | |
5 | ||
6 | #include <openssl/aes.h> | |
7 | ||
8 | #include "cpusupport.h" | |
9 | #include "crypto_aes_aesni.h" | |
10 | #include "insecure_memzero.h" | |
11 | #include "warnp.h" | |
12 | ||
13 | #include "crypto_aes.h" | |
14 | ||
15 | /** | |
16 | * This represents either an AES_KEY or a struct crypto_aes_key_aesni; we | |
17 | * know which it is based on whether we're using AESNI code or not. As such, | |
18 | * it's just an opaque pointer; but declaring it as a named structure type | |
19 | * prevents type-mismatch bugs in upstream code. | |
20 | */ | |
21 | struct crypto_aes_key; | |
22 | ||
23 | #ifdef CPUSUPPORT_X86_AESNI | |
24 | /* Test whether OpenSSL and AESNI code produce the same AES ciphertext. */ | |
25 | static int | |
26 | aesnitest(uint8_t ptext[16], uint8_t * key, size_t len) | |
27 | { | |
28 | AES_KEY kexp_openssl; | |
29 | void * kexp_aesni; | |
30 | uint8_t ctext_openssl[16]; | |
31 | uint8_t ctext_aesni[16]; | |
32 | ||
33 | /* Sanity-check. */ | |
34 | assert((len == 16) || (len == 32)); | |
35 | ||
36 | /* Expand the key. */ | |
37 | AES_set_encrypt_key(key, (int)(len * 8), &kexp_openssl); | |
38 | if ((kexp_aesni = crypto_aes_key_expand_aesni(key, len)) == NULL) | |
39 | goto err0; | |
40 | ||
41 | /* Encrypt the block. */ | |
42 | AES_encrypt(ptext, ctext_openssl, &kexp_openssl); | |
43 | crypto_aes_encrypt_block_aesni(ptext, ctext_aesni, kexp_aesni); | |
44 | ||
45 | /* Free the AESNI expanded key. */ | |
46 | crypto_aes_key_free_aesni(kexp_aesni); | |
47 | ||
48 | /* Do the outputs match? */ | |
49 | return (memcmp(ctext_openssl, ctext_aesni, 16)); | |
50 | ||
51 | err0: | |
52 | /* Failure! */ | |
53 | return (-1); | |
54 | } | |
55 | ||
56 | /* Should we use AESNI? */ | |
57 | static int | |
58 | useaesni(void) | |
59 | { | |
60 | static int aesnigood = -1; | |
61 | uint8_t key[32]; | |
62 | uint8_t ptext[16]; | |
63 | size_t i; | |
64 | ||
65 | /* If we haven't decided which code to use yet, decide now. */ | |
66 | while (aesnigood == -1) { | |
67 | /* Default to OpenSSL. */ | |
68 | aesnigood = 0; | |
69 | ||
70 | /* If the CPU doesn't claim to support AESNI, stop here. */ | |
71 | if (!cpusupport_x86_aesni()) | |
72 | break; | |
73 | ||
74 | /* Test cases: key is 0x00010203..., ptext is 0x00112233... */ | |
75 | for (i = 0; i < 16; i++) | |
76 | ptext[i] = (0x11 * i) & 0xff; | |
77 | for (i = 0; i < 32; i++) | |
78 | key[i] = i & 0xff; | |
79 | ||
80 | /* Test that AESNI and OpenSSL produce the same results. */ | |
81 | if (aesnitest(ptext, key, 16) || aesnitest(ptext, key, 32)) { | |
82 | warn0("Disabling AESNI due to failed self-test"); | |
83 | break; | |
84 | } | |
85 | ||
86 | /* AESNI works; use it. */ | |
87 | aesnigood = 1; | |
88 | } | |
89 | ||
90 | return (aesnigood); | |
91 | } | |
92 | #endif /* CPUSUPPORT_X86_AESNI */ | |
93 | ||
94 | /** | |
95 | * crypto_aes_key_expand(key, len): | |
96 | * Expand the ${len}-byte AES key ${key} into a structure which can be passed | |
97 | * to crypto_aes_encrypt_block. The length must be 16 or 32. | |
98 | */ | |
99 | struct crypto_aes_key * | |
100 | crypto_aes_key_expand(const uint8_t * key, size_t len) | |
101 | { | |
102 | AES_KEY * kexp; | |
103 | ||
104 | /* Sanity-check. */ | |
105 | assert((len == 16) || (len == 32)); | |
106 | ||
107 | #ifdef CPUSUPPORT_X86_AESNI | |
108 | /* Use AESNI if we can. */ | |
109 | if (useaesni()) | |
110 | return (crypto_aes_key_expand_aesni(key, len)); | |
111 | #endif | |
112 | ||
113 | /* Allocate structure. */ | |
114 | if ((kexp = malloc(sizeof(AES_KEY))) == NULL) | |
115 | goto err0; | |
116 | ||
117 | /* Expand the key. */ | |
118 | AES_set_encrypt_key(key, (int)(len * 8), kexp); | |
119 | ||
120 | /* Success! */ | |
121 | return ((void *)kexp); | |
122 | ||
123 | err0: | |
124 | /* Failure! */ | |
125 | return (NULL); | |
126 | } | |
127 | ||
128 | /** | |
129 | * crypto_aes_encrypt_block(in, out, key): | |
130 | * Using the expanded AES key ${key}, encrypt the block ${in} and write the | |
131 | * resulting ciphertext to ${out}. | |
132 | */ | |
133 | void | |
134 | crypto_aes_encrypt_block(const uint8_t * in, uint8_t * out, | |
135 | const struct crypto_aes_key * key) | |
136 | { | |
137 | ||
138 | #ifdef CPUSUPPORT_X86_AESNI | |
139 | if (useaesni()) { | |
140 | crypto_aes_encrypt_block_aesni(in, out, (const void *)key); | |
141 | return; | |
142 | } | |
143 | #endif | |
144 | ||
145 | /* Get AES to do the work. */ | |
146 | AES_encrypt(in, out, (const void *)key); | |
147 | } | |
148 | ||
149 | /** | |
150 | * crypto_aes_key_free(key): | |
151 | * Free the expanded AES key ${key}. | |
152 | */ | |
153 | void | |
154 | crypto_aes_key_free(struct crypto_aes_key * key) | |
155 | { | |
156 | ||
157 | #ifdef CPUSUPPORT_X86_AESNI | |
158 | if (useaesni()) { | |
159 | crypto_aes_key_free_aesni((void *)key); | |
160 | return; | |
161 | } | |
162 | #endif | |
163 | ||
164 | /* Behave consistently with free(NULL). */ | |
165 | if (key == NULL) | |
166 | return; | |
167 | ||
168 | /* Attempt to zero the expanded key. */ | |
169 | insecure_memzero(key, sizeof(AES_KEY)); | |
170 | ||
171 | /* Free the key. */ | |
172 | free(key); | |
173 | } |