xref: /xnu-10002.61.3/EXTERNAL_HEADERS/corecrypto/ccmode_siv.h (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1 /* Copyright (c) (2015-2021) 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 (*CC_SPTR(ccmode_siv, init))(const struct ccmode_siv *siv, ccsiv_ctx *ctx,
33                  size_t key_len, const uint8_t *key);
34     int (*CC_SPTR(ccmode_siv, set_nonce))(ccsiv_ctx *ctx,  size_t nbytes, const uint8_t *in);  // could just be ccm with NULL out
35     int (*CC_SPTR(ccmode_siv, auth))(ccsiv_ctx *ctx,  size_t nbytes, const uint8_t *in);  // could just be ccm with NULL out
36     int (*CC_SPTR(ccmode_siv, crypt))(ccsiv_ctx *ctx, size_t nbytes, const uint8_t *in, uint8_t *out);
37     int (*CC_SPTR(ccmode_siv, 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_vla(ccsiv_ctx, _size_, _name_)
43 #define ccsiv_ctx_clear(_size_, _name_) cc_clear(_size_, _name_)
44 
45 // Functions
46 
ccsiv_context_size(const struct ccmode_siv * mode)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 */
ccsiv_block_size(const struct ccmode_siv * mode)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  */
ccsiv_ciphertext_size(const struct ccmode_siv * mode,size_t plaintext_size)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 
ccsiv_plaintext_size(const struct ccmode_siv * mode,size_t ciphertext_size)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  */
ccsiv_init(const struct ccmode_siv * mode,ccsiv_ctx * ctx,size_t key_byte_len,const uint8_t * key)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  */
ccsiv_set_nonce(const struct ccmode_siv * mode,ccsiv_ctx * ctx,size_t nbytes,const uint8_t * in)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  */
ccsiv_aad(const struct ccmode_siv * mode,ccsiv_ctx * ctx,size_t nbytes,const uint8_t * in)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  */
ccsiv_crypt(const struct ccmode_siv * mode,ccsiv_ctx * ctx,size_t nbytes,const uint8_t * in,uint8_t * out)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  */
ccsiv_reset(const struct ccmode_siv * mode,ccsiv_ctx * ctx)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 
ccsiv_one_shot(const struct ccmode_siv * mode,size_t key_len,const uint8_t * key,unsigned nonce_nbytes,const uint8_t * nonce,unsigned adata_nbytes,const uint8_t * adata,size_t in_nbytes,const uint8_t * in,uint8_t * out)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_ */
269