1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* ====================================================================
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Redistribution and use in source and binary forms, with or without
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * modification, are permitted provided that the following conditions
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * are met:
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 1. Redistributions of source code must retain the above copyright
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer.
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 2. Redistributions in binary form must reproduce the above copyright
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer in
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    the documentation and/or other materials provided with the
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    distribution.
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3. All advertising materials mentioning features or use of this
17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    software must display the following acknowledgment:
18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    endorse or promote products derived from this software without
23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    prior written permission. For written permission, please contact
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    openssl-core@openssl.org.
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 5. Products derived from this software may not be called "OpenSSL"
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    nor may "OpenSSL" appear in their names without prior written
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    permission of the OpenSSL Project.
29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 6. Redistributions of any form whatsoever must retain the following
31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    acknowledgment:
32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ==================================================================== */
48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <assert.h>
50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h>
51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "internal.h"
53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
55d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                           const void *key, uint8_t ivec[16],
57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                           block128_f block) {
58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t n;
59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  const uint8_t *iv = ivec;
60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
61f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  assert(key != NULL && ivec != NULL);
62f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  assert(len == 0 || (in != NULL && out != NULL));
63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (STRICT_ALIGNMENT &&
65d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan      ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
66d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan          0) {
67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    while (len >= 16) {
68d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      for (n = 0; n < 16; ++n) {
69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        out[n] = in[n] ^ iv[n];
70d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      (*block)(out, out, key);
72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      iv = out;
73d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      len -= 16;
74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      in += 16;
75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      out += 16;
76d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    while (len >= 16) {
79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      for (n = 0; n < 16; n += sizeof(size_t)) {
80d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan        store_word_le(out + n, load_word_le(in + n) ^ load_word_le(iv + n));
81d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
82d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      (*block)(out, out, key);
83d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      iv = out;
84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      len -= 16;
85d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      in += 16;
86d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      out += 16;
87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  while (len) {
91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    for (n = 0; n < 16 && n < len; ++n) {
92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      out[n] = in[n] ^ iv[n];
93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    for (; n < 16; ++n) {
95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      out[n] = iv[n];
96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    (*block)(out, out, key);
98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    iv = out;
99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (len <= 16) {
100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      break;
101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    len -= 16;
103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    in += 16;
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    out += 16;
105d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
10769939df2891f62f7f00ff2ac275f1cd81a67454cRobert Sloan  OPENSSL_memcpy(ivec, iv, 16);
108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
110d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                           const void *key, uint8_t ivec[16],
112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                           block128_f block) {
113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t n;
114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  union {
115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    size_t t[16 / sizeof(size_t)];
116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    uint8_t c[16];
117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } tmp;
118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
119f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  assert(key != NULL && ivec != NULL);
120f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  assert(len == 0 || (in != NULL && out != NULL));
121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
122f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  const uintptr_t inptr = (uintptr_t) in;
123f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  const uintptr_t outptr = (uintptr_t) out;
1248f860b133896bf655e4342ecefe692d52df81d48Robert Sloan  // If |in| and |out| alias, |in| must be ahead.
125f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  assert(inptr >= outptr || inptr + len <= outptr);
126f4e427204234da139fd0585def4b4e22502e33f0Adam Langley
127f4e427204234da139fd0585def4b4e22502e33f0Adam Langley  if ((inptr >= 32 && outptr <= inptr - 32) || inptr < outptr) {
1288f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    // If |out| is at least two blocks behind |in| or completely disjoint, there
1298f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    // is no need to decrypt to a temporary block.
130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    const uint8_t *iv = ivec;
131d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (STRICT_ALIGNMENT &&
133d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan        ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
134d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan            0) {
135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      while (len >= 16) {
136d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        (*block)(in, out, key);
137e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley        for (n = 0; n < 16; ++n) {
138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          out[n] ^= iv[n];
139e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley        }
140d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        iv = in;
141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        len -= 16;
142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        in += 16;
143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        out += 16;
144d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
1458f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    } else if (16 % sizeof(size_t) == 0) {  // always true
146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      while (len >= 16) {
147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        (*block)(in, out, key);
148d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan        for (n = 0; n < 16; n += sizeof(size_t)) {
149d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan          store_word_le(out + n, load_word_le(out + n) ^ load_word_le(iv + n));
150e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley        }
151d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        iv = in;
152d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        len -= 16;
153d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        in += 16;
154d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        out += 16;
155d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
156d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
15769939df2891f62f7f00ff2ac275f1cd81a67454cRobert Sloan    OPENSSL_memcpy(ivec, iv, 16);
158d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
1598f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    // |out| is less than two blocks behind |in|. Decrypting an input block
1608f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    // directly to |out| would overwrite a ciphertext block before it is used as
1618f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    // the next block's IV. Decrypt to a temporary block instead.
162d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (STRICT_ALIGNMENT &&
163d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan        ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
164d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan            0) {
165d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      uint8_t c;
166d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      while (len >= 16) {
167d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        (*block)(in, tmp.c, key);
168d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        for (n = 0; n < 16; ++n) {
169d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          c = in[n];
170d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          out[n] = tmp.c[n] ^ ivec[n];
171d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          ivec[n] = c;
172d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        }
173d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        len -= 16;
174d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        in += 16;
175d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        out += 16;
176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
1778f860b133896bf655e4342ecefe692d52df81d48Robert Sloan    } else if (16 % sizeof(size_t) == 0) {  // always true
178d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      while (len >= 16) {
179d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        (*block)(in, tmp.c, key);
180d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan        for (n = 0; n < 16; n += sizeof(size_t)) {
181d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan          size_t c = load_word_le(in + n);
182d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan          store_word_le(out + n,
183d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan                        tmp.t[n / sizeof(size_t)] ^ load_word_le(ivec + n));
184d5c2215355e1ae960be386b0d69aed228102cdaeRobert Sloan          store_word_le(ivec + n, c);
185d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        }
186d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        len -= 16;
187d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        in += 16;
188d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        out += 16;
189d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
190d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
191d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
192d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
193d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  while (len) {
194d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    uint8_t c;
195d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    (*block)(in, tmp.c, key);
196d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    for (n = 0; n < 16 && n < len; ++n) {
197d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      c = in[n];
198d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      out[n] = tmp.c[n] ^ ivec[n];
199d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      ivec[n] = c;
200d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
201d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (len <= 16) {
202d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      for (; n < 16; ++n) {
203d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        ivec[n] = in[n];
204d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
205d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      break;
206d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
207d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    len -= 16;
208d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    in += 16;
209d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    out += 16;
210d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
211d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
212