| /* rijndael-api-fst.c --- Rijndael cipher implementation. |
| * Copyright (C) 2005-2006, 2009-2020 Free Software Foundation, Inc. |
| * |
| * This file is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published |
| * by the Free Software Foundation; either version 2, or (at your |
| * option) any later version. |
| * |
| * This file is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this file; if not, see <https://www.gnu.org/licenses/>. |
| * |
| */ |
| |
| /* Adapted for gnulib by Simon Josefsson. |
| * |
| * Based on public domain "Optimised C code" retrieved from (SHA1 |
| * 7c8e4b00d06685d1dbc6724a9e0d502353de339e): |
| * https://web.archive.org/web/20060618010435/http://www.iaik.tu-graz.ac.at/research/krypto/AES/old/~rijmen/rijndael/rijndael-fst-3.0.zip |
| */ |
| |
| #include <config.h> |
| |
| /** |
| * rijndael-api-fst.c |
| * |
| * @version 2.9 (December 2000) |
| * |
| * Optimised ANSI C code for the Rijndael cipher (now AES) |
| * |
| * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> |
| * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> |
| * @author Paulo Barreto <paulo.barreto@terra.com.br> |
| * |
| * This code is hereby placed in the public domain. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS |
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Acknowledgements: |
| * |
| * We are deeply indebted to the following people for their bug reports, |
| * fixes, and improvement suggestions to this implementation. Though we |
| * tried to list all contributions, we apologise in advance for any |
| * missing reference. |
| * |
| * Andrew Bales <Andrew.Bales@Honeywell.com> |
| * Markus Friedl <markus.friedl@informatik.uni-erlangen.de> |
| * John Skodon <skodonj@webquill.com> |
| */ |
| |
| #include "rijndael-alg-fst.h" |
| #include "rijndael-api-fst.h" |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| rijndael_rc |
| rijndaelMakeKey (rijndaelKeyInstance *key, rijndael_direction direction, |
| size_t keyLen, const char *keyMaterial) |
| { |
| size_t i; |
| char *keyMat; |
| char cipherKey[RIJNDAEL_MAXKB]; |
| |
| if (key == NULL) |
| { |
| return RIJNDAEL_BAD_KEY_INSTANCE; |
| } |
| |
| if ((direction == RIJNDAEL_DIR_ENCRYPT) |
| || (direction == RIJNDAEL_DIR_DECRYPT)) |
| { |
| key->direction = direction; |
| } |
| else |
| { |
| return RIJNDAEL_BAD_KEY_DIR; |
| } |
| |
| if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) |
| { |
| key->keyLen = keyLen; |
| } |
| else |
| { |
| return RIJNDAEL_BAD_KEY_MAT; |
| } |
| |
| if (keyMaterial != NULL) |
| { |
| strncpy (key->keyMaterial, keyMaterial, keyLen / 4); |
| } |
| |
| /* initialize key schedule: */ |
| keyMat = key->keyMaterial; |
| for (i = 0; i < key->keyLen / 8; i++) |
| { |
| char t, v; |
| |
| t = *keyMat++; |
| if ((t >= '0') && (t <= '9')) |
| v = (t - '0') << 4; |
| else if ((t >= 'a') && (t <= 'f')) |
| v = (t - 'a' + 10) << 4; |
| else if ((t >= 'A') && (t <= 'F')) |
| v = (t - 'A' + 10) << 4; |
| else |
| return RIJNDAEL_BAD_KEY_MAT; |
| |
| t = *keyMat++; |
| if ((t >= '0') && (t <= '9')) |
| v ^= (t - '0'); |
| else if ((t >= 'a') && (t <= 'f')) |
| v ^= (t - 'a' + 10); |
| else if ((t >= 'A') && (t <= 'F')) |
| v ^= (t - 'A' + 10); |
| else |
| return RIJNDAEL_BAD_KEY_MAT; |
| |
| cipherKey[i] = v; |
| } |
| if (direction == RIJNDAEL_DIR_ENCRYPT) |
| { |
| key->Nr = rijndaelKeySetupEnc (key->rk, cipherKey, keyLen); |
| } |
| else |
| { |
| key->Nr = rijndaelKeySetupDec (key->rk, cipherKey, keyLen); |
| } |
| rijndaelKeySetupEnc (key->ek, cipherKey, keyLen); |
| return 0; |
| } |
| |
| rijndael_rc |
| rijndaelCipherInit (rijndaelCipherInstance *cipher, rijndael_mode mode, |
| const char *IV) |
| { |
| if ((mode == RIJNDAEL_MODE_ECB) || (mode == RIJNDAEL_MODE_CBC) |
| || (mode == RIJNDAEL_MODE_CFB1)) |
| { |
| cipher->mode = mode; |
| } |
| else |
| { |
| return RIJNDAEL_BAD_CIPHER_MODE; |
| } |
| if (IV != NULL) |
| { |
| int i; |
| for (i = 0; i < RIJNDAEL_MAX_IV_SIZE; i++) |
| { |
| int t, j; |
| |
| t = IV[2 * i]; |
| if ((t >= '0') && (t <= '9')) |
| j = (t - '0') << 4; |
| else if ((t >= 'a') && (t <= 'f')) |
| j = (t - 'a' + 10) << 4; |
| else if ((t >= 'A') && (t <= 'F')) |
| j = (t - 'A' + 10) << 4; |
| else |
| return RIJNDAEL_BAD_CIPHER_INSTANCE; |
| |
| t = IV[2 * i + 1]; |
| if ((t >= '0') && (t <= '9')) |
| j ^= (t - '0'); |
| else if ((t >= 'a') && (t <= 'f')) |
| j ^= (t - 'a' + 10); |
| else if ((t >= 'A') && (t <= 'F')) |
| j ^= (t - 'A' + 10); |
| else |
| return RIJNDAEL_BAD_CIPHER_INSTANCE; |
| |
| cipher->IV[i] = (uint8_t) j; |
| } |
| } |
| else |
| { |
| memset (cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE); |
| } |
| return 0; |
| } |
| |
| int |
| rijndaelBlockEncrypt (rijndaelCipherInstance *cipher, |
| const rijndaelKeyInstance *key, |
| const char *input, |
| size_t inputLen, char *outBuffer) |
| { |
| size_t i, k, t, numBlocks; |
| union { char bytes[16]; uint32_t words[4]; } block; |
| char *iv; |
| |
| if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_DECRYPT) |
| { |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| if (input == NULL || inputLen <= 0) |
| { |
| return 0; /* nothing to do */ |
| } |
| |
| numBlocks = inputLen / 128; |
| |
| switch (cipher->mode) |
| { |
| case RIJNDAEL_MODE_ECB: |
| for (i = numBlocks; i > 0; i--) |
| { |
| rijndaelEncrypt (key->rk, key->Nr, input, outBuffer); |
| input += 16; |
| outBuffer += 16; |
| } |
| break; |
| |
| case RIJNDAEL_MODE_CBC: |
| iv = cipher->IV; |
| for (i = numBlocks; i > 0; i--) |
| { |
| block.words[0] = ((uint32_t *) input)[0] ^ ((uint32_t *) iv)[0]; |
| block.words[1] = ((uint32_t *) input)[1] ^ ((uint32_t *) iv)[1]; |
| block.words[2] = ((uint32_t *) input)[2] ^ ((uint32_t *) iv)[2]; |
| block.words[3] = ((uint32_t *) input)[3] ^ ((uint32_t *) iv)[3]; |
| rijndaelEncrypt (key->rk, key->Nr, block.bytes, outBuffer); |
| memcpy (cipher->IV, outBuffer, 16); |
| input += 16; |
| outBuffer += 16; |
| } |
| break; |
| |
| case RIJNDAEL_MODE_CFB1: |
| iv = cipher->IV; |
| for (i = numBlocks; i > 0; i--) |
| { |
| memcpy (outBuffer, input, 16); |
| for (k = 0; k < 128; k++) |
| { |
| rijndaelEncrypt (key->ek, key->Nr, iv, block.bytes); |
| outBuffer[k >> 3] ^= (block.bytes[0] & 0x80U) >> (k & 7); |
| for (t = 0; t < 15; t++) |
| { |
| iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7); |
| } |
| iv[15] = (iv[15] << 1) | |
| ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1); |
| } |
| outBuffer += 16; |
| input += 16; |
| } |
| break; |
| |
| default: |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| |
| return 128 * numBlocks; |
| } |
| |
| int |
| rijndaelPadEncrypt (rijndaelCipherInstance *cipher, |
| const rijndaelKeyInstance *key, |
| const char *input, |
| size_t inputOctets, char *outBuffer) |
| { |
| size_t i, numBlocks, padLen; |
| union { char bytes[16]; uint32_t words[4]; } block; |
| char *iv; |
| |
| if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_DECRYPT) |
| { |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| if (input == NULL || inputOctets <= 0) |
| { |
| return 0; /* nothing to do */ |
| } |
| |
| numBlocks = inputOctets / 16; |
| |
| switch (cipher->mode) |
| { |
| case RIJNDAEL_MODE_ECB: |
| for (i = numBlocks; i > 0; i--) |
| { |
| rijndaelEncrypt (key->rk, key->Nr, input, outBuffer); |
| input += 16; |
| outBuffer += 16; |
| } |
| padLen = 16 - (inputOctets - 16 * numBlocks); |
| assert (padLen > 0 && padLen <= 16); |
| memcpy (block.bytes, input, 16 - padLen); |
| memset (block.bytes + 16 - padLen, padLen, padLen); |
| rijndaelEncrypt (key->rk, key->Nr, block.bytes, outBuffer); |
| break; |
| |
| case RIJNDAEL_MODE_CBC: |
| iv = cipher->IV; |
| for (i = numBlocks; i > 0; i--) |
| { |
| block.words[0] = ((uint32_t *) input)[0] ^ ((uint32_t *) iv)[0]; |
| block.words[1] = ((uint32_t *) input)[1] ^ ((uint32_t *) iv)[1]; |
| block.words[2] = ((uint32_t *) input)[2] ^ ((uint32_t *) iv)[2]; |
| block.words[3] = ((uint32_t *) input)[3] ^ ((uint32_t *) iv)[3]; |
| rijndaelEncrypt (key->rk, key->Nr, block.bytes, outBuffer); |
| memcpy (cipher->IV, outBuffer, 16); |
| input += 16; |
| outBuffer += 16; |
| } |
| padLen = 16 - (inputOctets - 16 * numBlocks); |
| assert (padLen > 0 && padLen <= 16); |
| for (i = 0; i < 16 - padLen; i++) |
| { |
| block.bytes[i] = input[i] ^ iv[i]; |
| } |
| for (i = 16 - padLen; i < 16; i++) |
| { |
| block.bytes[i] = (char) padLen ^ iv[i]; |
| } |
| rijndaelEncrypt (key->rk, key->Nr, block.bytes, outBuffer); |
| memcpy (cipher->IV, outBuffer, 16); |
| break; |
| |
| default: |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| |
| return 16 * (numBlocks + 1); |
| } |
| |
| int |
| rijndaelBlockDecrypt (rijndaelCipherInstance *cipher, |
| const rijndaelKeyInstance *key, |
| const char *input, |
| size_t inputLen, char *outBuffer) |
| { |
| size_t i, k, t, numBlocks; |
| union { char bytes[16]; uint32_t words[4]; } block; |
| char *iv; |
| |
| if (cipher == NULL |
| || key == NULL |
| || (cipher->mode != RIJNDAEL_MODE_CFB1 |
| && key->direction == RIJNDAEL_DIR_ENCRYPT)) |
| { |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| if (input == NULL || inputLen <= 0) |
| { |
| return 0; /* nothing to do */ |
| } |
| |
| numBlocks = inputLen / 128; |
| |
| switch (cipher->mode) |
| { |
| case RIJNDAEL_MODE_ECB: |
| for (i = numBlocks; i > 0; i--) |
| { |
| rijndaelDecrypt (key->rk, key->Nr, input, outBuffer); |
| input += 16; |
| outBuffer += 16; |
| } |
| break; |
| |
| case RIJNDAEL_MODE_CBC: |
| iv = cipher->IV; |
| for (i = numBlocks; i > 0; i--) |
| { |
| rijndaelDecrypt (key->rk, key->Nr, input, block.bytes); |
| block.words[0] ^= ((uint32_t *) iv)[0]; |
| block.words[1] ^= ((uint32_t *) iv)[1]; |
| block.words[2] ^= ((uint32_t *) iv)[2]; |
| block.words[3] ^= ((uint32_t *) iv)[3]; |
| memcpy (cipher->IV, input, 16); |
| memcpy (outBuffer, block.bytes, 16); |
| input += 16; |
| outBuffer += 16; |
| } |
| break; |
| |
| case RIJNDAEL_MODE_CFB1: |
| iv = cipher->IV; |
| for (i = numBlocks; i > 0; i--) |
| { |
| memcpy (outBuffer, input, 16); |
| for (k = 0; k < 128; k++) |
| { |
| rijndaelEncrypt (key->ek, key->Nr, iv, block.bytes); |
| for (t = 0; t < 15; t++) |
| { |
| iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7); |
| } |
| iv[15] = (iv[15] << 1) | ((input[k >> 3] >> (7 - (k & 7))) & 1); |
| outBuffer[k >> 3] ^= (block.bytes[0] & 0x80U) >> (k & 7); |
| } |
| outBuffer += 16; |
| input += 16; |
| } |
| break; |
| |
| default: |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| |
| return 128 * numBlocks; |
| } |
| |
| int |
| rijndaelPadDecrypt (rijndaelCipherInstance *cipher, |
| const rijndaelKeyInstance *key, |
| const char *input, |
| size_t inputOctets, char *outBuffer) |
| { |
| size_t i, numBlocks, padLen; |
| union { char bytes[16]; uint32_t words[4]; } block; |
| char *iv; |
| |
| if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_ENCRYPT) |
| { |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| if (input == NULL || inputOctets <= 0) |
| { |
| return 0; /* nothing to do */ |
| } |
| if (inputOctets % 16 != 0) |
| { |
| return RIJNDAEL_BAD_DATA; |
| } |
| |
| numBlocks = inputOctets / 16; |
| |
| switch (cipher->mode) |
| { |
| case RIJNDAEL_MODE_ECB: |
| /* all blocks but last */ |
| for (i = numBlocks - 1; i > 0; i--) |
| { |
| rijndaelDecrypt (key->rk, key->Nr, input, outBuffer); |
| input += 16; |
| outBuffer += 16; |
| } |
| /* last block */ |
| rijndaelDecrypt (key->rk, key->Nr, input, block.bytes); |
| padLen = block.bytes[15]; |
| if (padLen >= 16) |
| { |
| return RIJNDAEL_BAD_DATA; |
| } |
| for (i = 16 - padLen; i < 16; i++) |
| { |
| if (block.bytes[i] != padLen) |
| { |
| return RIJNDAEL_BAD_DATA; |
| } |
| } |
| memcpy (outBuffer, block.bytes, 16 - padLen); |
| break; |
| |
| case RIJNDAEL_MODE_CBC: |
| iv = cipher->IV; |
| /* all blocks but last */ |
| for (i = numBlocks - 1; i > 0; i--) |
| { |
| rijndaelDecrypt (key->rk, key->Nr, input, block.bytes); |
| block.words[0] ^= ((uint32_t *) iv)[0]; |
| block.words[1] ^= ((uint32_t *) iv)[1]; |
| block.words[2] ^= ((uint32_t *) iv)[2]; |
| block.words[3] ^= ((uint32_t *) iv)[3]; |
| memcpy (iv, input, 16); |
| memcpy (outBuffer, block.bytes, 16); |
| input += 16; |
| outBuffer += 16; |
| } |
| /* last block */ |
| rijndaelDecrypt (key->rk, key->Nr, input, block.bytes); |
| block.words[0] ^= ((uint32_t *) iv)[0]; |
| block.words[1] ^= ((uint32_t *) iv)[1]; |
| block.words[2] ^= ((uint32_t *) iv)[2]; |
| block.words[3] ^= ((uint32_t *) iv)[3]; |
| padLen = block.bytes[15]; |
| if (padLen <= 0 || padLen > 16) |
| { |
| return RIJNDAEL_BAD_DATA; |
| } |
| for (i = 16 - padLen; i < 16; i++) |
| { |
| if (block.bytes[i] != padLen) |
| { |
| return RIJNDAEL_BAD_DATA; |
| } |
| } |
| memcpy (outBuffer, block.bytes, 16 - padLen); |
| break; |
| |
| default: |
| return RIJNDAEL_BAD_CIPHER_STATE; |
| } |
| |
| return 16 * numBlocks - padLen; |
| } |