xts.c
Go to the documentation of this file.
1 /**
2  * @file xts.c
3  * @brief XEX-based tweaked-codebook mode with ciphertext stealing (XTS)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * XTS is a tweakable block cipher designed for encryption of sector-based
30  * storage. Refer to IEEE Std 1619 and SP 800-38E for more details
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.4.0
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/crypto.h"
41 #include "cipher_modes/xts.h"
42 #include "debug.h"
43 
44 //Check crypto library configuration
45 #if (XTS_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Initialize XTS context
50  * @param[in] context Pointer to the XTS context
51  * @param[in] cipherAlgo Cipher algorithm
52  * @param[in] key Pointer to the key
53  * @param[in] keyLen Length of the key
54  * @return Error code
55  **/
56 
57 error_t xtsInit(XtsContext *context, const CipherAlgo *cipherAlgo,
58  const void *key, size_t keyLen)
59 {
60  error_t error;
61  const uint8_t *k1;
62  const uint8_t *k2;
63 
64  //XTS supports only symmetric block ciphers whose block size is 128 bits
65  if(cipherAlgo->type != CIPHER_ALGO_TYPE_BLOCK || cipherAlgo->blockSize != 16)
67 
68  //Invalid key length?
69  if(keyLen != 32 && keyLen != 64)
71 
72  //Cipher algorithm used to perform XTS encryption/decryption
73  context->cipherAlgo = cipherAlgo;
74 
75  //The key is parsed as a concatenation of 2 fields of equal size called K1 and K2
76  k1 = (uint8_t *) key;
77  k2 = (uint8_t *) key + (keyLen / 2);
78 
79  //Initialize first cipher context using K1
80  error = cipherAlgo->init(&context->cipherContext1, k1, keyLen / 2);
81  //Any error to report?
82  if(error)
83  return error;
84 
85  //Initialize second cipher context using K2
86  error = cipherAlgo->init(&context->cipherContext2, k2, keyLen / 2);
87  //Any error to report?
88  if(error)
89  return error;
90 
91  //Successful initialization
92  return NO_ERROR;
93 }
94 
95 
96 /**
97  * @brief Encrypt a data unit using XTS
98  * @param[in] context Pointer to the XTS context
99  * @param[in] i Value of the 128-bit tweak
100  * @param[in] p Pointer to the data unit to be encrypted (plaintext)
101  * @param[out] c Pointer to the resulting data unit (ciphertext)
102  * @param[in] length Length of the data unit, in bytes
103  * @return Error code
104  **/
105 
106 error_t xtsEncrypt(XtsContext *context, const uint8_t *i, const uint8_t *p,
107  uint8_t *c, size_t length)
108 {
109  uint8_t t[16];
110  uint8_t x[16];
111 
112  //The data unit size shall be at least 128 bits
113  if(length < 16)
115 
116  //Encrypt the tweak using K2
117  context->cipherAlgo->encryptBlock(&context->cipherContext2, i, t);
118 
119  //XTS mode operates in a block-by-block fashion
120  while(length >= 16)
121  {
122  //Merge the tweak into the input block
123  xtsXorBlock(x, p, t);
124  //Encrypt the block using K1
125  context->cipherAlgo->encryptBlock(&context->cipherContext1, x, x);
126  //Merge the tweak into the output block
127  xtsXorBlock(c, x, t);
128 
129  //Multiply T by x in GF(2^128)
130  xtsMul(t, t);
131 
132  //Next block
133  p += 16;
134  c += 16;
135  length -= 16;
136  }
137 
138  //Any partial block?
139  if(length > 0)
140  {
141  //Copy the final ciphertext bytes
142  osMemcpy(c, c - 16, length);
143  //Copy the final plaintext bytes
144  osMemcpy(x, p, length);
145  //Steal ciphertext to complete the block
146  osMemcpy(x + length, c + length - 16, 16 - length);
147 
148  //Merge the tweak into the input block
149  xtsXorBlock(x, x, t);
150  //Encrypt the final block using K1
151  context->cipherAlgo->encryptBlock(&context->cipherContext1, x, x);
152  //Merge the tweak into the output block
153  xtsXorBlock(c - 16, x, t);
154  }
155 
156  //Successful processing
157  return NO_ERROR;
158 }
159 
160 
161 /**
162  * @brief Decrypt a data unit using XTS
163  * @param[in] context Pointer to the XTS context
164  * @param[in] i Value of the 128-bit tweak
165  * @param[in] c Pointer to the data unit to be decrypted (ciphertext)
166  * @param[out] p Pointer to the resulting data unit (plaintext)
167  * @param[in] length Length of the data unit, in bytes
168  * @return Error code
169  **/
170 
171 error_t xtsDecrypt(XtsContext *context, const uint8_t *i, const uint8_t *c,
172  uint8_t *p, size_t length)
173 {
174  uint8_t t[16];
175  uint8_t x[16];
176 
177  //The data unit size shall be at least 128 bits
178  if(length < 16)
180 
181  //Encrypt the tweak using K2
182  context->cipherAlgo->encryptBlock(&context->cipherContext2, i, t);
183 
184  //XTS mode operates in a block-by-block fashion
185  while(length >= 32)
186  {
187  //Merge the tweak into the input block
188  xtsXorBlock(x, c, t);
189  //Decrypt the block using K1
190  context->cipherAlgo->decryptBlock(&context->cipherContext1, x, x);
191  //Merge the tweak into the output block
192  xtsXorBlock(p, x, t);
193 
194  //Multiply T by x in GF(2^128)
195  xtsMul(t, t);
196 
197  //Next block
198  c += 16;
199  p += 16;
200  length -= 16;
201  }
202 
203  //Any partial block?
204  if(length > 16)
205  {
206  uint8_t tt[16];
207 
208  //Multiply T by x in GF(2^128)
209  xtsMul(tt, t);
210 
211  //Merge the tweak into the input block
212  xtsXorBlock(x, c, tt);
213  //Decrypt the next-to-last block using K1
214  context->cipherAlgo->decryptBlock(&context->cipherContext1, x, x);
215  //Merge the tweak into the output block
216  xtsXorBlock(p, x, tt);
217 
218  //Retrieve the length of the final block
219  length -= 16;
220 
221  //Copy the final plaintext bytes
222  osMemcpy(p + 16, p, length);
223  //Copy the final ciphertext bytes
224  osMemcpy(x, c + 16, length);
225  //Steal ciphertext to complete the block
226  osMemcpy(x + length, p + length, 16 - length);
227  }
228  else
229  {
230  //The last block contains exactly 128 bits
231  osMemcpy(x, c, 16);
232  }
233 
234  //Merge the tweak into the input block
235  xtsXorBlock(x, x, t);
236  //Decrypt the final block using K1
237  context->cipherAlgo->decryptBlock(&context->cipherContext1, x, x);
238  //Merge the tweak into the output block
239  xtsXorBlock(p, x, t);
240 
241  //Successful processing
242  return NO_ERROR;
243 }
244 
245 
246 /**
247  * @brief Multiplication by x in GF(2^128)
248  * @param[out] x Pointer to the output block
249  * @param[out] a Pointer to the input block
250  **/
251 
252 void xtsMul(uint8_t *x, const uint8_t *a)
253 {
254  size_t i;
255  uint8_t c;
256 
257  //Save the value of the most significant bit
258  c = a[15] >> 7;
259 
260  //The multiplication of a polynomial by x in GF(2^128) corresponds to a
261  //shift of indices
262  for(i = 15; i > 0; i--)
263  {
264  x[i] = (a[i] << 1) | (a[i - 1] >> 7);
265  }
266 
267  //Shift the first byte of the block
268  x[0] = a[0] << 1;
269 
270  //If the highest term of the result is equal to one, then perform reduction
271  x[0] ^= 0x87 & ~(c - 1);
272 }
273 
274 
275 /**
276  * @brief XOR operation
277  * @param[out] x Block resulting from the XOR operation
278  * @param[in] a First input block
279  * @param[in] b Second input block
280  **/
281 
282 void xtsXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b)
283 {
284  size_t i;
285 
286  //Perform XOR operation
287  for(i = 0; i < 16; i++)
288  {
289  x[i] = a[i] ^ b[i];
290  }
291 }
292 
293 #endif
General definitions for cryptographic algorithms.
@ CIPHER_ALGO_TYPE_BLOCK
Definition: crypto.h:932
Debugging facilities.
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
uint8_t x
Definition: lldp_ext_med.h:211
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t b
Definition: nbns_common.h:104
uint8_t c
Definition: ndp.h:514
uint8_t p
Definition: ndp.h:300
uint8_t a
Definition: ndp.h:411
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
Common interface for encryption algorithms.
Definition: crypto.h:1036
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1044
CipherAlgoDecryptBlock decryptBlock
Definition: crypto.h:1045
size_t blockSize
Definition: crypto.h:1040
CipherAlgoInit init
Definition: crypto.h:1041
CipherAlgoType type
Definition: crypto.h:1039
XTS context.
Definition: xts.h:49
CipherContext cipherContext2
Definition: xts.h:52
const CipherAlgo * cipherAlgo
Definition: xts.h:50
CipherContext cipherContext1
Definition: xts.h:51
uint8_t length
Definition: tcp.h:368
error_t xtsDecrypt(XtsContext *context, const uint8_t *i, const uint8_t *c, uint8_t *p, size_t length)
Decrypt a data unit using XTS.
Definition: xts.c:171
void xtsXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b)
XOR operation.
Definition: xts.c:282
error_t xtsEncrypt(XtsContext *context, const uint8_t *i, const uint8_t *p, uint8_t *c, size_t length)
Encrypt a data unit using XTS.
Definition: xts.c:106
error_t xtsInit(XtsContext *context, const CipherAlgo *cipherAlgo, const void *key, size_t keyLen)
Initialize XTS context.
Definition: xts.c:57
void xtsMul(uint8_t *x, const uint8_t *a)
Multiplication by x in GF(2^128)
Definition: xts.c:252
XEX-based tweaked-codebook mode with ciphertext stealing (XTS)