3 XEX-based tweaked-codebook mode with ciphertext stealing (XTS)
5 Copyright (C) 2018 Red Hat, Inc.
7 This file is part of GNU Nettle.
9 GNU Nettle is free software: you can redistribute it and/or
10 modify it under the terms of either:
12 * the GNU Lesser General Public License as published by the Free
13 Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
18 * the GNU General Public License as published by the Free
19 Software Foundation; either version 2 of the License, or (at your
20 option) any later version.
22 or both in parallel, as here.
24 GNU Nettle is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received copies of the GNU General Public License and
30 the GNU Lesser General Public License along with this program. If
31 not, see http://www.gnu.org/licenses/.
46 #include "nettle-internal.h"
47 #include "block-internal.h"
50 check_length(size_t length, uint8_t *dst)
52 assert(length >= XTS_BLOCK_SIZE);
53 /* asserts may be compiled out, try to save the user by zeroing the dst in
54 * case the buffer contains sensitive data (like the clear text for inplace
56 if (length < XTS_BLOCK_SIZE)
57 memset(dst, '\0', length);
60 /* works also for inplace encryption/decryption */
63 xts_encrypt_message(const void *enc_ctx, const void *twk_ctx,
64 nettle_cipher_func *encf,
65 const uint8_t *tweak, size_t length,
66 uint8_t *dst, const uint8_t *src)
68 union nettle_block16 T;
69 union nettle_block16 P;
71 check_length(length, dst);
73 encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
75 /* the zeroth power of alpha is the initial ciphertext value itself, so we
76 * skip shifting and do it at the end of each block operation instead */
77 for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
78 length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
80 memxor3(P.b, src, T.b, XTS_BLOCK_SIZE); /* P -> PP */
81 encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b); /* CC */
82 memxor(dst, T.b, XTS_BLOCK_SIZE); /* CC -> C */
84 /* shift T for next block if any */
85 if (length > XTS_BLOCK_SIZE)
86 block16_mulx_le(&T, &T);
89 /* if the last block is partial, handle via stealing */
92 /* S Holds the real C(n-1) (Whole last block to steal from) */
93 union nettle_block16 S;
95 memxor3(P.b, src, T.b, XTS_BLOCK_SIZE); /* P -> PP */
96 encf(enc_ctx, XTS_BLOCK_SIZE, S.b, P.b); /* CC */
97 memxor(S.b, T.b, XTS_BLOCK_SIZE); /* CC -> S */
99 /* shift T for next block */
100 block16_mulx_le(&T, &T);
102 length -= XTS_BLOCK_SIZE;
103 src += XTS_BLOCK_SIZE;
105 memxor3(P.b, src, T.b, length); /* P |.. */
106 /* steal ciphertext to complete block */
107 memxor3(P.b + length, S.b + length, T.b + length,
108 XTS_BLOCK_SIZE - length); /* ..| S_2 -> PP */
110 encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b); /* CC */
111 memxor(dst, T.b, XTS_BLOCK_SIZE); /* CC -> C(n-1) */
113 /* Do this after we read src so inplace operations do not break */
114 dst += XTS_BLOCK_SIZE;
115 memcpy(dst, S.b, length); /* S_1 -> C(n) */
120 xts_decrypt_message(const void *dec_ctx, const void *twk_ctx,
121 nettle_cipher_func *decf, nettle_cipher_func *encf,
122 const uint8_t *tweak, size_t length,
123 uint8_t *dst, const uint8_t *src)
125 union nettle_block16 T;
126 union nettle_block16 C;
128 check_length(length, dst);
130 encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
132 for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
133 length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
135 memxor3(C.b, src, T.b, XTS_BLOCK_SIZE); /* c -> CC */
136 decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b); /* PP */
137 memxor(dst, T.b, XTS_BLOCK_SIZE); /* PP -> P */
139 /* shift T for next block if any */
140 if (length > XTS_BLOCK_SIZE)
141 block16_mulx_le(&T, &T);
144 /* if the last block is partial, handle via stealing */
147 union nettle_block16 T1;
148 /* S Holds the real P(n) (with part of stolen ciphertext) */
149 union nettle_block16 S;
151 /* we need the last T(n) and save the T(n-1) for later */
152 block16_mulx_le(&T1, &T);
154 memxor3(C.b, src, T1.b, XTS_BLOCK_SIZE); /* C -> CC */
155 decf(dec_ctx, XTS_BLOCK_SIZE, S.b, C.b); /* PP */
156 memxor(S.b, T1.b, XTS_BLOCK_SIZE); /* PP -> S */
158 /* process next block (Pn-1) */
159 length -= XTS_BLOCK_SIZE;
160 src += XTS_BLOCK_SIZE;
162 /* Prepare C, P holds the real P(n) */
163 memxor3(C.b, src, T.b, length); /* C_1 |.. */
164 memxor3(C.b + length, S.b + length, T.b + length,
165 XTS_BLOCK_SIZE - length); /* ..| S_2 -> CC */
166 decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b); /* PP */
167 memxor(dst, T.b, XTS_BLOCK_SIZE); /* PP -> P(n-1) */
169 /* Do this after we read src so inplace operations do not break */
170 dst += XTS_BLOCK_SIZE;
171 memcpy(dst, S.b, length); /* S_1 -> P(n) */