// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017-2019 Linaro Ltd <ard.biesheuvel@linaro.org>
*/
#include <crypto/aes.h>
#include <linux/crypto.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/unaligned.h>
/*
* Emit the sbox as volatile const to prevent the compiler from doing
* constant folding on sbox references involving fixed indexes.
*/
static volatile const u8 __cacheline_aligned aes_sbox[] = {
0 x63, 0 x7c, 0 x77, 0 x7b, 0 xf2, 0 x6b, 0 x6f, 0 xc5,
0 x30, 0 x01, 0 x67, 0 x2b, 0 xfe, 0 xd7, 0 xab, 0 x76,
0 xca, 0 x82, 0 xc9, 0 x7d, 0 xfa, 0 x59, 0 x47, 0 xf0,
0 xad, 0 xd4, 0 xa2, 0 xaf, 0 x9c, 0 xa4, 0 x72, 0 xc0,
0 xb7, 0 xfd, 0 x93, 0 x26, 0 x36, 0 x3f, 0 xf7, 0 xcc,
0 x34, 0 xa5, 0 xe5, 0 xf1, 0 x71, 0 xd8, 0 x31, 0 x15,
0 x04, 0 xc7, 0 x23, 0 xc3, 0 x18, 0 x96, 0 x05, 0 x9a,
0 x07, 0 x12, 0 x80, 0 xe2, 0 xeb, 0 x27, 0 xb2, 0 x75,
0 x09, 0 x83, 0 x2c, 0 x1a, 0 x1b, 0 x6e, 0 x5a, 0 xa0,
0 x52, 0 x3b, 0 xd6, 0 xb3, 0 x29, 0 xe3, 0 x2f, 0 x84,
0 x53, 0 xd1, 0 x00, 0 xed, 0 x20, 0 xfc, 0 xb1, 0 x5b,
0 x6a, 0 xcb, 0 xbe, 0 x39, 0 x4a, 0 x4c, 0 x58, 0 xcf,
0 xd0, 0 xef, 0 xaa, 0 xfb, 0 x43, 0 x4d, 0 x33, 0 x85,
0 x45, 0 xf9, 0 x02, 0 x7f, 0 x50, 0 x3c, 0 x9f, 0 xa8,
0 x51, 0 xa3, 0 x40, 0 x8f, 0 x92, 0 x9d, 0 x38, 0 xf5,
0 xbc, 0 xb6, 0 xda, 0 x21, 0 x10, 0 xff, 0 xf3, 0 xd2,
0 xcd, 0 x0c, 0 x13, 0 xec, 0 x5f, 0 x97, 0 x44, 0 x17,
0 xc4, 0 xa7, 0 x7e, 0 x3d, 0 x64, 0 x5d, 0 x19, 0 x73,
0 x60, 0 x81, 0 x4f, 0 xdc, 0 x22, 0 x2a, 0 x90, 0 x88,
0 x46, 0 xee, 0 xb8, 0 x14, 0 xde, 0 x5e, 0 x0b, 0 xdb,
0 xe0, 0 x32, 0 x3a, 0 x0a, 0 x49, 0 x06, 0 x24, 0 x5c,
0 xc2, 0 xd3, 0 xac, 0 x62, 0 x91, 0 x95, 0 xe4, 0 x79,
0 xe7, 0 xc8, 0 x37, 0 x6d, 0 x8d, 0 xd5, 0 x4e, 0 xa9,
0 x6c, 0 x56, 0 xf4, 0 xea, 0 x65, 0 x7a, 0 xae, 0 x08,
0 xba, 0 x78, 0 x25, 0 x2e, 0 x1c, 0 xa6, 0 xb4, 0 xc6,
0 xe8, 0 xdd, 0 x74, 0 x1f, 0 x4b, 0 xbd, 0 x8b, 0 x8a,
0 x70, 0 x3e, 0 xb5, 0 x66, 0 x48, 0 x03, 0 xf6, 0 x0e,
0 x61, 0 x35, 0 x57, 0 xb9, 0 x86, 0 xc1, 0 x1d, 0 x9e,
0 xe1, 0 xf8, 0 x98, 0 x11, 0 x69, 0 xd9, 0 x8e, 0 x94,
0 x9b, 0 x1e, 0 x87, 0 xe9, 0 xce, 0 x55, 0 x28, 0 xdf,
0 x8c, 0 xa1, 0 x89, 0 x0d, 0 xbf, 0 xe6, 0 x42, 0 x68,
0 x41, 0 x99, 0 x2d, 0 x0f, 0 xb0, 0 x54, 0 xbb, 0 x16,
};
static volatile const u8 __cacheline_aligned aes_inv_sbox[] = {
0 x52, 0 x09, 0 x6a, 0 xd5, 0 x30, 0 x36, 0 xa5, 0 x38,
0 xbf, 0 x40, 0 xa3, 0 x9e, 0 x81, 0 xf3, 0 xd7, 0 xfb,
0 x7c, 0 xe3, 0 x39, 0 x82, 0 x9b, 0 x2f, 0 xff, 0 x87,
0 x34, 0 x8e, 0 x43, 0 x44, 0 xc4, 0 xde, 0 xe9, 0 xcb,
0 x54, 0 x7b, 0 x94, 0 x32, 0 xa6, 0 xc2, 0 x23, 0 x3d,
0 xee, 0 x4c, 0 x95, 0 x0b, 0 x42, 0 xfa, 0 xc3, 0 x4e,
0 x08, 0 x2e, 0 xa1, 0 x66, 0 x28, 0 xd9, 0 x24, 0 xb2,
0 x76, 0 x5b, 0 xa2, 0 x49, 0 x6d, 0 x8b, 0 xd1, 0 x25,
0 x72, 0 xf8, 0 xf6, 0 x64, 0 x86, 0 x68, 0 x98, 0 x16,
0 xd4, 0 xa4, 0 x5c, 0 xcc, 0 x5d, 0 x65, 0 xb6, 0 x92,
0 x6c, 0 x70, 0 x48, 0 x50, 0 xfd, 0 xed, 0 xb9, 0 xda,
0 x5e, 0 x15, 0 x46, 0 x57, 0 xa7, 0 x8d, 0 x9d, 0 x84,
0 x90, 0 xd8, 0 xab, 0 x00, 0 x8c, 0 xbc, 0 xd3, 0 x0a,
0 xf7, 0 xe4, 0 x58, 0 x05, 0 xb8, 0 xb3, 0 x45, 0 x06,
0 xd0, 0 x2c, 0 x1e, 0 x8f, 0 xca, 0 x3f, 0 x0f, 0 x02,
0 xc1, 0 xaf, 0 xbd, 0 x03, 0 x01, 0 x13, 0 x8a, 0 x6b,
0 x3a, 0 x91, 0 x11, 0 x41, 0 x4f, 0 x67, 0 xdc, 0 xea,
0 x97, 0 xf2, 0 xcf, 0 xce, 0 xf0, 0 xb4, 0 xe6, 0 x73,
0 x96, 0 xac, 0 x74, 0 x22, 0 xe7, 0 xad, 0 x35, 0 x85,
0 xe2, 0 xf9, 0 x37, 0 xe8, 0 x1c, 0 x75, 0 xdf, 0 x6e,
0 x47, 0 xf1, 0 x1a, 0 x71, 0 x1d, 0 x29, 0 xc5, 0 x89,
0 x6f, 0 xb7, 0 x62, 0 x0e, 0 xaa, 0 x18, 0 xbe, 0 x1b,
0 xfc, 0 x56, 0 x3e, 0 x4b, 0 xc6, 0 xd2, 0 x79, 0 x20,
0 x9a, 0 xdb, 0 xc0, 0 xfe, 0 x78, 0 xcd, 0 x5a, 0 xf4,
0 x1f, 0 xdd, 0 xa8, 0 x33, 0 x88, 0 x07, 0 xc7, 0 x31,
0 xb1, 0 x12, 0 x10, 0 x59, 0 x27, 0 x80, 0 xec, 0 x5f,
0 x60, 0 x51, 0 x7f, 0 xa9, 0 x19, 0 xb5, 0 x4a, 0 x0d,
0 x2d, 0 xe5, 0 x7a, 0 x9f, 0 x93, 0 xc9, 0 x9c, 0 xef,
0 xa0, 0 xe0, 0 x3b, 0 x4d, 0 xae, 0 x2a, 0 xf5, 0 xb0,
0 xc8, 0 xeb, 0 xbb, 0 x3c, 0 x83, 0 x53, 0 x99, 0 x61,
0 x17, 0 x2b, 0 x04, 0 x7e, 0 xba, 0 x77, 0 xd6, 0 x26,
0 xe1, 0 x69, 0 x14, 0 x63, 0 x55, 0 x21, 0 x0c, 0 x7d,
};
extern const u8 crypto_aes_sbox[256 ] __alias(aes_sbox);
extern const u8 crypto_aes_inv_sbox[256 ] __alias(aes_inv_sbox);
EXPORT_SYMBOL(crypto_aes_sbox);
EXPORT_SYMBOL(crypto_aes_inv_sbox);
static u32 mul_by_x(u32 w)
{
u32 x = w & 0 x7f7f7f7f;
u32 y = w & 0 x80808080;
/* multiply by polynomial 'x' (0b10) in GF(2^8) */
return (x << 1 ) ^ (y >> 7 ) * 0 x1b;
}
static u32 mul_by_x2(u32 w)
{
u32 x = w & 0 x3f3f3f3f;
u32 y = w & 0 x80808080;
u32 z = w & 0 x40404040;
/* multiply by polynomial 'x^2' (0b100) in GF(2^8) */
return (x << 2 ) ^ (y >> 7 ) * 0 x36 ^ (z >> 6 ) * 0 x1b;
}
static u32 mix_columns(u32 x)
{
/*
* Perform the following matrix multiplication in GF(2^8)
*
* | 0x2 0x3 0x1 0x1 | | x[0] |
* | 0x1 0x2 0x3 0x1 | | x[1] |
* | 0x1 0x1 0x2 0x3 | x | x[2] |
* | 0x3 0x1 0x1 0x2 | | x[3] |
*/
u32 y = mul_by_x(x) ^ ror32(x, 16 );
return y ^ ror32(x ^ y, 8 );
}
static u32 inv_mix_columns(u32 x)
{
/*
* Perform the following matrix multiplication in GF(2^8)
*
* | 0xe 0xb 0xd 0x9 | | x[0] |
* | 0x9 0xe 0xb 0xd | | x[1] |
* | 0xd 0x9 0xe 0xb | x | x[2] |
* | 0xb 0xd 0x9 0xe | | x[3] |
*
* which can conveniently be reduced to
*
* | 0x2 0x3 0x1 0x1 | | 0x5 0x0 0x4 0x0 | | x[0] |
* | 0x1 0x2 0x3 0x1 | | 0x0 0x5 0x0 0x4 | | x[1] |
* | 0x1 0x1 0x2 0x3 | x | 0x4 0x0 0x5 0x0 | x | x[2] |
* | 0x3 0x1 0x1 0x2 | | 0x0 0x4 0x0 0x5 | | x[3] |
*/
u32 y = mul_by_x2(x);
return mix_columns(x ^ y ^ ror32(y, 16 ));
}
static __always_inline u32 subshift(u32 in[], int pos)
{
return (aes_sbox[in[pos] & 0 xff]) ^
(aes_sbox[(in[(pos + 1 ) % 4 ] >> 8 ) & 0 xff] << 8 ) ^
(aes_sbox[(in[(pos + 2 ) % 4 ] >> 16 ) & 0 xff] << 16 ) ^
(aes_sbox[(in[(pos + 3 ) % 4 ] >> 24 ) & 0 xff] << 24 );
}
static __always_inline u32 inv_subshift(u32 in[], int pos)
{
return (aes_inv_sbox[in[pos] & 0 xff]) ^
(aes_inv_sbox[(in[(pos + 3 ) % 4 ] >> 8 ) & 0 xff] << 8 ) ^
(aes_inv_sbox[(in[(pos + 2 ) % 4 ] >> 16 ) & 0 xff] << 16 ) ^
(aes_inv_sbox[(in[(pos + 1 ) % 4 ] >> 24 ) & 0 xff] << 24 );
}
static u32 subw(u32 in)
{
return (aes_sbox[in & 0 xff]) ^
(aes_sbox[(in >> 8 ) & 0 xff] << 8 ) ^
(aes_sbox[(in >> 16 ) & 0 xff] << 16 ) ^
(aes_sbox[(in >> 24 ) & 0 xff] << 24 );
}
/**
* aes_expandkey - Expands the AES key as described in FIPS-197
* @ctx: The location where the computed key will be stored.
* @in_key: The supplied key.
* @key_len: The length of the supplied key.
*
* Returns 0 on success. The function fails only if an invalid key size (or
* pointer) is supplied.
* The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes
* key schedule plus a 16 bytes key which is used before the first round).
* The decryption key is prepared for the "Equivalent Inverse Cipher" as
* described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is
* for the initial combination, the second slot for the first round and so on.
*/
int aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
unsigned int key_len)
{
u32 kwords = key_len / sizeof (u32);
u32 rc, i, j;
int err;
err = aes_check_keylen(key_len);
if (err)
return err;
ctx->key_length = key_len;
for (i = 0 ; i < kwords; i++)
ctx->key_enc[i] = get_unaligned_le32(in_key + i * sizeof (u32));
for (i = 0 , rc = 1 ; i < 10 ; i++, rc = mul_by_x(rc)) {
u32 *rki = ctx->key_enc + (i * kwords);
u32 *rko = rki + kwords;
rko[0 ] = ror32(subw(rki[kwords - 1 ]), 8 ) ^ rc ^ rki[0 ];
rko[1 ] = rko[0 ] ^ rki[1 ];
rko[2 ] = rko[1 ] ^ rki[2 ];
rko[3 ] = rko[2 ] ^ rki[3 ];
if (key_len == AES_KEYSIZE_192) {
if (i >= 7 )
break ;
rko[4 ] = rko[3 ] ^ rki[4 ];
rko[5 ] = rko[4 ] ^ rki[5 ];
} else if (key_len == AES_KEYSIZE_256) {
if (i >= 6 )
break ;
rko[4 ] = subw(rko[3 ]) ^ rki[4 ];
rko[5 ] = rko[4 ] ^ rki[5 ];
rko[6 ] = rko[5 ] ^ rki[6 ];
rko[7 ] = rko[6 ] ^ rki[7 ];
}
}
/*
* Generate the decryption keys for the Equivalent Inverse Cipher.
* This involves reversing the order of the round keys, and applying
* the Inverse Mix Columns transformation to all but the first and
* the last one.
*/
ctx->key_dec[0 ] = ctx->key_enc[key_len + 24 ];
ctx->key_dec[1 ] = ctx->key_enc[key_len + 25 ];
ctx->key_dec[2 ] = ctx->key_enc[key_len + 26 ];
ctx->key_dec[3 ] = ctx->key_enc[key_len + 27 ];
for (i = 4 , j = key_len + 20 ; j > 0 ; i += 4 , j -= 4 ) {
ctx->key_dec[i] = inv_mix_columns(ctx->key_enc[j]);
ctx->key_dec[i + 1 ] = inv_mix_columns(ctx->key_enc[j + 1 ]);
ctx->key_dec[i + 2 ] = inv_mix_columns(ctx->key_enc[j + 2 ]);
ctx->key_dec[i + 3 ] = inv_mix_columns(ctx->key_enc[j + 3 ]);
}
ctx->key_dec[i] = ctx->key_enc[0 ];
ctx->key_dec[i + 1 ] = ctx->key_enc[1 ];
ctx->key_dec[i + 2 ] = ctx->key_enc[2 ];
ctx->key_dec[i + 3 ] = ctx->key_enc[3 ];
return 0 ;
}
EXPORT_SYMBOL(aes_expandkey);
/**
* aes_encrypt - Encrypt a single AES block
* @ctx: Context struct containing the key schedule
* @out: Buffer to store the ciphertext
* @in: Buffer containing the plaintext
*/
void aes_encrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in)
{
const u32 *rkp = ctx->key_enc + 4 ;
int rounds = 6 + ctx->key_length / 4 ;
u32 st0[4 ], st1[4 ];
int round;
st0[0 ] = ctx->key_enc[0 ] ^ get_unaligned_le32(in);
st0[1 ] = ctx->key_enc[1 ] ^ get_unaligned_le32(in + 4 );
st0[2 ] = ctx->key_enc[2 ] ^ get_unaligned_le32(in + 8 );
st0[3 ] = ctx->key_enc[3 ] ^ get_unaligned_le32(in + 12 );
/*
* Force the compiler to emit data independent Sbox references,
* by xoring the input with Sbox values that are known to add up
* to zero. This pulls the entire Sbox into the D-cache before any
* data dependent lookups are done.
*/
st0[0 ] ^= aes_sbox[ 0 ] ^ aes_sbox[ 64 ] ^ aes_sbox[134 ] ^ aes_sbox[195 ];
st0[1 ] ^= aes_sbox[16 ] ^ aes_sbox[ 82 ] ^ aes_sbox[158 ] ^ aes_sbox[221 ];
st0[2 ] ^= aes_sbox[32 ] ^ aes_sbox[ 96 ] ^ aes_sbox[160 ] ^ aes_sbox[234 ];
st0[3 ] ^= aes_sbox[48 ] ^ aes_sbox[112 ] ^ aes_sbox[186 ] ^ aes_sbox[241 ];
for (round = 0 ;; round += 2 , rkp += 8 ) {
st1[0 ] = mix_columns(subshift(st0, 0 )) ^ rkp[0 ];
st1[1 ] = mix_columns(subshift(st0, 1 )) ^ rkp[1 ];
st1[2 ] = mix_columns(subshift(st0, 2 )) ^ rkp[2 ];
st1[3 ] = mix_columns(subshift(st0, 3 )) ^ rkp[3 ];
if (round == rounds - 2 )
break ;
st0[0 ] = mix_columns(subshift(st1, 0 )) ^ rkp[4 ];
st0[1 ] = mix_columns(subshift(st1, 1 )) ^ rkp[5 ];
st0[2 ] = mix_columns(subshift(st1, 2 )) ^ rkp[6 ];
st0[3 ] = mix_columns(subshift(st1, 3 )) ^ rkp[7 ];
}
put_unaligned_le32(subshift(st1, 0 ) ^ rkp[4 ], out);
put_unaligned_le32(subshift(st1, 1 ) ^ rkp[5 ], out + 4 );
put_unaligned_le32(subshift(st1, 2 ) ^ rkp[6 ], out + 8 );
put_unaligned_le32(subshift(st1, 3 ) ^ rkp[7 ], out + 12 );
}
EXPORT_SYMBOL(aes_encrypt);
/**
* aes_decrypt - Decrypt a single AES block
* @ctx: Context struct containing the key schedule
* @out: Buffer to store the plaintext
* @in: Buffer containing the ciphertext
*/
void aes_decrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in)
{
const u32 *rkp = ctx->key_dec + 4 ;
int rounds = 6 + ctx->key_length / 4 ;
u32 st0[4 ], st1[4 ];
int round;
st0[0 ] = ctx->key_dec[0 ] ^ get_unaligned_le32(in);
st0[1 ] = ctx->key_dec[1 ] ^ get_unaligned_le32(in + 4 );
st0[2 ] = ctx->key_dec[2 ] ^ get_unaligned_le32(in + 8 );
st0[3 ] = ctx->key_dec[3 ] ^ get_unaligned_le32(in + 12 );
/*
* Force the compiler to emit data independent Sbox references,
* by xoring the input with Sbox values that are known to add up
* to zero. This pulls the entire Sbox into the D-cache before any
* data dependent lookups are done.
*/
st0[0 ] ^= aes_inv_sbox[ 0 ] ^ aes_inv_sbox[ 64 ] ^ aes_inv_sbox[129 ] ^ aes_inv_sbox[200 ];
st0[1 ] ^= aes_inv_sbox[16 ] ^ aes_inv_sbox[ 83 ] ^ aes_inv_sbox[150 ] ^ aes_inv_sbox[212 ];
st0[2 ] ^= aes_inv_sbox[32 ] ^ aes_inv_sbox[ 96 ] ^ aes_inv_sbox[160 ] ^ aes_inv_sbox[236 ];
st0[3 ] ^= aes_inv_sbox[48 ] ^ aes_inv_sbox[112 ] ^ aes_inv_sbox[187 ] ^ aes_inv_sbox[247 ];
for (round = 0 ;; round += 2 , rkp += 8 ) {
st1[0 ] = inv_mix_columns(inv_subshift(st0, 0 )) ^ rkp[0 ];
st1[1 ] = inv_mix_columns(inv_subshift(st0, 1 )) ^ rkp[1 ];
st1[2 ] = inv_mix_columns(inv_subshift(st0, 2 )) ^ rkp[2 ];
st1[3 ] = inv_mix_columns(inv_subshift(st0, 3 )) ^ rkp[3 ];
if (round == rounds - 2 )
break ;
st0[0 ] = inv_mix_columns(inv_subshift(st1, 0 )) ^ rkp[4 ];
st0[1 ] = inv_mix_columns(inv_subshift(st1, 1 )) ^ rkp[5 ];
st0[2 ] = inv_mix_columns(inv_subshift(st1, 2 )) ^ rkp[6 ];
st0[3 ] = inv_mix_columns(inv_subshift(st1, 3 )) ^ rkp[7 ];
}
put_unaligned_le32(inv_subshift(st1, 0 ) ^ rkp[4 ], out);
put_unaligned_le32(inv_subshift(st1, 1 ) ^ rkp[5 ], out + 4 );
put_unaligned_le32(inv_subshift(st1, 2 ) ^ rkp[6 ], out + 8 );
put_unaligned_le32(inv_subshift(st1, 3 ) ^ rkp[7 ], out + 12 );
}
EXPORT_SYMBOL(aes_decrypt);
MODULE_DESCRIPTION("Generic AES library" );
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>" );
MODULE_LICENSE("GPL v2" );
Messung V0.5 in Prozent C=97 H=86 G=91
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland