Coverage Report

Created: 2025-09-05 06:13

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