]>
Commit | Line | Data |
---|---|---|
3bfe9005 SL |
1 | /* |
2 | * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
e1178600 SL |
10 | /*- |
11 | * S390X support for AES CCM. | |
12 | * This file is included by cipher_ccm_hw.c | |
13 | */ | |
14 | ||
3bfe9005 SL |
15 | #define S390X_CCM_AAD_FLAG 0x40 |
16 | ||
e1178600 SL |
17 | static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx, |
18 | const unsigned char *key, size_t keylen) | |
3bfe9005 SL |
19 | { |
20 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
21 | ||
22 | sctx->ccm.s390x.fc = S390X_AES_FC(keylen); | |
23 | memcpy(&sctx->ccm.s390x.kmac.k, key, keylen); | |
24 | /* Store encoded m and l. */ | |
25 | sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7) | |
26 | | (((ctx->m - 2) >> 1) & 0x7) << 3; | |
27 | memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b)); | |
28 | sctx->ccm.s390x.blocks = 0; | |
29 | ctx->key_set = 1; | |
30 | return 1; | |
31 | } | |
32 | ||
33 | static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx, | |
34 | const unsigned char *nonce, size_t noncelen, | |
35 | size_t mlen) | |
36 | { | |
37 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
38 | ||
39 | sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG; | |
40 | sctx->ccm.s390x.nonce.g[1] = mlen; | |
41 | memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l); | |
42 | return 1; | |
43 | } | |
44 | ||
45 | /*- | |
46 | * Process additional authenticated data. Code is big-endian. | |
47 | */ | |
48 | static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx, | |
49 | const unsigned char *aad, size_t alen) | |
50 | { | |
51 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
52 | unsigned char *ptr; | |
53 | int i, rem; | |
54 | ||
55 | if (!alen) | |
56 | return 1; | |
57 | ||
58 | sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG; | |
59 | ||
60 | /* Suppress 'type-punned pointer dereference' warning. */ | |
61 | ptr = sctx->ccm.s390x.buf.b; | |
62 | ||
63 | if (alen < ((1 << 16) - (1 << 8))) { | |
64 | *(uint16_t *)ptr = alen; | |
65 | i = 2; | |
66 | } else if (sizeof(alen) == 8 | |
67 | && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) { | |
68 | *(uint16_t *)ptr = 0xffff; | |
69 | *(uint64_t *)(ptr + 2) = alen; | |
70 | i = 10; | |
71 | } else { | |
72 | *(uint16_t *)ptr = 0xfffe; | |
73 | *(uint32_t *)(ptr + 2) = alen; | |
74 | i = 6; | |
75 | } | |
76 | ||
77 | while (i < 16 && alen) { | |
78 | sctx->ccm.s390x.buf.b[i] = *aad; | |
79 | ++aad; | |
80 | --alen; | |
81 | ++i; | |
82 | } | |
83 | while (i < 16) { | |
84 | sctx->ccm.s390x.buf.b[i] = 0; | |
85 | ++i; | |
86 | } | |
87 | ||
88 | sctx->ccm.s390x.kmac.icv.g[0] = 0; | |
89 | sctx->ccm.s390x.kmac.icv.g[1] = 0; | |
90 | s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc, | |
91 | &sctx->ccm.s390x.kmac); | |
92 | sctx->ccm.s390x.blocks += 2; | |
93 | ||
94 | rem = alen & 0xf; | |
95 | alen &= ~(size_t)0xf; | |
96 | if (alen) { | |
97 | s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); | |
98 | sctx->ccm.s390x.blocks += alen >> 4; | |
99 | aad += alen; | |
100 | } | |
101 | if (rem) { | |
102 | for (i = 0; i < rem; i++) | |
103 | sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i]; | |
104 | ||
105 | s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, | |
106 | sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc, | |
107 | sctx->ccm.s390x.kmac.k); | |
108 | sctx->ccm.s390x.blocks++; | |
109 | } | |
110 | return 1; | |
111 | } | |
112 | ||
113 | /*- | |
114 | * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for | |
115 | * success. | |
116 | */ | |
117 | static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx, | |
118 | const unsigned char *in, | |
119 | unsigned char *out, size_t len, int enc) | |
120 | { | |
121 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
122 | size_t n, rem; | |
123 | unsigned int i, l, num; | |
124 | unsigned char flags; | |
125 | ||
126 | flags = sctx->ccm.s390x.nonce.b[0]; | |
127 | if (!(flags & S390X_CCM_AAD_FLAG)) { | |
128 | s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b, | |
129 | sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); | |
130 | sctx->ccm.s390x.blocks++; | |
131 | } | |
132 | l = flags & 0x7; | |
133 | sctx->ccm.s390x.nonce.b[0] = l; | |
134 | ||
135 | /*- | |
136 | * Reconstruct length from encoded length field | |
137 | * and initialize it with counter value. | |
138 | */ | |
139 | n = 0; | |
140 | for (i = 15 - l; i < 15; i++) { | |
141 | n |= sctx->ccm.s390x.nonce.b[i]; | |
142 | sctx->ccm.s390x.nonce.b[i] = 0; | |
143 | n <<= 8; | |
144 | } | |
145 | n |= sctx->ccm.s390x.nonce.b[15]; | |
146 | sctx->ccm.s390x.nonce.b[15] = 1; | |
147 | ||
148 | if (n != len) | |
149 | return 0; /* length mismatch */ | |
150 | ||
151 | if (enc) { | |
152 | /* Two operations per block plus one for tag encryption */ | |
153 | sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1; | |
154 | if (sctx->ccm.s390x.blocks > (1ULL << 61)) | |
155 | return 0; /* too much data */ | |
156 | } | |
157 | ||
158 | num = 0; | |
159 | rem = len & 0xf; | |
160 | len &= ~(size_t)0xf; | |
161 | ||
162 | if (enc) { | |
163 | /* mac-then-encrypt */ | |
164 | if (len) | |
165 | s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); | |
166 | if (rem) { | |
167 | for (i = 0; i < rem; i++) | |
168 | sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i]; | |
169 | ||
170 | s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, | |
171 | sctx->ccm.s390x.kmac.icv.b, | |
172 | sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); | |
173 | } | |
174 | ||
175 | CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, | |
176 | sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, | |
177 | &num, (ctr128_f)AES_ctr32_encrypt); | |
178 | } else { | |
179 | /* decrypt-then-mac */ | |
180 | CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, | |
181 | sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, | |
182 | &num, (ctr128_f)AES_ctr32_encrypt); | |
183 | ||
184 | if (len) | |
185 | s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); | |
186 | if (rem) { | |
187 | for (i = 0; i < rem; i++) | |
188 | sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i]; | |
189 | ||
190 | s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, | |
191 | sctx->ccm.s390x.kmac.icv.b, | |
192 | sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); | |
193 | } | |
194 | } | |
195 | /* encrypt tag */ | |
196 | for (i = 15 - l; i < 16; i++) | |
197 | sctx->ccm.s390x.nonce.b[i] = 0; | |
198 | ||
199 | s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b, | |
200 | sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); | |
201 | sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0]; | |
202 | sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1]; | |
203 | ||
204 | sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */ | |
205 | return 1; | |
206 | } | |
207 | ||
208 | ||
209 | static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx, | |
210 | unsigned char *tag, size_t tlen) | |
211 | { | |
212 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
213 | ||
214 | if (tlen > ctx->m) | |
215 | return 0; | |
216 | memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen); | |
217 | return 1; | |
218 | } | |
219 | ||
220 | static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx, | |
221 | const unsigned char *in, | |
222 | unsigned char *out, size_t len, | |
223 | unsigned char *tag, size_t taglen) | |
224 | { | |
225 | int rv; | |
226 | ||
227 | rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1); | |
228 | if (rv && tag != NULL) | |
229 | rv = s390x_aes_ccm_gettag(ctx, tag, taglen); | |
230 | return rv; | |
231 | } | |
232 | ||
233 | static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx, | |
234 | const unsigned char *in, | |
235 | unsigned char *out, size_t len, | |
236 | unsigned char *expected_tag, | |
237 | size_t taglen) | |
238 | { | |
239 | int rv = 0; | |
240 | PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; | |
241 | ||
242 | rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0); | |
243 | if (rv) { | |
244 | if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0) | |
245 | rv = 0; | |
246 | } | |
247 | if (rv == 0) | |
248 | OPENSSL_cleanse(out, len); | |
249 | return rv; | |
250 | } | |
251 | ||
252 | static const PROV_CCM_HW s390x_aes_ccm = { | |
e1178600 | 253 | s390x_aes_ccm_initkey, |
3bfe9005 SL |
254 | s390x_aes_ccm_setiv, |
255 | s390x_aes_ccm_setaad, | |
256 | s390x_aes_ccm_auth_encrypt, | |
257 | s390x_aes_ccm_auth_decrypt, | |
258 | s390x_aes_ccm_gettag | |
259 | }; | |
260 | ||
261 | const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits) | |
262 | { | |
263 | if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE) | |
264 | || (keybits == 192 && S390X_aes_192_ccm_CAPABLE) | |
265 | || (keybits == 256 && S390X_aes_256_ccm_CAPABLE)) | |
266 | return &s390x_aes_ccm; | |
267 | return &aes_ccm; | |
268 | } |