STM32: 实现Advanced Encryption Standard(AES) – 128-bit加密算法

AES加密算法是对称加密算法(symmetric-key algorithm)的一种。对称加密就意味着加密,解密中使用的key是相同的。从实现的算法来看,在加密解密的过程中,不需要动态分配内存,算法比较简捷,对于嵌入式系统来说好处多多。

这里主要是针对128-bit的AES加密算法的分析与实现。

  • 原理

请先看下面一段flash(来自http://www.formaestudio.com/rijndaelinspector/archivos/Rijndael_Animation_v4_eng.swf)

NOTE:

- 演示中的数值可能存在错误,具体请看:http://coolshell.cn/articles/3161.html#comment-114419

Key Schedule 这一步里面,Round key 2 的第三列错了。
23,a3,39,39 应该为 59,25,80,7a;前面的步骤出现过正确的值,可以对照。

- P3中的State表示的是明文,而Cipher key表示的是16字节(128-bit的密钥)

对于128-bit的加密算法来说, 16字节的Cipher key会通过Key Schedule扩展成176字节,具体的扩展方法请看:http://www.samiam.org/key-schedule.html, 当然在进行Key扩展时,会使用到:

a. S-box – https://en.wikipedia.org/wiki/Rijndael_S-box

b. Rcon – https://en.wikipedia.org/wiki/Rijndael_key_schedule

c. Finite field arithmetic – https://en.wikipedia.org/wiki/Finite_field_arithmetic#Rijndael.27s_finite_field

 

权威文档:http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf

中文文档请看:http://www.cnblogs.com/luop/p/4334160.html

  • 加密算法C语言实现 – 辅助定义
#define AES_MAXNR		14
#define ROTL8(x,shift) ((uint8_t) ((x) << (shift)) | ((x) >> (8 - (shift))))

#undef ROTATE
#if defined(_MSC_VER) || defined(__ICC)
# define ROTATE(a,n)	_lrotl(a,n)
#elif defined(__GNUC__) && __GNUC__>=2
# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
#   define ROTATE(a,n)	({ register unsigned int ret;	\
				asm (			\
				"roll %1,%0"		\
				: "=r"(ret)		\
				: "I"(n), "0"(a)	\
				: "cc");		\
			   ret;				\
			})
# endif
#endif

typedef struct {
	uint32_t rd_key[4 * (AES_MAXNR + 1)];
	int32_t rounds;
	uint8_t sbox[256];
} AES_KEY;
  • 加密算法C语言实现 – 加密过程

1.  计算sbox

// https://en.wikipedia.org/wiki/Rijndael_S-box
static void initialize_aes_sbox(uint8_t *sbox)
{
    /* loop invariant: p * q == 1 in the Galois field */
    uint8_t p = 1, q = 1;
    do {
        /* multiply p by x+1 */
        p = p ^ (p << 1) ^ (p & 0x80 ? 0x1B : 0);
        /* divide q by x+1 */
        q ^= q << 1;
        q ^= q << 2;
        q ^= q << 4;
        q ^= q & 0x80 ? 0x09 : 0;
        /* compute the affine transformation */
        sbox[p] = 0x63 ^ q ^ ROTL8(q, 1) ^ ROTL8(q, 2) ^ ROTL8(q, 3) ^ ROTL8(q, 4);
    } while (p != 1);
    /* 0 is a special case since it has no inverse */
    sbox[0] = 0x63;
}

2. Rcon实现

static uint8_t rcon(uint8_t i) {
    uint8_t c;

    for (c = 1; i != 1; i--)
        c = c << 1 ^ (c & 0x80 ? 0x1b : 0);

    return c;
}

3. 乘法运算实现

// https://en.wikipedia.org/wiki/Finite_field_arithmetic
/* Multiply two numbers in the GF(2^8) finite field defined 
 * by the polynomial x^8 + x^4 + x^3 + x + 1 = 0
 * using the Russian Peasant Multiplication algorithm
 * (the other way being to do carry-less multiplication followed by a modular reduction)
 */
static uint8_t gmul(uint8_t a, uint8_t b) {
    uint8_t p = 0; /* the product of the multiplication */
    while (b) {
        if (b & 1) /* if b is odd, then add the corresponding a to p (final product = sum of all a's corresponding to odd b's) */
            p ^= a; /* since we're in GF(2^m), addition is an XOR */

        if (a & 0x80) /* GF modulo: if a >= 128, then it will overflow when shifted left, so reduce */
            a = (a << 1) ^ 0x11b; /* XOR with the primitive polynomial x^8 + x^4 + x^3 + x + 1 (0b1_0001_1011) -- you can change it but it must be irreducible */
        else
            a <<= 1; /* equivalent to a*2 */
        b >>= 1; /* equivalent to b // 2 */
    }
    return p;
}

4. 加密使用的key扩展

int AES_set_encrypt_key(const uint8_t *userKey, const uint32_t bits, AES_KEY *key)
{
    uint32_t i, v1, v2, v3, v4, v5;

    if (bits != 128) return -1;

    key->rounds = 10;
    initialize_aes_sbox(key->sbox);

    v1 = key->rd_key[0] = *(uint32_t *)(userKey +  0);
    v2 = key->rd_key[1] = *(uint32_t *)(userKey +  4);
    v3 = key->rd_key[2] = *(uint32_t *)(userKey +  8);
    v4 = key->rd_key[3] = *(uint32_t *)(userKey + 12);

    uint8_t *sbox = key->sbox;

    for (i = 1; i <= key->rounds; i++) {
        v5 = sbox[(v4 >> 24) & 0xff] <<  0 |
                sbox[(v4 >> 16) & 0xff] << 24 |
                sbox[(v4 >>  8) & 0xff] << 16 |
                sbox[(v4 >>  0) & 0xff] <<  8;
        v1 = rcon(i) << 24 ^ v5 ^ v1;
        v2 = v1 ^ v2;
        v3 = v2 ^ v3;
        v4 = v3 ^ v4;

        key->rd_key[4 * i + 0] = v1;
        key->rd_key[4 * i + 1] = v2;
        key->rd_key[4 * i + 2] = v3;
        key->rd_key[4 * i + 3] = v4;
    }

    return 0;
}

NOTE:

这里加密所使用的rcon并非标准:

unsigned char rcon[256] = {
    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 
    0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 
    0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 
    0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 
    0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 
    0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 
    0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 
    0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 
    0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 
    0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 
    0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 
    0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 
    0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 
    0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 
    0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 
    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
}

而是将对应的数值向左移了24位,所以经过这个算法加密的数据,不能通过openssl这种标准的算法来进行解密。

与标准算法的区别请看这篇:

STM32: 实现AES 128-bit加密算法 - 标准实现

5. 加密算法

void AES_encrypt(const uint8_t *text, uint8_t *cipher, const AES_KEY *key)
{
	uint32_t v1, v2, v3, v4;
	uint32_t v11, v12, v13, v14;
	uint32_t v17, v18, v20;

	v1 = key->rd_key[0] ^ *(uint32_t *)(text +  0);
	v2 = key->rd_key[1] ^ *(uint32_t *)(text +  4);
	v3 = key->rd_key[2] ^ *(uint32_t *)(text +  8);
	v4 = key->rd_key[3] ^ *(uint32_t *)(text + 12);

	const uint8_t *sbox = key->sbox;

	for (v20 = 1; v20 < 10; v20++) {
		v11 = sbox[(v1 >> 24) & 0xFF] << 24 | sbox[(v2 >> 16) & 0xFF] << 16 | sbox[(v3 >>  8) & 0xFF] <<  8 | sbox[(v4 >>  0) & 0xFF] <<  0;
		v12 = sbox[(v1 >>  0) & 0xFF] <<  0 | sbox[(v2 >> 24) & 0xFF] << 24 | sbox[(v3 >> 16) & 0xFF] << 16 | sbox[(v4 >>  8) & 0xFF] <<  8;
		v13 = sbox[(v1 >>  8) & 0xFF] <<  8 | sbox[(v2 >>  0) & 0xFF] <<  0 | sbox[(v3 >> 24) & 0xFF] << 24 | sbox[(v4 >> 16) & 0xFF] << 16;
		v14 = sbox[(v1 >> 16) & 0xFF] << 16 | sbox[(v2 >>  8) & 0xFF] <<  8 | sbox[(v3 >>  0) & 0xFF] <<  0 | sbox[(v4 >> 24) & 0xFF] << 24;

		/*****************************************************************************
		v1  = [ a1 a2 a3 a4 ] <- 0xa1a2a3a4
		v2  = [ b1 b2 b3 b4 ] <- 0xb1b2b3b4
		v3  = [ c1 c2 c3 c4 ] <- 0xc1c2c3c4
		v4  = [ d1 d2 d3 d4 ] <- 0xd1d2d3d4

		v11 = [ a1 b2 c3 d4 ] <- 0xa1b2c3d4
		v12 = [ b1 c2 d3 a4 ] <- 0xb1c2d3a4
		v13 = [ c1 d2 a3 b4 ] <- 0xc1d2a3b4
		v14 = [ d1 a2 b3 c4 ] <- 0xd1a2b3c4

		v1 = \
			[ 02 03 01 01 ] [ a1 ]
			[ 01 02 03 01 ] [ b2 ]
			[ 01 01 02 03 ] [ c3 ]
			[ 03 01 01 02 ] [ d4 ]
		   = \
			(02*a1 ^ 03*b2 ^ 01*c3 ^ 01*d4) << 24 |		<- (02*a1 ^ 03*b2 ^ 01*c3 ^ 01*d4) << 24
			(01*a1 ^ 02*b2 ^ 03*c3 ^ 01*d4) << 16 |		<- (02*b2 ^ 03*c3 ^ 01*d1 ^ 01*a1) << 16
			(01^a1 ^ 01*b2 ^ 02*c3 ^ 03*d4) <<  8 |		<- (02*c3 ^ 03*d4 ^ 01*a1 ^ 01*b2) <<  8
			(03*a1 ^ 01*b2 ^ 01*c3 ^ 02*d4) <<  0 		<- (02*d4 ^ 03*a1 ^ 01*b2 ^ 01*c3) <<  0
		--------------------------------------------------------------------------------------------

		[ 0e 0b 0d 09 ] [ 02 03 01 01 ]   [ 01 00 00 00 ]
		[ 09 0e 0b 0d ] [ 01 02 03 01 ]   [ 00 01 00 00 ]
                                        =
		[ 0d 09 0e 0b ] [ 01 01 02 03 ]   [ 00 00 01 00 ]
		[ 0b 0d 09 0e ] [ 03 01 01 02 ]   [ 00 00 00 01 ]
		*****************************************************************************/
		v17 = ROTATE(v11, 16);
		v18 = ROTATE(v11, 24);
		v1 = key->rd_key[4 * v20 + 0] ^ 0x1B * ((v11 >> 7) & 0x1010101) ^ 2 * (v11 & 0xFF7F7F7F) ^
				((2 * (v11 & 0x7F000000) ^ 0x1B * ((v11 >> 7) & 0x1010101) ^ v11) >> 24 | (0x1B * ((v11 >> 7) & 0x10101) ^ 2 * (v11 & 0xFFFF7F7F) ^ v11) << 8) ^ v18 ^ v17;

		v17 = ROTATE(v12, 16);
		v18 = ROTATE(v12, 24);
		v2 = key->rd_key[4 * v20 + 1] ^ 0x1B * ((v12 >> 7) & 0x1010101) ^ 2 * (v12 & 0xFF7F7F7F) ^
				((2 * (v12 & 0x7F000000) ^ 0x1B * ((v12 >> 7) & 0x1010101) ^ v12) >> 24 | (0x1B * ((v12 >> 7) & 0x10101) ^ 2 * (v12 & 0xFFFF7F7F) ^ v12) << 8) ^ v18 ^ v17;

		v17 = ROTATE(v13, 16);
		v18 = ROTATE(v13, 24);
		v3 = key->rd_key[4 * v20 + 2] ^ 0x1B * ((v13 >> 7) & 0x1010101) ^ 2 * (v13 & 0xFF7F7F7F) ^
				((2 * (v13 & 0x7F000000) ^ 0x1B * ((v13 >> 7) & 0x1010101) ^ v13) >> 24 | (0x1B * ((v13 >> 7) & 0x10101) ^ 2 * (v13 & 0xFFFF7F7F) ^ v13) << 8) ^ v18 ^ v17;

		v17 = ROTATE(v14, 16);
		v18 = ROTATE(v14, 24);
		v4 = key->rd_key[4 * v20 + 3] ^ 0x1B * ((v14 >> 7) & 0x1010101) ^ 2 * (v14 & 0xFF7F7F7F) ^
				((2 * (v14 & 0x7F000000) ^ 0x1B * ((v14 >> 7) & 0x1010101) ^ v14) >> 24 | (0x1B * ((v14 >> 7) & 0x10101) ^ 2 * (v14 & 0xFFFF7F7F) ^ v14) << 8) ^ v18 ^ v17;
	}

	// v1 v2, v3, v4
	*(uint32_t *)(cipher +  0) = key->rd_key[4 * v20 + 0] ^
			(sbox[(v1 >> 24) & 0xFF] << 24 | sbox[(v2 >> 16) & 0xFF] << 16 | sbox[(v3 >>  8) & 0xFF] <<  8 | sbox[(v4 >>  0) & 0xFF] <<  0);

	*(uint32_t *)(cipher +  4) = key->rd_key[4 * v20 + 1] ^
			(sbox[(v1 >>  0) & 0xFF] <<  0 | sbox[(v2 >> 24) & 0xFF] << 24 | sbox[(v3 >> 16) & 0xFF] << 16 | sbox[(v4 >>  8) & 0xFF] <<  8);

	*(uint32_t *)(cipher +  8) = key->rd_key[4 * v20 + 2] ^
			(sbox[(v1 >>  8) & 0xFF] <<  8 | sbox[(v2 >>  0) & 0xFF] <<  0 | sbox[(v3 >> 24) & 0xFF] << 24 | sbox[(v4 >> 16) & 0xFF] << 16);

	*(uint32_t *)(cipher + 12) = key->rd_key[4 * v20 + 3] ^
			(sbox[(v1 >> 16) & 0xFF] << 16 | sbox[(v2 >>  8) & 0xFF] <<  8 | sbox[(v3 >>  0) & 0xFF] <<  0 | sbox[(v4 >> 24) & 0xFF] << 24);
}
  • 加密算法C语言实现 –  解密过程

1. 计算inv_sbox

static void initialize_aes_inv_sbox(uint8_t *inv_sbox)
{
	uint8_t sbox[256];
	int32_t i;

	initialize_aes_sbox(sbox);

	for (i = 0; i < 256; i++) inv_sbox[sbox[i]] = i;
}

NOTE: 通过已知的sbox计算出inv sbox

2. 解密所需的key扩展

int AES_set_decrypt_key(const uint8_t *userKey, const uint32_t bits, AES_KEY *key)
{
	uint32_t i, v1, v2, v3, v4, v5;

	if (bits != 128) return -1;

	key->rounds = 10;
	initialize_aes_sbox(key->sbox);

	v1 = key->rd_key[0] = *(uint32_t *)(userKey +  0);
	v2 = key->rd_key[1] = *(uint32_t *)(userKey +  4);
	v3 = key->rd_key[2] = *(uint32_t *)(userKey +  8);
	v4 = key->rd_key[3] = *(uint32_t *)(userKey + 12);

	uint8_t *sbox = key->sbox;

	for (i = 1; i <= key->rounds; i++) {
		v5 = sbox[(v4 >> 24) & 0xff] <<  0 |
				sbox[(v4 >> 16) & 0xff] << 24 |
				sbox[(v4 >>  8) & 0xff] << 16 |
				sbox[(v4 >>  0) & 0xff] <<  8;
		v1 = rcon(i) << 24 ^ v5 ^ v1;
		v2 = v1 ^ v2;
		v3 = v2 ^ v3;
		v4 = v3 ^ v4;

		key->rd_key[4 * i + 0] = v1;
		key->rd_key[4 * i + 1] = v2;
		key->rd_key[4 * i + 2] = v3;
		key->rd_key[4 * i + 3] = v4;
	}

	initialize_aes_inv_sbox(key->sbox);

	return 0;
}

3. 解密算法

void AES_decrypt(const uint8_t *cipher, uint8_t *text, const AES_KEY *key)
{
	uint32_t v1, v2, v3, v4, v11, v12, v13, v14;
	const uint8_t *inv_sbox = key->sbox;
	uint32_t v20 = key->rounds;

	v11 = *(uint32_t *)(cipher +  0) ^ key->rd_key[v20 * 4 + 0];
	v12 = *(uint32_t *)(cipher +  4) ^ key->rd_key[v20 * 4 + 1];
	v13 = *(uint32_t *)(cipher +  8) ^ key->rd_key[v20 * 4 + 2];
	v14 = *(uint32_t *)(cipher + 12) ^ key->rd_key[v20 * 4 + 3];

	v1 = inv_sbox[(v11 >> 24) & 0xff] << 24 |
		 inv_sbox[(v14 >> 16) & 0xff] << 16 |
		 inv_sbox[(v13 >>  8) & 0xff] <<  8 |
		 inv_sbox[(v12 >>  0) & 0xff] <<  0;

	v2 = inv_sbox[(v12 >> 24) & 0xff] << 24 |
		 inv_sbox[(v11 >> 16) & 0xff] << 16 |
		 inv_sbox[(v14 >>  8) & 0xff] <<  8 |
		 inv_sbox[(v13 >>  0) & 0xff] <<  0;

	v3 = inv_sbox[(v13 >> 24) & 0xff] << 24 |
		 inv_sbox[(v12 >> 16) & 0xff] << 16 |
		 inv_sbox[(v11 >>  8) & 0xff] <<  8 |
		 inv_sbox[(v14 >>  0) & 0xff] <<  0;

	v4 = inv_sbox[(v14 >> 24) & 0xff] << 24 |
		 inv_sbox[(v13 >> 16) & 0xff] << 16 |
		 inv_sbox[(v12 >>  8) & 0xff] <<  8 |
		 inv_sbox[(v11 >>  0) & 0xff] <<  0;

	for (v20--; v20 >= 1; v20--) {
		uint32_t *v30[4] = { &v1, &v2, &v3, &v4 };
		uint8_t a1, a2, a3, a4;
		int32_t i;
		/************************************************************************
		v1 = 0xa1a2a3a4
		v11 = \
				[ 0e 0b 0d 09 ]   [ a1 ]
				[ 09 0e 0b 0d ]   [ a2 ]
				[ 0d 09 0e 0b ]   [ a3 ]
				[ 0b 0d 09 0e ]   [ a4 ]
		    = \
				(0e*a1 ^ 0b*a2 ^ 0d*a3 ^ 09*a4) << 24 |
				(09*a1 ^ 0e*a2 ^ 0b*a3 ^ 0d*a4) << 16 |
				(0d*a1 ^ 09*a2 ^ 0e*a3 ^ 0b*a4) <<  8 |
				(0b*a1 ^ 0d*a2 ^ 09*a3 ^ 0e*a4) <<  0
		*************************************************************************/
		for (i = 0; i < 4; i++) {
			uint32_t *v = v30[i];
			*v ^= key->rd_key[4 * v20 + i];

			a1 = (*v >> 24) & 0xff;
			a2 = (*v >> 16) & 0xff;
			a3 = (*v >>  8) & 0xff;
			a4 = (*v >>  0) & 0xff;

			*v = (gmul(a1, 0x0e) ^ gmul(a2, 0x0b) ^ gmul(a3, 0x0d) ^ gmul(a4, 0x09)) << 24 |
					 (gmul(a1, 0x09) ^ gmul(a2, 0x0e) ^ gmul(a3, 0x0b) ^ gmul(a4, 0x0d)) << 16 |
					 (gmul(a1, 0x0d) ^ gmul(a2, 0x09) ^ gmul(a3, 0x0e) ^ gmul(a4, 0x0b)) <<  8 |
					 (gmul(a1, 0x0b) ^ gmul(a2, 0x0d) ^ gmul(a3, 0x09) ^ gmul(a4, 0x0e)) <<  0;
		}
		
		v11 = inv_sbox[(v1 >> 24) & 0xff] << 24 |
			 inv_sbox[(v4 >> 16) & 0xff] << 16 |
			 inv_sbox[(v3 >>  8) & 0xff] <<  8 |
			 inv_sbox[(v2 >>  0) & 0xff] <<  0;

		v12 = inv_sbox[(v2 >> 24) & 0xff] << 24 |
			 inv_sbox[(v1 >> 16) & 0xff] << 16 |
			 inv_sbox[(v4 >>  8) & 0xff] <<  8 |
			 inv_sbox[(v3 >>  0) & 0xff] <<  0;

		v13 = inv_sbox[(v3 >> 24) & 0xff] << 24 |
			 inv_sbox[(v2 >> 16) & 0xff] << 16 |
			 inv_sbox[(v1 >>  8) & 0xff] <<  8 |
			 inv_sbox[(v4 >>  0) & 0xff] <<  0;

		v14 = inv_sbox[(v4 >> 24) & 0xff] << 24 |
			 inv_sbox[(v3 >> 16) & 0xff] << 16 |
			 inv_sbox[(v2 >>  8) & 0xff] <<  8 |
			 inv_sbox[(v1 >>  0) & 0xff] <<  0;

		v1 = v11; v2 = v12; v3 = v13; v4 = v14;
	}

	*(uint32_t *)(text +  0) = key->rd_key[0] ^ v1;
	*(uint32_t *)(text +  4) = key->rd_key[1] ^ v2;
	*(uint32_t *)(text +  8) = key->rd_key[2] ^ v3;
	*(uint32_t *)(text + 12) = key->rd_key[3] ^ v4;
}
  • 加密算法C语言实现 –  演示

1. 代码

int main(int argc, char *argv[])
{
	// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
	// Expansion of a 128-bit Cipher Key
	uint8_t userKey[] = {
		0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
		0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
	};
	uint8_t text[] = {
		'w', 'w', 'w', '.', 'b', 'r', 'o', 'b', 'w', 'i', 'n', 'd', '.', 'c', 'o', 'm'
	};
	uint8_t cipher[16];
	AES_KEY aes_key;

	memset(&aes_key, 0x00, sizeof(aes_key));

	AES_set_encrypt_key(userKey, 128, &aes_key);
	printf(" --------------------- AES 128 ENC EXPANDED KEY -------------------------\n");
	hexdump(aes_key.rd_key, sizeof(aes_key.rd_key), 0, NULL);

	AES_encrypt(text, cipher, &aes_key);
	printf(" --------------------- AES 128 ENC - CIPHER -----------------------------\n");
	hexdump(cipher, sizeof(cipher), 0, NULL);

	AES_set_decrypt_key(userKey, 128, &aes_key);
	printf(" --------------------- AES 128 DEC EXPANDED KEY -------------------------\n");
	hexdump(aes_key.rd_key, sizeof(aes_key.rd_key), 0, NULL);

	memset(text, 0x00, sizeof(text));

	AES_decrypt(cipher, text, &aes_key);
	printf(" --------------------- AES 128 DEC - TEXT -------------------------------\n");
	hexdump(text, sizeof(text), 0, NULL);

	return 0;
}

2. 结果

 --------------------- AES 128 ENC EXPANDED KEY -------------------------
00000000: 2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c  +~..(.........O<
00000010: c0 7f 9f 93 e8 d1 4d 35 43 26 58 bd 4a e9 17 81  ......M5C&X.J...
00000020: cc a9 81 61 24 78 cc 54 67 5e 94 e9 2d b7 83 68  ...a$x.Tg^..-..h
00000030: 89 71 28 89 ad 09 e4 dd ca 57 70 34 e7 e0 f3 5c  .q(......Wp4...\
00000040: c3 e5 c9 8c 6e ec 2d 51 a4 bb 5d 65 43 5b ae 39  ....n.-Q..]eC[.9
00000050: d1 ff f0 78 bf 13 dd 29 1b a8 80 4c 58 f3 2e 75  ...x...)...LX..u
00000060: 4c 95 fd 69 f3 86 20 40 e8 2e a0 0c b0 dd 8e 79  L..i.. @.......y
00000070: fa 72 3c 30 09 f4 1c 70 e1 da bc 7c 51 07 32 05  .r<0...p...|Q.2.
00000080: 91 a3 f9 93 98 57 e5 e3 79 8d 59 9f 28 8a 6b 9a  .....W..y.Y.(.k.
00000090: 29 97 87 f7 b1 c0 62 14 c8 4d 3b 8b e0 c7 50 11  ).....b..M;...P.
000000a0: ab 76 41 92 1a b6 23 86 d2 fb 18 0d 32 3c 48 1c  .vA...#.....2<H.
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 --------------------- AES 128 ENC - CIPHER -----------------------------
00000000: b6 08 04 bc 5f 65 f2 b3 d7 16 f7 6f d6 6a a2 27  ...._e.....o.j.'
 --------------------- AES 128 DEC EXPANDED KEY -------------------------
00000000: 2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c  +~..(.........O<
00000010: c0 7f 9f 93 e8 d1 4d 35 43 26 58 bd 4a e9 17 81  ......M5C&X.J...
00000020: cc a9 81 61 24 78 cc 54 67 5e 94 e9 2d b7 83 68  ...a$x.Tg^..-..h
00000030: 89 71 28 89 ad 09 e4 dd ca 57 70 34 e7 e0 f3 5c  .q(......Wp4...\
00000040: c3 e5 c9 8c 6e ec 2d 51 a4 bb 5d 65 43 5b ae 39  ....n.-Q..]eC[.9
00000050: d1 ff f0 78 bf 13 dd 29 1b a8 80 4c 58 f3 2e 75  ...x...)...LX..u
00000060: 4c 95 fd 69 f3 86 20 40 e8 2e a0 0c b0 dd 8e 79  L..i.. @.......y
00000070: fa 72 3c 30 09 f4 1c 70 e1 da bc 7c 51 07 32 05  .r<0...p...|Q.2.
00000080: 91 a3 f9 93 98 57 e5 e3 79 8d 59 9f 28 8a 6b 9a  .....W..y.Y.(.k.
00000090: 29 97 87 f7 b1 c0 62 14 c8 4d 3b 8b e0 c7 50 11  ).....b..M;...P.
000000a0: ab 76 41 92 1a b6 23 86 d2 fb 18 0d 32 3c 48 1c  .vA...#.....2<H.
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 --------------------- AES 128 DEC - TEXT -------------------------------
00000000: 77 77 77 2e 62 72 6f 62 77 69 6e 64 2e 63 6f 6d  www.brobwind.com
  • 加密算法C语言实现 –  源代码

完整的代码可以从这里下载:

$ git clone https://github.com/brobwind/bro_aes.git

代码结构:

bro_aes
+-- Makefile
+-- README.md
+-- bro_aes.c
+-- bro_aes.h
+-- bro_util.c
+-- bro_util.h
`-- main.c

使用Makefile编译系统。

  • 相关的参考文档:
  1. http://crypto.stackexchange.com/questions/2418/how-to-use-rcon-in-key-expansion-of-128-bit-advanced-encryption-standard
  2. http://www.cnblogs.com/luop/p/4334160.html
  3. http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
  4. http://www.samiam.org/key-schedule.html
  5. http://www.formaestudio.com/rijndaelinspector/archivos/Rijndael_Animation_v4_eng.swf
  6. http://www.adamberent.com/documents/AESbyExample.htm
  7. http://www.efgh.com/software/rijndael.htm

《STM32: 实现Advanced Encryption Standard(AES) – 128-bit加密算法》有15个想法

  1. http://extranet.cryptomathic.com/aescalc/index?key=2b7e151628aed2a6abf7158809cf4f3c&iv=00000000000000000000000000000000&input=7777772e62726f6277696e642e636f6d&mode=ecb&action=Encrypt&output=

    Key : 2B7E151628AED2A6ABF7158809CF4F3C
    Input Data : 7777772E62726F6277696E642E636F6D <– www.brobwind.com
    Output Data : 7607B8E394C51976AB885254AC658D22

    http://testprotect.com/appendix/AEScalc
    和上面相同

    http://aes.online-domain-tools.com/

    Input Data : www.brobwind.com
    Key : 2B7E151628AED2A6ABF7158809CF4F3C
    Output Data : 7607B8E394C51976AB885254AC658D22

    和你加密的结果对不住?

    b6 08 04 bc 5f 65 f2 b3 d7 16 f7 6f d6 6a a2 27

    是应为文中提到的原因吗?

    NOTE:
    这里加密所使用的rcon并非标准:
    而是将对应的数值向左移了24位,所以经过这个算法加密的数据,
    不能通过openssl这种标准的算法来进行解密。

  2. http://extranet.cryptomathic.com/aescalc/index?key=2b7e151628aed2a6abf7158809cf4f3c&iv=00000000000000000000000000000000&input=7777772e62726f6277696e642e636f6d&mode=ecb&action=Encrypt&output=

    Key : 2B7E151628AED2A6ABF7158809CF4F3C
    Input Data : 7777772E62726F6277696E642E636F6D <– http://www.brobwind.com
    Output Data : 7607B8E394C51976AB885254AC658D22

  3. http://aes.online-domain-tools.com/

    Input Data : http://www.brobwind.com
    Key : 2B7E151628AED2A6ABF7158809CF4F3C
    Output Data : 7607B8E394C51976AB885254AC658D22

    和你加密的结果对不住?

    b6 08 04 bc 5f 65 f2 b3 d7 16 f7 6f d6 6a a2 27

  4. 是因为文中提到的原因吗?

    NOTE:
    这里加密所使用的rcon并非标准:
    而是将对应的数值向左移了24位,所以经过这个算法加密的数据,
    不能通过openssl这种标准的算法来进行解密。

    1. 可以说这个并不是AES 128-bit的标准实现,主要是为了将来可以会实现一个能够与ST-LINK/V2-1 bootloader相兼容的bootloader。
      请仔细看这篇文档:https://www.brobwind.com/archives/1133
      在http://www.taylorkillian.com/2013/01/retrieving-st-linkv2-firmware-from.htm上有提到固件的加密算法为AES 128-bit, 而加密的key为”I am key, wawawa”, 所以:
      --------------------- AES 128 ENC EXPANDED KEY -------------------------
      00000000: 49 20 61 6d 20 6b 65 79 2c 20 77 61 77 61 77 61 I am key, wawawa <- Encryption key
      00000010: a6 d5 8e 99 86 be eb e0 aa 9e 9c 81 dd ff eb e0 ................
      00000020: 47 14 98 72 c1 aa 73 92 6b 34 ef 13 b6 cb 04 f3 G..r..s.k4......
      00000030: 4a 5a 87 84 8b f0 f4 16 e0 c4 1b 05 56 0f 1f f6 JZ..........V...
      00000040: 08 eb f1 4c 83 1b 05 5a 63 df 1e 5f 35 d0 01 a9 ...L...Zc.._5...
      00000050: db 7d 81 20 58 66 84 7a 3b b9 9a 25 0e 69 9b 8c .}. Xf.z;..%.i..
      00000060: bf d6 78 14 e7 b0 fc 6e dc 09 66 4b d2 60 fd c7 ..x....n..fK.
      ..
      00000070: 79 63 a8 00 9e d3 54 6e 42 da 32 25 90 ba cf e2 yc....TnB.2%....
      00000080: e1 03 5c 0a 7f d0 08 64 3d 0a 3a 41 ad b0 f5 a3 ..\....d=.:A....
      00000090: eb 96 bb f7 94 46 b3 93 a9 4c 89 d2 04 fc 7c 71 .....F...L....|q
      000000a0: 48 64 0b d1 dc 22 b8 42 75 6e 31 90 71 92 4d e1 Hd...".Bun1.q.M.
      --------------------- AES 128 ENC - CIPHER -----------------------------
      00000000: f6 5c 83 b1 d2 cf 3e e2 0c 3d 6d 17 e4 0d f1 60 .\....>..=m....
      <- Device encryption key
      --------------------- AES 128 DEC EXPANDED KEY -------------------------
      00000000: 49 20 61 6d 20 6b 65 79 2c 20 77 61 77 61 77 61 I am key, wawawa
      00000010: a6 d5 8e 99 86 be eb e0 aa 9e 9c 81 dd ff eb e0 ................
      00000020: 47 14 98 72 c1 aa 73 92 6b 34 ef 13 b6 cb 04 f3 G..r..s.k4......
      00000030: 4a 5a 87 84 8b f0 f4 16 e0 c4 1b 05 56 0f 1f f6 JZ..........V...
      00000040: 08 eb f1 4c 83 1b 05 5a 63 df 1e 5f 35 d0 01 a9 ...L...Zc.._5...
      00000050: db 7d 81 20 58 66 84 7a 3b b9 9a 25 0e 69 9b 8c .}. Xf.z;..%.i..
      00000060: bf d6 78 14 e7 b0 fc 6e dc 09 66 4b d2 60 fd c7 ..x....n..fK.
      ..
      00000070: 79 63 a8 00 9e d3 54 6e 42 da 32 25 90 ba cf e2 yc....TnB.2%....
      00000080: e1 03 5c 0a 7f d0 08 64 3d 0a 3a 41 ad b0 f5 a3 ..\....d=.:A....
      00000090: eb 96 bb f7 94 46 b3 93 a9 4c 89 d2 04 fc 7c 71 .....F...L....|q
      000000a0: 48 64 0b d1 dc 22 b8 42 75 6e 31 90 71 92 4d e1 Hd...".Bun1.q.M.
      --------------------- AES 128 DEC - TEXT -------------------------------
      00000000: 40 00 ff ff 52 ff 6c 06 49 72 51 49 15 42 16 87 @...R.l.IrQI.B.. <- Unique device ID

    2. 我本来以为只是在计算expand key的时候使用的rcon不同,所以最终的结果也不同。现在看来,在进行文本加密时,使用的算法可能也与标准的AES算法不同,有时间再进行进一步分析。
      不过这个算法与AES的标准算法还是很接近的,都有
      - SubBytes transformation
      -ShiftRows transformation
      -MixColumns transformation
      -AddRoundKey Transformation
      https://android.googlesource.com/platform/external/openssl/+/android-5.1.1_r38/crypto/aes/aes_x86core.c 虽说可以当作AES C参考实现,个人觉得学习的难度有点大。

        1. 它们的区别请看这篇文档:STM32: 实现AES 128-BIT加密算法 - 标准实现
          https://www.brobwind.com/archives/1255

  5. # elif defined(__arm__)
    // ftp://ftp.dca.fee.unicamp.br/pub/docs/ea871/ARM/ARMGCCInlineAssemblerCookbook.pdf
    # define ROTATE(a,n) ({ register unsigned int ret; \
    asm ( \
    “ror %0,%0,%1” \
    : “=r”(ret) \
    : “I”(32 – n), “0”(a) \
    : “cc”); \
    ret; \
    })
    # endif

    使用这个在stm32 mdk编译时会报bro_aes.c(293): error: #29: expected an expression
    请问该怎么解决?

    1. /** \brief Rotate Right in unsigned value (32 bit)

      This function Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.

      \param [in] value Value to rotate
      \param [in] value Number of Bits to rotate
      \return Rotated value
      */
      __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
      {

      __ASM volatile (“ror %0, %0, %1” : “+r” (op1) : “r” (op2) );
      return(op1);
      }

  6. 能不能详细的说一下计算S盒那部分,看的不太明白,为什么p要*3,q要/3,还有最后为什么要异或0X63,每一步看的云里雾里的,希望楼主解答一下,谢谢。。。

    1. 你参考这两篇文档看看,我也没搞懂:
      http://www.samiam.org/s-box.html
      http://www.samiam.org/galois.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注