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