1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <string.h> 11e1051a39Sopenharmony_ci#include <openssl/crypto.h> 12e1051a39Sopenharmony_ci#include "crypto/modes.h" 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_ci/* 15e1051a39Sopenharmony_ci * Trouble with Ciphertext Stealing, CTS, mode is that there is no 16e1051a39Sopenharmony_ci * common official specification, but couple of cipher/application 17e1051a39Sopenharmony_ci * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to 18e1051a39Sopenharmony_ci * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which 19e1051a39Sopenharmony_ci * deviates from mentioned RFCs. Most notably it allows input to be 20e1051a39Sopenharmony_ci * of block length and it doesn't flip the order of the last two 21e1051a39Sopenharmony_ci * blocks. CTS is being discussed even in ECB context, but it's not 22e1051a39Sopenharmony_ci * adopted for any known application. This implementation provides 23e1051a39Sopenharmony_ci * two interfaces: one compliant with above mentioned RFCs and one 24e1051a39Sopenharmony_ci * compliant with the NIST proposal, both extending CBC mode. 25e1051a39Sopenharmony_ci */ 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_cisize_t CRYPTO_cts128_encrypt_block(const unsigned char *in, 28e1051a39Sopenharmony_ci unsigned char *out, size_t len, 29e1051a39Sopenharmony_ci const void *key, unsigned char ivec[16], 30e1051a39Sopenharmony_ci block128_f block) 31e1051a39Sopenharmony_ci{ 32e1051a39Sopenharmony_ci size_t residue, n; 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_ci if (len <= 16) 35e1051a39Sopenharmony_ci return 0; 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_ci if ((residue = len % 16) == 0) 38e1051a39Sopenharmony_ci residue = 16; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ci len -= residue; 41e1051a39Sopenharmony_ci 42e1051a39Sopenharmony_ci CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_ci in += len; 45e1051a39Sopenharmony_ci out += len; 46e1051a39Sopenharmony_ci 47e1051a39Sopenharmony_ci for (n = 0; n < residue; ++n) 48e1051a39Sopenharmony_ci ivec[n] ^= in[n]; 49e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 50e1051a39Sopenharmony_ci memcpy(out, out - 16, residue); 51e1051a39Sopenharmony_ci memcpy(out - 16, ivec, 16); 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_ci return len + residue; 54e1051a39Sopenharmony_ci} 55e1051a39Sopenharmony_ci 56e1051a39Sopenharmony_cisize_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, 57e1051a39Sopenharmony_ci unsigned char *out, size_t len, 58e1051a39Sopenharmony_ci const void *key, 59e1051a39Sopenharmony_ci unsigned char ivec[16], 60e1051a39Sopenharmony_ci block128_f block) 61e1051a39Sopenharmony_ci{ 62e1051a39Sopenharmony_ci size_t residue, n; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci if (len < 16) 65e1051a39Sopenharmony_ci return 0; 66e1051a39Sopenharmony_ci 67e1051a39Sopenharmony_ci residue = len % 16; 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci len -= residue; 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_ci CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block); 72e1051a39Sopenharmony_ci 73e1051a39Sopenharmony_ci if (residue == 0) 74e1051a39Sopenharmony_ci return len; 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ci in += len; 77e1051a39Sopenharmony_ci out += len; 78e1051a39Sopenharmony_ci 79e1051a39Sopenharmony_ci for (n = 0; n < residue; ++n) 80e1051a39Sopenharmony_ci ivec[n] ^= in[n]; 81e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 82e1051a39Sopenharmony_ci memcpy(out - 16 + residue, ivec, 16); 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci return len + residue; 85e1051a39Sopenharmony_ci} 86e1051a39Sopenharmony_ci 87e1051a39Sopenharmony_cisize_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, 88e1051a39Sopenharmony_ci size_t len, const void *key, 89e1051a39Sopenharmony_ci unsigned char ivec[16], cbc128_f cbc) 90e1051a39Sopenharmony_ci{ 91e1051a39Sopenharmony_ci size_t residue; 92e1051a39Sopenharmony_ci union { 93e1051a39Sopenharmony_ci size_t align; 94e1051a39Sopenharmony_ci unsigned char c[16]; 95e1051a39Sopenharmony_ci } tmp; 96e1051a39Sopenharmony_ci 97e1051a39Sopenharmony_ci if (len <= 16) 98e1051a39Sopenharmony_ci return 0; 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_ci if ((residue = len % 16) == 0) 101e1051a39Sopenharmony_ci residue = 16; 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_ci len -= residue; 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ci (*cbc) (in, out, len, key, ivec, 1); 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_ci in += len; 108e1051a39Sopenharmony_ci out += len; 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_ci#if defined(CBC_HANDLES_TRUNCATED_IO) 111e1051a39Sopenharmony_ci memcpy(tmp.c, out - 16, 16); 112e1051a39Sopenharmony_ci (*cbc) (in, out - 16, residue, key, ivec, 1); 113e1051a39Sopenharmony_ci memcpy(out, tmp.c, residue); 114e1051a39Sopenharmony_ci#else 115e1051a39Sopenharmony_ci memset(tmp.c, 0, sizeof(tmp)); 116e1051a39Sopenharmony_ci memcpy(tmp.c, in, residue); 117e1051a39Sopenharmony_ci memcpy(out, out - 16, residue); 118e1051a39Sopenharmony_ci (*cbc) (tmp.c, out - 16, 16, key, ivec, 1); 119e1051a39Sopenharmony_ci#endif 120e1051a39Sopenharmony_ci return len + residue; 121e1051a39Sopenharmony_ci} 122e1051a39Sopenharmony_ci 123e1051a39Sopenharmony_cisize_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out, 124e1051a39Sopenharmony_ci size_t len, const void *key, 125e1051a39Sopenharmony_ci unsigned char ivec[16], cbc128_f cbc) 126e1051a39Sopenharmony_ci{ 127e1051a39Sopenharmony_ci size_t residue; 128e1051a39Sopenharmony_ci union { 129e1051a39Sopenharmony_ci size_t align; 130e1051a39Sopenharmony_ci unsigned char c[16]; 131e1051a39Sopenharmony_ci } tmp; 132e1051a39Sopenharmony_ci 133e1051a39Sopenharmony_ci if (len < 16) 134e1051a39Sopenharmony_ci return 0; 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ci residue = len % 16; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci len -= residue; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci (*cbc) (in, out, len, key, ivec, 1); 141e1051a39Sopenharmony_ci 142e1051a39Sopenharmony_ci if (residue == 0) 143e1051a39Sopenharmony_ci return len; 144e1051a39Sopenharmony_ci 145e1051a39Sopenharmony_ci in += len; 146e1051a39Sopenharmony_ci out += len; 147e1051a39Sopenharmony_ci 148e1051a39Sopenharmony_ci#if defined(CBC_HANDLES_TRUNCATED_IO) 149e1051a39Sopenharmony_ci (*cbc) (in, out - 16 + residue, residue, key, ivec, 1); 150e1051a39Sopenharmony_ci#else 151e1051a39Sopenharmony_ci memset(tmp.c, 0, sizeof(tmp)); 152e1051a39Sopenharmony_ci memcpy(tmp.c, in, residue); 153e1051a39Sopenharmony_ci (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1); 154e1051a39Sopenharmony_ci#endif 155e1051a39Sopenharmony_ci return len + residue; 156e1051a39Sopenharmony_ci} 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_cisize_t CRYPTO_cts128_decrypt_block(const unsigned char *in, 159e1051a39Sopenharmony_ci unsigned char *out, size_t len, 160e1051a39Sopenharmony_ci const void *key, unsigned char ivec[16], 161e1051a39Sopenharmony_ci block128_f block) 162e1051a39Sopenharmony_ci{ 163e1051a39Sopenharmony_ci size_t residue, n; 164e1051a39Sopenharmony_ci union { 165e1051a39Sopenharmony_ci size_t align; 166e1051a39Sopenharmony_ci unsigned char c[32]; 167e1051a39Sopenharmony_ci } tmp; 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci if (len <= 16) 170e1051a39Sopenharmony_ci return 0; 171e1051a39Sopenharmony_ci 172e1051a39Sopenharmony_ci if ((residue = len % 16) == 0) 173e1051a39Sopenharmony_ci residue = 16; 174e1051a39Sopenharmony_ci 175e1051a39Sopenharmony_ci len -= 16 + residue; 176e1051a39Sopenharmony_ci 177e1051a39Sopenharmony_ci if (len) { 178e1051a39Sopenharmony_ci CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 179e1051a39Sopenharmony_ci in += len; 180e1051a39Sopenharmony_ci out += len; 181e1051a39Sopenharmony_ci } 182e1051a39Sopenharmony_ci 183e1051a39Sopenharmony_ci (*block) (in, tmp.c + 16, key); 184e1051a39Sopenharmony_ci 185e1051a39Sopenharmony_ci memcpy(tmp.c, tmp.c + 16, 16); 186e1051a39Sopenharmony_ci memcpy(tmp.c, in + 16, residue); 187e1051a39Sopenharmony_ci (*block) (tmp.c, tmp.c, key); 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_ci for (n = 0; n < 16; ++n) { 190e1051a39Sopenharmony_ci unsigned char c = in[n]; 191e1051a39Sopenharmony_ci out[n] = tmp.c[n] ^ ivec[n]; 192e1051a39Sopenharmony_ci ivec[n] = c; 193e1051a39Sopenharmony_ci } 194e1051a39Sopenharmony_ci for (residue += 16; n < residue; ++n) 195e1051a39Sopenharmony_ci out[n] = tmp.c[n] ^ in[n]; 196e1051a39Sopenharmony_ci 197e1051a39Sopenharmony_ci return 16 + len + residue; 198e1051a39Sopenharmony_ci} 199e1051a39Sopenharmony_ci 200e1051a39Sopenharmony_cisize_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, 201e1051a39Sopenharmony_ci unsigned char *out, size_t len, 202e1051a39Sopenharmony_ci const void *key, 203e1051a39Sopenharmony_ci unsigned char ivec[16], 204e1051a39Sopenharmony_ci block128_f block) 205e1051a39Sopenharmony_ci{ 206e1051a39Sopenharmony_ci size_t residue, n; 207e1051a39Sopenharmony_ci union { 208e1051a39Sopenharmony_ci size_t align; 209e1051a39Sopenharmony_ci unsigned char c[32]; 210e1051a39Sopenharmony_ci } tmp; 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci if (len < 16) 213e1051a39Sopenharmony_ci return 0; 214e1051a39Sopenharmony_ci 215e1051a39Sopenharmony_ci residue = len % 16; 216e1051a39Sopenharmony_ci 217e1051a39Sopenharmony_ci if (residue == 0) { 218e1051a39Sopenharmony_ci CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 219e1051a39Sopenharmony_ci return len; 220e1051a39Sopenharmony_ci } 221e1051a39Sopenharmony_ci 222e1051a39Sopenharmony_ci len -= 16 + residue; 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_ci if (len) { 225e1051a39Sopenharmony_ci CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block); 226e1051a39Sopenharmony_ci in += len; 227e1051a39Sopenharmony_ci out += len; 228e1051a39Sopenharmony_ci } 229e1051a39Sopenharmony_ci 230e1051a39Sopenharmony_ci (*block) (in + residue, tmp.c + 16, key); 231e1051a39Sopenharmony_ci 232e1051a39Sopenharmony_ci memcpy(tmp.c, tmp.c + 16, 16); 233e1051a39Sopenharmony_ci memcpy(tmp.c, in, residue); 234e1051a39Sopenharmony_ci (*block) (tmp.c, tmp.c, key); 235e1051a39Sopenharmony_ci 236e1051a39Sopenharmony_ci for (n = 0; n < 16; ++n) { 237e1051a39Sopenharmony_ci unsigned char c = in[n]; 238e1051a39Sopenharmony_ci out[n] = tmp.c[n] ^ ivec[n]; 239e1051a39Sopenharmony_ci ivec[n] = in[n + residue]; 240e1051a39Sopenharmony_ci tmp.c[n] = c; 241e1051a39Sopenharmony_ci } 242e1051a39Sopenharmony_ci for (residue += 16; n < residue; ++n) 243e1051a39Sopenharmony_ci out[n] = tmp.c[n] ^ tmp.c[n - 16]; 244e1051a39Sopenharmony_ci 245e1051a39Sopenharmony_ci return 16 + len + residue; 246e1051a39Sopenharmony_ci} 247e1051a39Sopenharmony_ci 248e1051a39Sopenharmony_cisize_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, 249e1051a39Sopenharmony_ci size_t len, const void *key, 250e1051a39Sopenharmony_ci unsigned char ivec[16], cbc128_f cbc) 251e1051a39Sopenharmony_ci{ 252e1051a39Sopenharmony_ci size_t residue; 253e1051a39Sopenharmony_ci union { 254e1051a39Sopenharmony_ci size_t align; 255e1051a39Sopenharmony_ci unsigned char c[32]; 256e1051a39Sopenharmony_ci } tmp; 257e1051a39Sopenharmony_ci 258e1051a39Sopenharmony_ci if (len <= 16) 259e1051a39Sopenharmony_ci return 0; 260e1051a39Sopenharmony_ci 261e1051a39Sopenharmony_ci if ((residue = len % 16) == 0) 262e1051a39Sopenharmony_ci residue = 16; 263e1051a39Sopenharmony_ci 264e1051a39Sopenharmony_ci len -= 16 + residue; 265e1051a39Sopenharmony_ci 266e1051a39Sopenharmony_ci if (len) { 267e1051a39Sopenharmony_ci (*cbc) (in, out, len, key, ivec, 0); 268e1051a39Sopenharmony_ci in += len; 269e1051a39Sopenharmony_ci out += len; 270e1051a39Sopenharmony_ci } 271e1051a39Sopenharmony_ci 272e1051a39Sopenharmony_ci memset(tmp.c, 0, sizeof(tmp)); 273e1051a39Sopenharmony_ci /* 274e1051a39Sopenharmony_ci * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 275e1051a39Sopenharmony_ci */ 276e1051a39Sopenharmony_ci (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0); 277e1051a39Sopenharmony_ci 278e1051a39Sopenharmony_ci memcpy(tmp.c, in + 16, residue); 279e1051a39Sopenharmony_ci#if defined(CBC_HANDLES_TRUNCATED_IO) 280e1051a39Sopenharmony_ci (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 281e1051a39Sopenharmony_ci#else 282e1051a39Sopenharmony_ci (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 283e1051a39Sopenharmony_ci memcpy(out, tmp.c, 16 + residue); 284e1051a39Sopenharmony_ci#endif 285e1051a39Sopenharmony_ci return 16 + len + residue; 286e1051a39Sopenharmony_ci} 287e1051a39Sopenharmony_ci 288e1051a39Sopenharmony_cisize_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, 289e1051a39Sopenharmony_ci size_t len, const void *key, 290e1051a39Sopenharmony_ci unsigned char ivec[16], cbc128_f cbc) 291e1051a39Sopenharmony_ci{ 292e1051a39Sopenharmony_ci size_t residue; 293e1051a39Sopenharmony_ci union { 294e1051a39Sopenharmony_ci size_t align; 295e1051a39Sopenharmony_ci unsigned char c[32]; 296e1051a39Sopenharmony_ci } tmp; 297e1051a39Sopenharmony_ci 298e1051a39Sopenharmony_ci if (len < 16) 299e1051a39Sopenharmony_ci return 0; 300e1051a39Sopenharmony_ci 301e1051a39Sopenharmony_ci residue = len % 16; 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci if (residue == 0) { 304e1051a39Sopenharmony_ci (*cbc) (in, out, len, key, ivec, 0); 305e1051a39Sopenharmony_ci return len; 306e1051a39Sopenharmony_ci } 307e1051a39Sopenharmony_ci 308e1051a39Sopenharmony_ci len -= 16 + residue; 309e1051a39Sopenharmony_ci 310e1051a39Sopenharmony_ci if (len) { 311e1051a39Sopenharmony_ci (*cbc) (in, out, len, key, ivec, 0); 312e1051a39Sopenharmony_ci in += len; 313e1051a39Sopenharmony_ci out += len; 314e1051a39Sopenharmony_ci } 315e1051a39Sopenharmony_ci 316e1051a39Sopenharmony_ci memset(tmp.c, 0, sizeof(tmp)); 317e1051a39Sopenharmony_ci /* 318e1051a39Sopenharmony_ci * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0] 319e1051a39Sopenharmony_ci */ 320e1051a39Sopenharmony_ci (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0); 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ci memcpy(tmp.c, in, residue); 323e1051a39Sopenharmony_ci#if defined(CBC_HANDLES_TRUNCATED_IO) 324e1051a39Sopenharmony_ci (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0); 325e1051a39Sopenharmony_ci#else 326e1051a39Sopenharmony_ci (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0); 327e1051a39Sopenharmony_ci memcpy(out, tmp.c, 16 + residue); 328e1051a39Sopenharmony_ci#endif 329e1051a39Sopenharmony_ci return 16 + len + residue; 330e1051a39Sopenharmony_ci} 331