• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <assert.h>
11#include <string.h>
12
13#include "internal.h"
14
15
16static_assert(16 % sizeof(size_t) == 0, "block cannot be divided into size_t");
17
18void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
19                           const AES_KEY *key, uint8_t ivec[16], unsigned *num,
20                           int enc, block128_f block) {
21  assert(in && out && key && ivec && num);
22
23  unsigned n = *num;
24
25  if (enc) {
26    while (n && len) {
27      *(out++) = ivec[n] ^= *(in++);
28      --len;
29      n = (n + 1) % 16;
30    }
31    while (len >= 16) {
32      (*block)(ivec, ivec, key);
33      for (; n < 16; n += sizeof(crypto_word_t)) {
34        crypto_word_t tmp =
35            CRYPTO_load_word_le(ivec + n) ^ CRYPTO_load_word_le(in + n);
36        CRYPTO_store_word_le(ivec + n, tmp);
37        CRYPTO_store_word_le(out + n, tmp);
38      }
39      len -= 16;
40      out += 16;
41      in += 16;
42      n = 0;
43    }
44    if (len) {
45      (*block)(ivec, ivec, key);
46      while (len--) {
47        out[n] = ivec[n] ^= in[n];
48        ++n;
49      }
50    }
51    *num = n;
52    return;
53  } else {
54    while (n && len) {
55      uint8_t c;
56      *(out++) = ivec[n] ^ (c = *(in++));
57      ivec[n] = c;
58      --len;
59      n = (n + 1) % 16;
60    }
61    while (len >= 16) {
62      (*block)(ivec, ivec, key);
63      for (; n < 16; n += sizeof(crypto_word_t)) {
64        crypto_word_t t = CRYPTO_load_word_le(in + n);
65        CRYPTO_store_word_le(out + n, CRYPTO_load_word_le(ivec + n) ^ t);
66        CRYPTO_store_word_le(ivec + n, t);
67      }
68      len -= 16;
69      out += 16;
70      in += 16;
71      n = 0;
72    }
73    if (len) {
74      (*block)(ivec, ivec, key);
75      while (len--) {
76        uint8_t c;
77        out[n] = ivec[n] ^ (c = in[n]);
78        ivec[n] = c;
79        ++n;
80      }
81    }
82    *num = n;
83    return;
84  }
85}
86
87
88/* This expects a single block of size nbits for both in and out. Note that
89   it corrupts any extra bits in the last byte of out */
90static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits,
91                               const AES_KEY *key, uint8_t ivec[16], int enc,
92                               block128_f block) {
93  int n, rem, num;
94  uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one
95                               byte off the end */
96
97  if (nbits <= 0 || nbits > 128) {
98    return;
99  }
100
101  // fill in the first half of the new IV with the current IV
102  OPENSSL_memcpy(ovec, ivec, 16);
103  // construct the new IV
104  (*block)(ivec, ivec, key);
105  num = (nbits + 7) / 8;
106  if (enc) {
107    // encrypt the input
108    for (n = 0; n < num; ++n) {
109      out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
110    }
111  } else {
112    // decrypt the input
113    for (n = 0; n < num; ++n) {
114      out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
115    }
116  }
117  // shift ovec left...
118  rem = nbits % 8;
119  num = nbits / 8;
120  if (rem == 0) {
121    OPENSSL_memcpy(ivec, ovec + num, 16);
122  } else {
123    for (n = 0; n < 16; ++n) {
124      ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
125    }
126  }
127
128  // it is not necessary to cleanse ovec, since the IV is not secret
129}
130
131// N.B. This expects the input to be packed, MS bit first
132void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
133                             const AES_KEY *key, uint8_t ivec[16],
134                             unsigned *num, int enc, block128_f block) {
135  size_t n;
136  uint8_t c[1], d[1];
137
138  assert(in && out && key && ivec && num);
139  assert(*num == 0);
140
141  for (n = 0; n < bits; ++n) {
142    c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
143    cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
144    out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
145                 ((d[0] & 0x80) >> (unsigned int)(n % 8));
146  }
147}
148
149void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
150                             size_t length, const AES_KEY *key,
151                             unsigned char ivec[16], unsigned *num, int enc,
152                             block128_f block) {
153  size_t n;
154
155  assert(in && out && key && ivec && num);
156  assert(*num == 0);
157
158  for (n = 0; n < length; ++n) {
159    cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
160  }
161}
162