Add a new file crypto/aes-helpers.c with simple functions to support some AES modes: - AES cbc: AES_cbc_encrypt() AES_cbc_decrypt() - AES ctr: AES_ctr_encrypt() - AES xts: AES_xts_encrypt() AES_xts_decrypt() and some AES related helpers: - AES_xor() - AES_xts_prep_next_tweak() Add header file include/crypto/aes-helpers.h for these functions
Signed-off-by: Harald Freudenberger <[email protected]> Reviewed-by: Finn Callies <[email protected]> --- crypto/aes-helpers.c | 106 ++++++++++++++++++++++++++++++++ crypto/meson.build | 1 + include/crypto/aes-helpers.h | 116 +++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 crypto/aes-helpers.c create mode 100644 include/crypto/aes-helpers.h diff --git a/crypto/aes-helpers.c b/crypto/aes-helpers.c new file mode 100644 index 0000000000..ff4aa0a385 --- /dev/null +++ b/crypto/aes-helpers.c @@ -0,0 +1,106 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * AES helper functions and mode implementations + * + * Authors: + * Harald Freudenberger <[email protected]> + */ + +#include "qemu/osdep.h" +#include "crypto/aes.h" +#include "crypto/aes-helpers.h" + +void AES_xor(const unsigned char *src1, const unsigned char *src2, + unsigned char *dst) +{ + int i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) { + dst[i] = src1[i] ^ src2[i]; + } +} + +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + unsigned char *iv, const AES_KEY *key) +{ + unsigned char buf[AES_BLOCK_SIZE]; + + /* in xor iv => buf */ + AES_xor(in, iv, buf); + /* encrypt buf => out */ + AES_encrypt(buf, out, key); + /* prep iv for next round */ + memcpy(iv, out, AES_BLOCK_SIZE); +} + +void AES_cbc_decrypt(const unsigned char *in, unsigned char *out, + unsigned char *iv, const AES_KEY *key) +{ + unsigned char buf[AES_BLOCK_SIZE]; + + /* decrypt in => buf */ + AES_decrypt(in, buf, key); + /* buf xor iv => out */ + AES_xor(buf, iv, out); + /* prep iv for next round */ + memcpy(iv, in, AES_BLOCK_SIZE); +} + +void AES_ctr_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *ctr, const AES_KEY *key) +{ + unsigned char buf[AES_BLOCK_SIZE]; + + /* encrypt ctr => buf */ + AES_encrypt(ctr, buf, key); + /* exor input data with encrypted ctr => out */ + AES_xor(in, buf, out); +} + +/* + * Tweak calculation for AES XTS. + * Multiply tweak by α (x) in GF(2^128) per IEEE 1619-2007. The tweak + * is a 128-bit little-endian integer (tweak[0]=LSB, tweak[15]=MSB). + * This implementation has been verified on litte and big endian. + */ +void AES_xts_prep_next_tweak(unsigned char *tweak) +{ + unsigned char carry; + int i; + + carry = tweak[AES_BLOCK_SIZE - 1] >> 7; + + for (i = AES_BLOCK_SIZE - 1; i > 0; i--) { + tweak[i] = (unsigned char)((tweak[i] << 1) | (tweak[i - 1] >> 7)); + } + + tweak[i] = (unsigned char)(tweak[i] << 1); + tweak[i] ^= (unsigned char)(0x87 & (unsigned char)(-(unsigned char)carry)); +} + +void AES_xts_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *tweak, const AES_KEY *key) +{ + unsigned char buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE]; + + /* in xor tweak => buf1 */ + AES_xor(in, tweak, buf1); + /* encrypt buf1 => buf2 */ + AES_encrypt(buf1, buf2, key); + /* buf2 xor tweak => out */ + AES_xor(buf2, tweak, out); +} + +void AES_xts_decrypt(const unsigned char *in, unsigned char *out, + const unsigned char *tweak, const AES_KEY *key) +{ + unsigned char buf1[AES_BLOCK_SIZE], buf2[AES_BLOCK_SIZE]; + + /* in xor tweak => buf1 */ + AES_xor(in, tweak, buf1); + /* encrypt buf1 => buf2 */ + AES_decrypt(buf1, buf2, key); + /* buf2 xor tweak => out */ + AES_xor(buf2, tweak, out); +} diff --git a/crypto/meson.build b/crypto/meson.build index b51597a879..675f27311c 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -55,6 +55,7 @@ system_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) util_ss.add(files( 'aes.c', + 'aes-helpers.c', 'clmul.c', 'init.c', 'sm4.c', diff --git a/include/crypto/aes-helpers.h b/include/crypto/aes-helpers.h new file mode 100644 index 0000000000..c1552b0e8f --- /dev/null +++ b/include/crypto/aes-helpers.h @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * AES helper functions and modes + */ + +#ifndef QEMU_AES_HELPERS_H +#define QEMU_AES_HELPERS_H + +/** + * AES_xor: + * + * Bitwise XOR operation between two AES blocks. + * + * @src1: first source buffer of AES_BLOCK_SIZE bytes + * @src2: second source buffer of AES_BLOCK_SIZE bytes + * @dst: destination buffer of AES_BLOCK_SIZE bytes + */ +void AES_xor(const unsigned char *src1, const unsigned char *src2, + unsigned char *dst); + +/** + * AES_cbc_encrypt: + * + * Single block AES encrypt in CBC (Cipher Block Chaining) mode. + * The input block is XORed with the IV, then encrypted with AES. + * IV is updated at the end and is prepared for the next invocation. + * + * @in: input plaintext block of AES_BLOCK_SIZE bytes + * @out: output ciphertext block of AES_BLOCK_SIZE bytes + * @iv: IV, updated after processing for chaining + * @key: AES key + */ +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + unsigned char *iv, const AES_KEY *key); + +/** + * AES_cbc_decrypt: + * + * Single block AES decrypt in CBC (Cipher Block Chaining) mode. + * The input block is decrypted, then XORed with the IV. + * IV is updated at the end and is prepared for the next invocation. + * + * @in: input ciphertext block of AES_BLOCK_SIZE bytes + * @out: output plaintext block of AES_BLOCK_SIZE bytes + * @iv: initialization vector, updated to input block for chaining + * @key: AES key + */ +void AES_cbc_decrypt(const unsigned char *in, unsigned char *out, + unsigned char *iv, const AES_KEY *key); + +/** + * AES_ctr_encrypt: + * + * Single block AES encrypt/decrypt in CTR (Counter) mode. + * The counter block is encrypted, then XORed with the + * input data block. + * In CTR mode encrypt and decrypt are identical operations. + * Note that the caller is responsible for incrementing the + * counter block. + * + * @in: input data block of AES_BLOCK_SIZE bytes + * @out: output data block of AES_BLOCK_SIZE bytes + * @ctr: counter value of AES_BLOCK_SIZE bytes + * @key: AES key + */ +void AES_ctr_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *ctr, const AES_KEY *key); + +/** + * AES_xts_prep_next_tweak: + * + * Tweak calculation for AES XTS. + * Prepares the next tweak value for AES-XTS mode by multiplying + * the current tweak by α (x) in GF(2^128) according to IEEE 1619-2007. + * + * @tweak: pointer to tweak value to be updated (16 bytes buffer + * containing a 128 bit little endian integer) + */ +void AES_xts_prep_next_tweak(unsigned char *tweak); + +/** + * AES_xts_encrypt: + * + * Single block AES encrypt in XTS mode. + * The input is XORed with the tweak, encrypted, then XORed with + * the tweak again to produce the output. + * Note that the caller is responsible for managing the tweak value. + * Use AES_xts_prep_next_tweak() to advance the tweak for the next block. + * + * @in: input plaintext block of AES_BLOCK_SIZE bytes + * @out: output ciphertext block of AES_BLOCK_SIZE bytes + * @tweak: tweak value (16 bytes) + * @key: AES key + */ +void AES_xts_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *tweak, const AES_KEY *key); + +/** + * AES_xts_decrypt: + * + * Single block AES decrypt in XTS mode. + * The input is XORed with the tweak, decrypted, then XORed with + * the tweak again to produce the output. + * Note that the caller is responsible for managing the tweak value. + * Use AES_xts_prep_next_tweak() to advance the tweak for the next block. + * + * @in: input ciphertext block of AES_BLOCK_SIZE bytes + * @out: output plaintext block of AES_BLOCK_SIZE bytes + * @tweak: tweak value (16 bytes) + * @key: AES key + */ +void AES_xts_decrypt(const unsigned char *in, unsigned char *out, + const unsigned char *tweak, const AES_KEY *key); + +#endif -- 2.43.0
