xref: /freebsd/crypto/openssl/crypto/modes/cfb128.c (revision b077aed3)
1e71b7053SJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
31f13597dSJung-uk Kim  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
81f13597dSJung-uk Kim  */
91f13597dSJung-uk Kim 
101f13597dSJung-uk Kim #include <string.h>
11*b077aed3SPierre Pronchery #include <openssl/crypto.h>
12*b077aed3SPierre Pronchery #include "crypto/modes.h"
131f13597dSJung-uk Kim 
1458f35182SJung-uk Kim #if defined(__GNUC__) && !defined(STRICT_ALIGNMENT)
1558f35182SJung-uk Kim typedef size_t size_t_aX __attribute((__aligned__(1)));
1658f35182SJung-uk Kim #else
1758f35182SJung-uk Kim typedef size_t size_t_aX;
1858f35182SJung-uk Kim #endif
1958f35182SJung-uk Kim 
206f9291ceSJung-uk Kim /*
216f9291ceSJung-uk Kim  * The input and output encrypted as though 128bit cfb mode is being used.
226f9291ceSJung-uk Kim  * The extra state information to record how much of the 128bit block we have
236f9291ceSJung-uk Kim  * used is contained in *num;
241f13597dSJung-uk Kim  */
CRYPTO_cfb128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],int * num,int enc,block128_f block)251f13597dSJung-uk Kim void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
261f13597dSJung-uk Kim                            size_t len, const void *key,
271f13597dSJung-uk Kim                            unsigned char ivec[16], int *num,
281f13597dSJung-uk Kim                            int enc, block128_f block)
291f13597dSJung-uk Kim {
301f13597dSJung-uk Kim     unsigned int n;
311f13597dSJung-uk Kim     size_t l = 0;
321f13597dSJung-uk Kim 
33*b077aed3SPierre Pronchery     if (*num < 0) {
34*b077aed3SPierre Pronchery         /* There is no good way to signal an error return from here */
35*b077aed3SPierre Pronchery         *num = -1;
36*b077aed3SPierre Pronchery         return;
37*b077aed3SPierre Pronchery     }
381f13597dSJung-uk Kim     n = *num;
391f13597dSJung-uk Kim 
401f13597dSJung-uk Kim     if (enc) {
411f13597dSJung-uk Kim #if !defined(OPENSSL_SMALL_FOOTPRINT)
426f9291ceSJung-uk Kim         if (16 % sizeof(size_t) == 0) { /* always true actually */
436f9291ceSJung-uk Kim             do {
441f13597dSJung-uk Kim                 while (n && len) {
451f13597dSJung-uk Kim                     *(out++) = ivec[n] ^= *(in++);
461f13597dSJung-uk Kim                     --len;
471f13597dSJung-uk Kim                     n = (n + 1) % 16;
481f13597dSJung-uk Kim                 }
491f13597dSJung-uk Kim # if defined(STRICT_ALIGNMENT)
506f9291ceSJung-uk Kim                 if (((size_t)in | (size_t)out | (size_t)ivec) %
516f9291ceSJung-uk Kim                     sizeof(size_t) != 0)
521f13597dSJung-uk Kim                     break;
531f13597dSJung-uk Kim # endif
541f13597dSJung-uk Kim                 while (len >= 16) {
551f13597dSJung-uk Kim                     (*block) (ivec, ivec, key);
561f13597dSJung-uk Kim                     for (; n < 16; n += sizeof(size_t)) {
5758f35182SJung-uk Kim                         *(size_t_aX *)(out + n) =
5858f35182SJung-uk Kim                             *(size_t_aX *)(ivec + n)
5958f35182SJung-uk Kim                                 ^= *(size_t_aX *)(in + n);
601f13597dSJung-uk Kim                     }
611f13597dSJung-uk Kim                     len -= 16;
621f13597dSJung-uk Kim                     out += 16;
631f13597dSJung-uk Kim                     in += 16;
641f13597dSJung-uk Kim                     n = 0;
651f13597dSJung-uk Kim                 }
661f13597dSJung-uk Kim                 if (len) {
671f13597dSJung-uk Kim                     (*block) (ivec, ivec, key);
681f13597dSJung-uk Kim                     while (len--) {
691f13597dSJung-uk Kim                         out[n] = ivec[n] ^= in[n];
701f13597dSJung-uk Kim                         ++n;
711f13597dSJung-uk Kim                     }
721f13597dSJung-uk Kim                 }
731f13597dSJung-uk Kim                 *num = n;
741f13597dSJung-uk Kim                 return;
751f13597dSJung-uk Kim             } while (0);
766f9291ceSJung-uk Kim         }
771f13597dSJung-uk Kim         /* the rest would be commonly eliminated by x86* compiler */
781f13597dSJung-uk Kim #endif
791f13597dSJung-uk Kim         while (l < len) {
801f13597dSJung-uk Kim             if (n == 0) {
811f13597dSJung-uk Kim                 (*block) (ivec, ivec, key);
821f13597dSJung-uk Kim             }
831f13597dSJung-uk Kim             out[l] = ivec[n] ^= in[l];
841f13597dSJung-uk Kim             ++l;
851f13597dSJung-uk Kim             n = (n + 1) % 16;
861f13597dSJung-uk Kim         }
871f13597dSJung-uk Kim         *num = n;
881f13597dSJung-uk Kim     } else {
891f13597dSJung-uk Kim #if !defined(OPENSSL_SMALL_FOOTPRINT)
906f9291ceSJung-uk Kim         if (16 % sizeof(size_t) == 0) { /* always true actually */
916f9291ceSJung-uk Kim             do {
921f13597dSJung-uk Kim                 while (n && len) {
931f13597dSJung-uk Kim                     unsigned char c;
946f9291ceSJung-uk Kim                     *(out++) = ivec[n] ^ (c = *(in++));
956f9291ceSJung-uk Kim                     ivec[n] = c;
961f13597dSJung-uk Kim                     --len;
971f13597dSJung-uk Kim                     n = (n + 1) % 16;
981f13597dSJung-uk Kim                 }
991f13597dSJung-uk Kim # if defined(STRICT_ALIGNMENT)
1006f9291ceSJung-uk Kim                 if (((size_t)in | (size_t)out | (size_t)ivec) %
1016f9291ceSJung-uk Kim                     sizeof(size_t) != 0)
1021f13597dSJung-uk Kim                     break;
1031f13597dSJung-uk Kim # endif
1041f13597dSJung-uk Kim                 while (len >= 16) {
1051f13597dSJung-uk Kim                     (*block) (ivec, ivec, key);
1061f13597dSJung-uk Kim                     for (; n < 16; n += sizeof(size_t)) {
10758f35182SJung-uk Kim                         size_t t = *(size_t_aX *)(in + n);
10858f35182SJung-uk Kim                         *(size_t_aX *)(out + n)
10958f35182SJung-uk Kim                             = *(size_t_aX *)(ivec + n) ^ t;
11058f35182SJung-uk Kim                         *(size_t_aX *)(ivec + n) = t;
1111f13597dSJung-uk Kim                     }
1121f13597dSJung-uk Kim                     len -= 16;
1131f13597dSJung-uk Kim                     out += 16;
1141f13597dSJung-uk Kim                     in += 16;
1151f13597dSJung-uk Kim                     n = 0;
1161f13597dSJung-uk Kim                 }
1171f13597dSJung-uk Kim                 if (len) {
1181f13597dSJung-uk Kim                     (*block) (ivec, ivec, key);
1191f13597dSJung-uk Kim                     while (len--) {
1201f13597dSJung-uk Kim                         unsigned char c;
1216f9291ceSJung-uk Kim                         out[n] = ivec[n] ^ (c = in[n]);
1226f9291ceSJung-uk Kim                         ivec[n] = c;
1231f13597dSJung-uk Kim                         ++n;
1241f13597dSJung-uk Kim                     }
1251f13597dSJung-uk Kim                 }
1261f13597dSJung-uk Kim                 *num = n;
1271f13597dSJung-uk Kim                 return;
1281f13597dSJung-uk Kim             } while (0);
1296f9291ceSJung-uk Kim         }
1301f13597dSJung-uk Kim         /* the rest would be commonly eliminated by x86* compiler */
1311f13597dSJung-uk Kim #endif
1321f13597dSJung-uk Kim         while (l < len) {
1331f13597dSJung-uk Kim             unsigned char c;
1341f13597dSJung-uk Kim             if (n == 0) {
1351f13597dSJung-uk Kim                 (*block) (ivec, ivec, key);
1361f13597dSJung-uk Kim             }
1376f9291ceSJung-uk Kim             out[l] = ivec[n] ^ (c = in[l]);
1386f9291ceSJung-uk Kim             ivec[n] = c;
1391f13597dSJung-uk Kim             ++l;
1401f13597dSJung-uk Kim             n = (n + 1) % 16;
1411f13597dSJung-uk Kim         }
1421f13597dSJung-uk Kim         *num = n;
1431f13597dSJung-uk Kim     }
1441f13597dSJung-uk Kim }
1451f13597dSJung-uk Kim 
1466f9291ceSJung-uk Kim /*
1476f9291ceSJung-uk Kim  * This expects a single block of size nbits for both in and out. Note that
1486f9291ceSJung-uk Kim  * it corrupts any extra bits in the last byte of out
1496f9291ceSJung-uk Kim  */
cfbr_encrypt_block(const unsigned char * in,unsigned char * out,int nbits,const void * key,unsigned char ivec[16],int enc,block128_f block)1501f13597dSJung-uk Kim static void cfbr_encrypt_block(const unsigned char *in, unsigned char *out,
1511f13597dSJung-uk Kim                                int nbits, const void *key,
1521f13597dSJung-uk Kim                                unsigned char ivec[16], int enc,
1531f13597dSJung-uk Kim                                block128_f block)
1541f13597dSJung-uk Kim {
1551f13597dSJung-uk Kim     int n, rem, num;
156e71b7053SJung-uk Kim     unsigned char ovec[16 * 2 + 1]; /* +1 because we dereference (but don't
1576f9291ceSJung-uk Kim                                      * use) one byte off the end */
1581f13597dSJung-uk Kim 
1596f9291ceSJung-uk Kim     if (nbits <= 0 || nbits > 128)
1606f9291ceSJung-uk Kim         return;
1611f13597dSJung-uk Kim 
1621f13597dSJung-uk Kim     /* fill in the first half of the new IV with the current IV */
1631f13597dSJung-uk Kim     memcpy(ovec, ivec, 16);
1641f13597dSJung-uk Kim     /* construct the new IV */
1651f13597dSJung-uk Kim     (*block) (ivec, ivec, key);
1661f13597dSJung-uk Kim     num = (nbits + 7) / 8;
1671f13597dSJung-uk Kim     if (enc)                    /* encrypt the input */
1681f13597dSJung-uk Kim         for (n = 0; n < num; ++n)
1691f13597dSJung-uk Kim             out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
1701f13597dSJung-uk Kim     else                        /* decrypt the input */
1711f13597dSJung-uk Kim         for (n = 0; n < num; ++n)
1721f13597dSJung-uk Kim             out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
1731f13597dSJung-uk Kim     /* shift ovec left... */
1741f13597dSJung-uk Kim     rem = nbits % 8;
1751f13597dSJung-uk Kim     num = nbits / 8;
1761f13597dSJung-uk Kim     if (rem == 0)
1771f13597dSJung-uk Kim         memcpy(ivec, ovec + num, 16);
1781f13597dSJung-uk Kim     else
1791f13597dSJung-uk Kim         for (n = 0; n < 16; ++n)
1801f13597dSJung-uk Kim             ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
1811f13597dSJung-uk Kim 
1821f13597dSJung-uk Kim     /* it is not necessary to cleanse ovec, since the IV is not secret */
1831f13597dSJung-uk Kim }
1841f13597dSJung-uk Kim 
1851f13597dSJung-uk Kim /* N.B. This expects the input to be packed, MS bit first */
CRYPTO_cfb128_1_encrypt(const unsigned char * in,unsigned char * out,size_t bits,const void * key,unsigned char ivec[16],int * num,int enc,block128_f block)1861f13597dSJung-uk Kim void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
1871f13597dSJung-uk Kim                              size_t bits, const void *key,
1881f13597dSJung-uk Kim                              unsigned char ivec[16], int *num,
1891f13597dSJung-uk Kim                              int enc, block128_f block)
1901f13597dSJung-uk Kim {
1911f13597dSJung-uk Kim     size_t n;
1921f13597dSJung-uk Kim     unsigned char c[1], d[1];
1931f13597dSJung-uk Kim 
1946f9291ceSJung-uk Kim     for (n = 0; n < bits; ++n) {
1951f13597dSJung-uk Kim         c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
1961f13597dSJung-uk Kim         cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
1971f13597dSJung-uk Kim         out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
1981f13597dSJung-uk Kim             ((d[0] & 0x80) >> (unsigned int)(n % 8));
1991f13597dSJung-uk Kim     }
2001f13597dSJung-uk Kim }
2011f13597dSJung-uk Kim 
CRYPTO_cfb128_8_encrypt(const unsigned char * in,unsigned char * out,size_t length,const void * key,unsigned char ivec[16],int * num,int enc,block128_f block)2021f13597dSJung-uk Kim void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
2031f13597dSJung-uk Kim                              size_t length, const void *key,
2041f13597dSJung-uk Kim                              unsigned char ivec[16], int *num,
2051f13597dSJung-uk Kim                              int enc, block128_f block)
2061f13597dSJung-uk Kim {
2071f13597dSJung-uk Kim     size_t n;
2081f13597dSJung-uk Kim 
2091f13597dSJung-uk Kim     for (n = 0; n < length; ++n)
2101f13597dSJung-uk Kim         cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
2111f13597dSJung-uk Kim }
212