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#include "../../internal.h" 20 21 22void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, 23 const AES_KEY *key, uint8_t ivec[16], 24 block128_f block) { 25 assert(key != NULL && ivec != NULL); 26 if (len == 0) { 27 // Avoid |ivec| == |iv| in the |memcpy| below, which is not legal in C. 28 return; 29 } 30 31 assert(in != NULL && out != NULL); 32 size_t n; 33 const uint8_t *iv = ivec; 34 while (len >= 16) { 35 CRYPTO_xor16(out, in, iv); 36 (*block)(out, out, key); 37 iv = out; 38 len -= 16; 39 in += 16; 40 out += 16; 41 } 42 43 while (len) { 44 for (n = 0; n < 16 && n < len; ++n) { 45 out[n] = in[n] ^ iv[n]; 46 } 47 for (; n < 16; ++n) { 48 out[n] = iv[n]; 49 } 50 (*block)(out, out, key); 51 iv = out; 52 if (len <= 16) { 53 break; 54 } 55 len -= 16; 56 in += 16; 57 out += 16; 58 } 59 60 OPENSSL_memcpy(ivec, iv, 16); 61} 62 63void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, 64 const AES_KEY *key, uint8_t ivec[16], 65 block128_f block) { 66 assert(key != NULL && ivec != NULL); 67 if (len == 0) { 68 // Avoid |ivec| == |iv| in the |memcpy| below, which is not legal in C. 69 return; 70 } 71 72 assert(in != NULL && out != NULL); 73 74 const uintptr_t inptr = (uintptr_t) in; 75 const uintptr_t outptr = (uintptr_t) out; 76 // If |in| and |out| alias, |in| must be ahead. 77 assert(inptr >= outptr || inptr + len <= outptr); 78 79 size_t n; 80 alignas(16) uint8_t tmp[16]; 81 if ((inptr >= 32 && outptr <= inptr - 32) || inptr < outptr) { 82 // If |out| is at least two blocks behind |in| or completely disjoint, there 83 // is no need to decrypt to a temporary block. 84 const uint8_t *iv = ivec; 85 while (len >= 16) { 86 (*block)(in, out, key); 87 CRYPTO_xor16(out, out, iv); 88 iv = in; 89 len -= 16; 90 in += 16; 91 out += 16; 92 } 93 OPENSSL_memcpy(ivec, iv, 16); 94 } else { 95 static_assert(16 % sizeof(crypto_word_t) == 0, 96 "block cannot be evenly divided into words"); 97 98 while (len >= 16) { 99 (*block)(in, tmp, key); 100 for (n = 0; n < 16; n += sizeof(crypto_word_t)) { 101 crypto_word_t c = CRYPTO_load_word_le(in + n); 102 CRYPTO_store_word_le(out + n, CRYPTO_load_word_le(tmp + n) ^ 103 CRYPTO_load_word_le(ivec + n)); 104 CRYPTO_store_word_le(ivec + n, c); 105 } 106 len -= 16; 107 in += 16; 108 out += 16; 109 } 110 } 111 112 while (len) { 113 uint8_t c; 114 (*block)(in, tmp, key); 115 for (n = 0; n < 16 && n < len; ++n) { 116 c = in[n]; 117 out[n] = tmp[n] ^ ivec[n]; 118 ivec[n] = c; 119 } 120 if (len <= 16) { 121 for (; n < 16; ++n) { 122 ivec[n] = in[n]; 123 } 124 break; 125 } 126 len -= 16; 127 in += 16; 128 out += 16; 129 } 130} 131