Initial commit
[authen-passphrase-scrypt.git] / scrypt-1.2.1 / libcperciva / crypto / crypto_aes.c
CommitLineData
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 */
21struct crypto_aes_key;
22
23#ifdef CPUSUPPORT_X86_AESNI
24/* Test whether OpenSSL and AESNI code produce the same AES ciphertext. */
25static int
26aesnitest(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
51err0:
52 /* Failure! */
53 return (-1);
54}
55
56/* Should we use AESNI? */
57static int
58useaesni(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 */
99struct crypto_aes_key *
100crypto_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
123err0:
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 */
133void
134crypto_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 */
153void
154crypto_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}
This page took 0.018304 seconds and 4 git commands to generate.