1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2008-2021 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#if defined(__GNUC__) && !defined(STRICT_ALIGNMENT) 15e1051a39Sopenharmony_citypedef size_t size_t_aX __attribute((__aligned__(1))); 16e1051a39Sopenharmony_ci#else 17e1051a39Sopenharmony_citypedef size_t size_t_aX; 18e1051a39Sopenharmony_ci#endif 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_ci/* 21e1051a39Sopenharmony_ci * The input and output encrypted as though 128bit cfb mode is being used. 22e1051a39Sopenharmony_ci * The extra state information to record how much of the 128bit block we have 23e1051a39Sopenharmony_ci * used is contained in *num; 24e1051a39Sopenharmony_ci */ 25e1051a39Sopenharmony_civoid CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out, 26e1051a39Sopenharmony_ci size_t len, const void *key, 27e1051a39Sopenharmony_ci unsigned char ivec[16], int *num, 28e1051a39Sopenharmony_ci int enc, block128_f block) 29e1051a39Sopenharmony_ci{ 30e1051a39Sopenharmony_ci unsigned int n; 31e1051a39Sopenharmony_ci size_t l = 0; 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_ci if (*num < 0) { 34e1051a39Sopenharmony_ci /* There is no good way to signal an error return from here */ 35e1051a39Sopenharmony_ci *num = -1; 36e1051a39Sopenharmony_ci return; 37e1051a39Sopenharmony_ci } 38e1051a39Sopenharmony_ci n = *num; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ci if (enc) { 41e1051a39Sopenharmony_ci#if !defined(OPENSSL_SMALL_FOOTPRINT) 42e1051a39Sopenharmony_ci if (16 % sizeof(size_t) == 0) { /* always true actually */ 43e1051a39Sopenharmony_ci do { 44e1051a39Sopenharmony_ci while (n && len) { 45e1051a39Sopenharmony_ci *(out++) = ivec[n] ^= *(in++); 46e1051a39Sopenharmony_ci --len; 47e1051a39Sopenharmony_ci n = (n + 1) % 16; 48e1051a39Sopenharmony_ci } 49e1051a39Sopenharmony_ci# if defined(STRICT_ALIGNMENT) 50e1051a39Sopenharmony_ci if (((size_t)in | (size_t)out | (size_t)ivec) % 51e1051a39Sopenharmony_ci sizeof(size_t) != 0) 52e1051a39Sopenharmony_ci break; 53e1051a39Sopenharmony_ci# endif 54e1051a39Sopenharmony_ci while (len >= 16) { 55e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 56e1051a39Sopenharmony_ci for (; n < 16; n += sizeof(size_t)) { 57e1051a39Sopenharmony_ci *(size_t_aX *)(out + n) = 58e1051a39Sopenharmony_ci *(size_t_aX *)(ivec + n) 59e1051a39Sopenharmony_ci ^= *(size_t_aX *)(in + n); 60e1051a39Sopenharmony_ci } 61e1051a39Sopenharmony_ci len -= 16; 62e1051a39Sopenharmony_ci out += 16; 63e1051a39Sopenharmony_ci in += 16; 64e1051a39Sopenharmony_ci n = 0; 65e1051a39Sopenharmony_ci } 66e1051a39Sopenharmony_ci if (len) { 67e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 68e1051a39Sopenharmony_ci while (len--) { 69e1051a39Sopenharmony_ci out[n] = ivec[n] ^= in[n]; 70e1051a39Sopenharmony_ci ++n; 71e1051a39Sopenharmony_ci } 72e1051a39Sopenharmony_ci } 73e1051a39Sopenharmony_ci *num = n; 74e1051a39Sopenharmony_ci return; 75e1051a39Sopenharmony_ci } while (0); 76e1051a39Sopenharmony_ci } 77e1051a39Sopenharmony_ci /* the rest would be commonly eliminated by x86* compiler */ 78e1051a39Sopenharmony_ci#endif 79e1051a39Sopenharmony_ci while (l < len) { 80e1051a39Sopenharmony_ci if (n == 0) { 81e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 82e1051a39Sopenharmony_ci } 83e1051a39Sopenharmony_ci out[l] = ivec[n] ^= in[l]; 84e1051a39Sopenharmony_ci ++l; 85e1051a39Sopenharmony_ci n = (n + 1) % 16; 86e1051a39Sopenharmony_ci } 87e1051a39Sopenharmony_ci *num = n; 88e1051a39Sopenharmony_ci } else { 89e1051a39Sopenharmony_ci#if !defined(OPENSSL_SMALL_FOOTPRINT) 90e1051a39Sopenharmony_ci if (16 % sizeof(size_t) == 0) { /* always true actually */ 91e1051a39Sopenharmony_ci do { 92e1051a39Sopenharmony_ci while (n && len) { 93e1051a39Sopenharmony_ci unsigned char c; 94e1051a39Sopenharmony_ci *(out++) = ivec[n] ^ (c = *(in++)); 95e1051a39Sopenharmony_ci ivec[n] = c; 96e1051a39Sopenharmony_ci --len; 97e1051a39Sopenharmony_ci n = (n + 1) % 16; 98e1051a39Sopenharmony_ci } 99e1051a39Sopenharmony_ci# if defined(STRICT_ALIGNMENT) 100e1051a39Sopenharmony_ci if (((size_t)in | (size_t)out | (size_t)ivec) % 101e1051a39Sopenharmony_ci sizeof(size_t) != 0) 102e1051a39Sopenharmony_ci break; 103e1051a39Sopenharmony_ci# endif 104e1051a39Sopenharmony_ci while (len >= 16) { 105e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 106e1051a39Sopenharmony_ci for (; n < 16; n += sizeof(size_t)) { 107e1051a39Sopenharmony_ci size_t t = *(size_t_aX *)(in + n); 108e1051a39Sopenharmony_ci *(size_t_aX *)(out + n) 109e1051a39Sopenharmony_ci = *(size_t_aX *)(ivec + n) ^ t; 110e1051a39Sopenharmony_ci *(size_t_aX *)(ivec + n) = t; 111e1051a39Sopenharmony_ci } 112e1051a39Sopenharmony_ci len -= 16; 113e1051a39Sopenharmony_ci out += 16; 114e1051a39Sopenharmony_ci in += 16; 115e1051a39Sopenharmony_ci n = 0; 116e1051a39Sopenharmony_ci } 117e1051a39Sopenharmony_ci if (len) { 118e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 119e1051a39Sopenharmony_ci while (len--) { 120e1051a39Sopenharmony_ci unsigned char c; 121e1051a39Sopenharmony_ci out[n] = ivec[n] ^ (c = in[n]); 122e1051a39Sopenharmony_ci ivec[n] = c; 123e1051a39Sopenharmony_ci ++n; 124e1051a39Sopenharmony_ci } 125e1051a39Sopenharmony_ci } 126e1051a39Sopenharmony_ci *num = n; 127e1051a39Sopenharmony_ci return; 128e1051a39Sopenharmony_ci } while (0); 129e1051a39Sopenharmony_ci } 130e1051a39Sopenharmony_ci /* the rest would be commonly eliminated by x86* compiler */ 131e1051a39Sopenharmony_ci#endif 132e1051a39Sopenharmony_ci while (l < len) { 133e1051a39Sopenharmony_ci unsigned char c; 134e1051a39Sopenharmony_ci if (n == 0) { 135e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 136e1051a39Sopenharmony_ci } 137e1051a39Sopenharmony_ci out[l] = ivec[n] ^ (c = in[l]); 138e1051a39Sopenharmony_ci ivec[n] = c; 139e1051a39Sopenharmony_ci ++l; 140e1051a39Sopenharmony_ci n = (n + 1) % 16; 141e1051a39Sopenharmony_ci } 142e1051a39Sopenharmony_ci *num = n; 143e1051a39Sopenharmony_ci } 144e1051a39Sopenharmony_ci} 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_ci/* 147e1051a39Sopenharmony_ci * This expects a single block of size nbits for both in and out. Note that 148e1051a39Sopenharmony_ci * it corrupts any extra bits in the last byte of out 149e1051a39Sopenharmony_ci */ 150e1051a39Sopenharmony_cistatic void cfbr_encrypt_block(const unsigned char *in, unsigned char *out, 151e1051a39Sopenharmony_ci int nbits, const void *key, 152e1051a39Sopenharmony_ci unsigned char ivec[16], int enc, 153e1051a39Sopenharmony_ci block128_f block) 154e1051a39Sopenharmony_ci{ 155e1051a39Sopenharmony_ci int n, rem, num; 156e1051a39Sopenharmony_ci unsigned char ovec[16 * 2 + 1]; /* +1 because we dereference (but don't 157e1051a39Sopenharmony_ci * use) one byte off the end */ 158e1051a39Sopenharmony_ci 159e1051a39Sopenharmony_ci if (nbits <= 0 || nbits > 128) 160e1051a39Sopenharmony_ci return; 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_ci /* fill in the first half of the new IV with the current IV */ 163e1051a39Sopenharmony_ci memcpy(ovec, ivec, 16); 164e1051a39Sopenharmony_ci /* construct the new IV */ 165e1051a39Sopenharmony_ci (*block) (ivec, ivec, key); 166e1051a39Sopenharmony_ci num = (nbits + 7) / 8; 167e1051a39Sopenharmony_ci if (enc) /* encrypt the input */ 168e1051a39Sopenharmony_ci for (n = 0; n < num; ++n) 169e1051a39Sopenharmony_ci out[n] = (ovec[16 + n] = in[n] ^ ivec[n]); 170e1051a39Sopenharmony_ci else /* decrypt the input */ 171e1051a39Sopenharmony_ci for (n = 0; n < num; ++n) 172e1051a39Sopenharmony_ci out[n] = (ovec[16 + n] = in[n]) ^ ivec[n]; 173e1051a39Sopenharmony_ci /* shift ovec left... */ 174e1051a39Sopenharmony_ci rem = nbits % 8; 175e1051a39Sopenharmony_ci num = nbits / 8; 176e1051a39Sopenharmony_ci if (rem == 0) 177e1051a39Sopenharmony_ci memcpy(ivec, ovec + num, 16); 178e1051a39Sopenharmony_ci else 179e1051a39Sopenharmony_ci for (n = 0; n < 16; ++n) 180e1051a39Sopenharmony_ci ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem); 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ci /* it is not necessary to cleanse ovec, since the IV is not secret */ 183e1051a39Sopenharmony_ci} 184e1051a39Sopenharmony_ci 185e1051a39Sopenharmony_ci/* N.B. This expects the input to be packed, MS bit first */ 186e1051a39Sopenharmony_civoid CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out, 187e1051a39Sopenharmony_ci size_t bits, const void *key, 188e1051a39Sopenharmony_ci unsigned char ivec[16], int *num, 189e1051a39Sopenharmony_ci int enc, block128_f block) 190e1051a39Sopenharmony_ci{ 191e1051a39Sopenharmony_ci size_t n; 192e1051a39Sopenharmony_ci unsigned char c[1], d[1]; 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_ci for (n = 0; n < bits; ++n) { 195e1051a39Sopenharmony_ci c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; 196e1051a39Sopenharmony_ci cfbr_encrypt_block(c, d, 1, key, ivec, enc, block); 197e1051a39Sopenharmony_ci out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) | 198e1051a39Sopenharmony_ci ((d[0] & 0x80) >> (unsigned int)(n % 8)); 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci} 201e1051a39Sopenharmony_ci 202e1051a39Sopenharmony_civoid CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, 203e1051a39Sopenharmony_ci size_t length, const void *key, 204e1051a39Sopenharmony_ci unsigned char ivec[16], int *num, 205e1051a39Sopenharmony_ci int enc, block128_f block) 206e1051a39Sopenharmony_ci{ 207e1051a39Sopenharmony_ci size_t n; 208e1051a39Sopenharmony_ci 209e1051a39Sopenharmony_ci for (n = 0; n < length; ++n) 210e1051a39Sopenharmony_ci cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block); 211e1051a39Sopenharmony_ci} 212