1 /* $OpenBSD: cts128.c,v 1.5 2015/07/19 18:27:26 miod Exp $ */
2 /* ====================================================================
3 * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
5 * Rights for redistribution and usage in source and binary
6 * forms are granted according to the OpenSSL license.
9 #include <openssl/crypto.h>
10 #include "modes_lcl.h"
20 * Trouble with Ciphertext Stealing, CTS, mode is that there is no
21 * common official specification, but couple of cipher/application
22 * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
23 * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
24 * deviates from mentioned RFCs. Most notably it allows input to be
25 * of block length and it doesn't flip the order of the last two
26 * blocks. CTS is being discussed even in ECB context, but it's not
27 * adopted for any known application. This implementation provides
28 * two interfaces: one compliant with above mentioned RFCs and one
29 * compliant with the NIST proposal, both extending CBC mode.
32 size_t CRYPTO_cts128_encrypt_block(const unsigned char *in
, unsigned char *out
,
33 size_t len
, const void *key
,
34 unsigned char ivec
[16], block128_f block
)
37 if (len
<= 16) return 0;
39 if ((residue
=len
%16) == 0) residue
= 16;
43 CRYPTO_cbc128_encrypt(in
,out
,len
,key
,ivec
,block
);
48 for (n
=0; n
<residue
; ++n
)
50 (*block
)(ivec
,ivec
,key
);
51 memcpy(out
,out
-16,residue
);
52 memcpy(out
-16,ivec
,16);
57 size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in
, unsigned char *out
,
58 size_t len
, const void *key
,
59 unsigned char ivec
[16], block128_f block
)
62 if (len
< 16) return 0;
68 CRYPTO_cbc128_encrypt(in
,out
,len
,key
,ivec
,block
);
70 if (residue
==0) return len
;
75 for (n
=0; n
<residue
; ++n
)
77 (*block
)(ivec
,ivec
,key
);
78 memcpy(out
-16+residue
,ivec
,16);
83 size_t CRYPTO_cts128_encrypt(const unsigned char *in
, unsigned char *out
,
84 size_t len
, const void *key
,
85 unsigned char ivec
[16], cbc128_f cbc
)
87 union { size_t align
; unsigned char c
[16]; } tmp
;
89 if (len
<= 16) return 0;
91 if ((residue
=len
%16) == 0) residue
= 16;
95 (*cbc
)(in
,out
,len
,key
,ivec
,1);
100 memset(tmp
.c
,0,sizeof(tmp
));
101 memcpy(tmp
.c
,in
,residue
);
102 memcpy(out
,out
-16,residue
);
103 (*cbc
)(tmp
.c
,out
-16,16,key
,ivec
,1);
107 size_t CRYPTO_nistcts128_encrypt(const unsigned char *in
, unsigned char *out
,
108 size_t len
, const void *key
,
109 unsigned char ivec
[16], cbc128_f cbc
)
111 union { size_t align
; unsigned char c
[16]; } tmp
;
113 if (len
< 16) return 0;
119 (*cbc
)(in
,out
,len
,key
,ivec
,1);
121 if (residue
==0) return len
;
126 memset(tmp
.c
,0,sizeof(tmp
));
127 memcpy(tmp
.c
,in
,residue
);
128 (*cbc
)(tmp
.c
,out
-16+residue
,16,key
,ivec
,1);
132 size_t CRYPTO_cts128_decrypt_block(const unsigned char *in
, unsigned char *out
,
133 size_t len
, const void *key
,
134 unsigned char ivec
[16], block128_f block
)
136 union { size_t align
; unsigned char c
[32]; } tmp
;
138 if (len
<=16) return 0;
140 if ((residue
=len
%16) == 0) residue
= 16;
145 CRYPTO_cbc128_decrypt(in
,out
,len
,key
,ivec
,block
);
150 (*block
)(in
,tmp
.c
+16,key
);
152 memcpy(tmp
.c
,tmp
.c
+16,16);
153 memcpy(tmp
.c
,in
+16,residue
);
154 (*block
)(tmp
.c
,tmp
.c
,key
);
156 for(n
=0; n
<16; ++n
) {
157 unsigned char c
= in
[n
];
158 out
[n
] = tmp
.c
[n
] ^ ivec
[n
];
161 for(residue
+=16; n
<residue
; ++n
)
162 out
[n
] = tmp
.c
[n
] ^ in
[n
];
164 return 16+len
+residue
;
167 size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in
, unsigned char *out
,
168 size_t len
, const void *key
,
169 unsigned char ivec
[16], block128_f block
)
171 union { size_t align
; unsigned char c
[32]; } tmp
;
173 if (len
<16) return 0;
178 CRYPTO_cbc128_decrypt(in
,out
,len
,key
,ivec
,block
);
185 CRYPTO_cbc128_decrypt(in
,out
,len
,key
,ivec
,block
);
190 (*block
)(in
+residue
,tmp
.c
+16,key
);
192 memcpy(tmp
.c
,tmp
.c
+16,16);
193 memcpy(tmp
.c
,in
,residue
);
194 (*block
)(tmp
.c
,tmp
.c
,key
);
196 for(n
=0; n
<16; ++n
) {
197 unsigned char c
= in
[n
];
198 out
[n
] = tmp
.c
[n
] ^ ivec
[n
];
199 ivec
[n
] = in
[n
+residue
];
202 for(residue
+=16; n
<residue
; ++n
)
203 out
[n
] = tmp
.c
[n
] ^ tmp
.c
[n
-16];
205 return 16+len
+residue
;
208 size_t CRYPTO_cts128_decrypt(const unsigned char *in
, unsigned char *out
,
209 size_t len
, const void *key
,
210 unsigned char ivec
[16], cbc128_f cbc
)
212 union { size_t align
; unsigned char c
[32]; } tmp
;
214 if (len
<=16) return 0;
216 if ((residue
=len
%16) == 0) residue
= 16;
221 (*cbc
)(in
,out
,len
,key
,ivec
,0);
226 memset(tmp
.c
,0,sizeof(tmp
));
227 /* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
228 (*cbc
)(in
,tmp
.c
,16,key
,tmp
.c
+16,0);
230 memcpy(tmp
.c
,in
+16,residue
);
231 (*cbc
)(tmp
.c
,tmp
.c
,32,key
,ivec
,0);
232 memcpy(out
,tmp
.c
,16+residue
);
233 return 16+len
+residue
;
236 size_t CRYPTO_nistcts128_decrypt(const unsigned char *in
, unsigned char *out
,
237 size_t len
, const void *key
,
238 unsigned char ivec
[16], cbc128_f cbc
)
240 union { size_t align
; unsigned char c
[32]; } tmp
;
242 if (len
<16) return 0;
247 (*cbc
)(in
,out
,len
,key
,ivec
,0);
254 (*cbc
)(in
,out
,len
,key
,ivec
,0);
259 memset(tmp
.c
,0,sizeof(tmp
));
260 /* this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] */
261 (*cbc
)(in
+residue
,tmp
.c
,16,key
,tmp
.c
+16,0);
263 memcpy(tmp
.c
,in
,residue
);
264 (*cbc
)(tmp
.c
,tmp
.c
,32,key
,ivec
,0);
265 memcpy(out
,tmp
.c
,16+residue
);
266 return 16+len
+residue
;