]> git.saurik.com Git - apple/xnu.git/blob - EXTERNAL_HEADERS/corecrypto/ccmode_siv.h
5d40c1dd13e5615485c489ae7c86893a076dd950
[apple/xnu.git] / EXTERNAL_HEADERS / corecrypto / ccmode_siv.h
1 /* Copyright (c) (2015,2016,2017,2018,2019) Apple Inc. All rights reserved.
2 *
3 * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
4 * is contained in the License.txt file distributed with corecrypto) and only to
5 * people who accept that license. IMPORTANT: Any license rights granted to you by
6 * Apple Inc. (if any) are limited to internal use within your organization only on
7 * devices and computers you own or control, for the sole purpose of verifying the
8 * security characteristics and correct functioning of the Apple Software. You may
9 * not, directly or indirectly, redistribute the Apple Software or any portions thereof.
10 */
11
12 #ifndef _CORECRYPTO_CCMODE_SIV_H_
13 #define _CORECRYPTO_CCMODE_SIV_H_
14
15 #include <corecrypto/cc.h>
16 #include <corecrypto/ccmode.h>
17 #include <corecrypto/ccmode_impl.h>
18
19 #include <corecrypto/cccmac.h>
20
21 /* This provide an implementation of SIV
22 as specified in https://tools.ietf.org/html/rfc5297
23 also in http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/siv/siv.pdf
24 Counter Mode where IV is based on CMAC
25 */
26
27 cc_aligned_struct(16) ccsiv_ctx;
28
29 struct ccmode_siv {
30 size_t size; /* first argument to ccsiv_ctx_decl(). */
31 size_t block_size;
32 int (*init)(const struct ccmode_siv *siv, ccsiv_ctx *ctx,
33 size_t key_len, const uint8_t *key);
34 int (*set_nonce)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in); // could just be ccm with NULL out
35 int (*auth)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in); // could just be ccm with NULL out
36 int (*crypt)(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in, uint8_t *out);
37 int (*reset)(ccsiv_ctx *ctx);
38 const struct ccmode_cbc *cbc;
39 const struct ccmode_ctr *ctr;
40 };
41
42 #define ccsiv_ctx_decl(_size_, _name_) cc_ctx_decl(ccsiv_ctx, _size_, _name_)
43 #define ccsiv_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
44
45 // Functions
46
47 CC_INLINE size_t ccsiv_context_size(const struct ccmode_siv *mode)
48 {
49 return mode->size;
50 }
51
52 /*!
53 @function ccsiv_block_size
54 @abstract Return the block_size = block_length = tag_length used in the mode.
55
56 @param mode ccsiv mode descriptor
57
58 @discussion Used to return the current block size of the SIV mode. Note that the tag in this mode is an output of the underlying blockcipher and therefore the tag length corresponds to the block size.
59 */
60 CC_INLINE size_t ccsiv_block_size(const struct ccmode_siv *mode)
61 {
62 return mode->block_size;
63 }
64
65 /*!
66 @function ccsiv_ciphertext_size
67 @abstract Return size of Ciphertext (which is the ciphertext and corresponding tag) given the mode and plaintext length
68
69 @param mode ccsiv mode descriptor
70 @param plaintext_size Size of the plaintext
71
72 @discussion returns the length of the aead ciphertext that the context will generate which includes both the encrypted plaintext and tag.
73 */
74 CC_INLINE size_t ccsiv_ciphertext_size(const struct ccmode_siv *mode,
75 size_t plaintext_size)
76 {
77 return plaintext_size + mode->cbc->block_size;
78 }
79
80 /*!
81 @function ccsiv_plaintext_size
82 @abstract Return size of plaintext given a ciphertext length and mode.
83
84 @param mode ccsiv mode descriptor
85 @param ciphertext_size Size of the ciphertext
86
87 @discussion returns the length of the plaintext which results from the decryption of a ciphertext of the corresponding size (here ciphertext size includes the tag).
88 */
89
90 CC_INLINE size_t ccsiv_plaintext_size(const struct ccmode_siv *mode,
91 size_t ciphertext_size)
92 {
93 if (ciphertext_size<mode->cbc->block_size) {
94 return 0; // error
95 }
96 return ciphertext_size - mode->cbc->block_size;
97 }
98
99 /*!
100 @function ccsiv_init
101 @abstract Initialize a context for ccsiv with an associated mode, and given key.
102
103 @param mode Descriptor for the mode
104 @param ctx Alocated context to be intialized
105 @param key_byte_len Length of the key: Supported key sizes are 32, 48, 64 bytes.
106 @param key key for siv. All bits of this key should be random. (See discussion)
107
108 @discussion In order to compute SIV_Enc_k(a1,...,am, n, x) where ai is the ith piece of associated data, n is a nonce and x is a plaintext, we use the following sequence of calls :
109
110
111 @code
112 ccsiv_init(...)
113 ccsiv_aad(...) (may be called zero or more times)
114 ccsiv_set_nonce(...)
115 ccsiv_crypt(...)
116 @endcode
117
118 To reuse the context for additional encryptions, follow this sequence:
119
120 @code
121 ccsiv_reset(...)
122 ccsiv_aad(...) (may be called zero or more times)
123 ccsiv_set_nonce(...)
124 ccsiv_crypt(...)
125 @endcode
126
127 Importantly, all the bits in the key need to be random. Duplicating a smaller key to achieve a longer key length will result in an insecure implementation.
128 */
129 CC_INLINE int ccsiv_init(const struct ccmode_siv *mode, ccsiv_ctx *ctx,
130 size_t key_byte_len, const uint8_t *key)
131 {
132 return mode->init(mode, ctx, key_byte_len, key);
133 }
134
135 /*!
136 @function ccsiv_set_nonce
137 @abstract Add the nonce to the siv's computation of the the tag. Changes the internal state of the context
138 so that after the call only a crypt or reset call is permitted.
139
140 @param mode Descriptor for the mode
141 @param ctx Intialized ctx
142 @param nbytes Length of the current nonce data being added
143 @param in Nonce data to be authenticated.
144
145 @discussion The nonce is a special form of authenticated data. If provided (a call to ccsiv_set_nonce is optional) it allows
146 randomization of the ciphertext (preventing deterministic encryption). While the length of the nonce is not limmited, the
147 amount of entropy that can be provided is limited by the number of bits in the block of the associated block-cipher.
148 */
149 CC_INLINE int ccsiv_set_nonce(const struct ccmode_siv *mode, ccsiv_ctx *ctx,
150 size_t nbytes, const uint8_t *in)
151 {
152 return mode->set_nonce(ctx, nbytes, in);
153 }
154
155 /*!
156 @function ccsiv_aad
157 @abstract Add the next piece of associated data to the SIV's computation of the tag.
158 @param mode Descriptor for the mode
159 @param ctx Intialized ctx
160 @param nbytes Length of the current associated data being added
161 @param in Associated data to be authenticated.
162
163 @discussion Adds the associated data given by in to the computation of the tag in the associated data. Note this call is optional and no associated data needs to be provided. Multiple pieces of associated data can be provided by multiple calls to this function. Note the associated data in this case is simply computed as the concatenation of all of the associated data inputs.
164 */
165 CC_INLINE int ccsiv_aad(const struct ccmode_siv *mode, ccsiv_ctx *ctx,
166 size_t nbytes, const uint8_t *in)
167 {
168 return mode->auth(ctx, nbytes, in);
169 }
170
171 /*!
172 @function ccsiv_crypt
173 @abstract Depdening on mode, 1) Encrypts a plaintext , or 2) Decrypts a ciphertext
174
175 @param mode Descriptor for the mode
176 @param ctx Intialized ctx
177 @param nbytes Case 1) Length of the current plaintext
178 Case 2) Length of the current ciphertext (block length + plaintext length).
179 @param in Case 1) Plaintext
180 Case 2) Ciphertext
181 @param out Case 1) Tag+ciphertext (buffer should be already allocated and of length block_length+plaintext_length.)
182 Case 2) Plaintext (buffer should be already allocated and of length ciphertext_length - block_length length
183
184 @discussion Depending on whether mode has been setup to encrypt or decrypt, this function
185 1) Encrypts the plaintext given as input in, and provides the ciphertext (which is a concatenation of the cbc-tag
186 followed by the encrypted plaintext) as output out. 2) Decrypts plaintext using the input ciphertext at in (which again is the cbc-tag, followed by encrypted plaintext), and then verifies that the computed tag and provided tags match.
187
188 This function is only called once. If one wishes to compute another (en)/(de)cryption, one resets the state with
189 ccsiv_reset, and then begins the process again. There is no way to stream large plaintext/ciphertext inputs into the
190 function.
191
192 In the case of a decryption, if there is a failure in verifying the computed tag against the provided tag (embedded int he ciphertext), then a decryption/verification
193 failure is returned, and any internally computed plaintexts and tags are zeroed out.
194 Lastly the contexts internal state is reset, so that a new decryption/encryption can be commenced.
195
196 Decryption can be done in place in memory by setting in=out. Encryption cannot be done in place. However, if one is trying to minimize memory usage one can set out = in - block_length, which results in the ciphertext being encrypted inplace, and the IV being prepended before the ciphertext.
197 */
198 CC_INLINE int ccsiv_crypt(const struct ccmode_siv *mode, ccsiv_ctx *ctx,
199 size_t nbytes, const uint8_t *in, uint8_t *out)
200 {
201 return mode->crypt(ctx, nbytes, in, out);
202 }
203
204 /*!
205 @function ccsiv_reset
206 @abstract Resets the state of the ccsiv_ctx ctx, maintaing the key, but preparing the
207 ctx to preform a new Associated Data Authenticated (En)/(De)cryption.
208 @param mode Descriptor for the mode
209 @param ctx Intialized ctx
210 */
211 CC_INLINE int ccsiv_reset(const struct ccmode_siv *mode, ccsiv_ctx *ctx)
212 {
213 return mode->reset(ctx);
214 }
215
216 /*!
217 @function ccsiv_one_shot
218 @abstract A simplified but more constrained way of performing a AES SIV (en)/(de)cryption. It is limited because only
219 one piece of associated data may be provided.
220
221 @param mode Descriptor for the mode
222 @param key_len Length of the key: Supported key sizes are 32, 48, 64 bytes
223 @param key key for siv
224 @param nonce_nbytes Length of the current nonce data being added
225 @param nonce Nonce data to be authenticated.
226 @param adata_nbytes Length of the associated data.
227 @param adata Associated data to be authenticated.
228 @param in_nbytes Length of either the plaintext (for encryption) or ciphertext (for decryption), in the latter case the length includes the length of the tag.
229 @param in Plaintext or ciphertext. Note that the ciphertext includes a tag of length tag_length prepended to it.
230 @param out Buffer to hold ciphertext/plaintext. (Note Ciphertext is of size plaintext_length + block_length and plaintext is of ciphertext_length - block_length, as the tag has the length of one block.
231 Must be the case that out<= in - block length || out>= in + plaintext_length
232
233 @discussion Decryption can be done in place in memory by setting in=out. Encryption cannot be done in place. However, is one is trying to minimize memory usage
234 one can set out = in - block_length, which results in the ciphertext being encrypted inplace, and the IV being prepended before the ciphertext.
235
236 Suppose the block length is 16 bytes long (AES) and plaintext of length 20, then we could set in = 16, out = 0 let the bytes of the plaintext be denoted as P_1...P_20
237 then memory is depicted as:
238 | 0 = ? | 1 = ? | ... | 15 = ? | 16 = P_1 | ... | 35 = P_20 |
239 | | | | |
240 V V V V V
241 |IV_1 | IV_2 | ... | IV_16 | C_1 | ... | C_20 |
242
243 Note that the ciphrtext itself is encrypted in place, but the IV prefixes the ciphertext.
244
245
246 */
247
248 CC_INLINE int ccsiv_one_shot(const struct ccmode_siv *mode,
249 size_t key_len, const uint8_t *key,
250 unsigned nonce_nbytes, const uint8_t* nonce,
251 unsigned adata_nbytes, const uint8_t* adata,
252 size_t in_nbytes, const uint8_t *in, uint8_t *out)
253 {
254 int rc;
255 ccsiv_ctx_decl(mode->size, ctx);
256 rc=mode->init(mode, ctx, key_len, key);
257 if (rc) {return rc;}
258 rc=mode->set_nonce(ctx, nonce_nbytes, nonce);
259 if (rc) {return rc;}
260 rc=mode->auth(ctx, adata_nbytes, adata);
261 if (rc) {return rc;}
262 rc=mode->crypt(ctx, in_nbytes, in, out);
263 if (rc) {return rc;}
264 ccsiv_ctx_clear(mode->size, ctx);
265 return rc;
266 }
267
268 #endif /* _CORECRYPTO_CCMODE_H_ */