xref: /linux/crypto/sm4.c (revision 73c919d3)
1d2825fa9SJason A. Donenfeld /* SPDX-License-Identifier: GPL-2.0-or-later */
2d2825fa9SJason A. Donenfeld /*
3d2825fa9SJason A. Donenfeld  * SM4, as specified in
4d2825fa9SJason A. Donenfeld  * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html
5d2825fa9SJason A. Donenfeld  *
6d2825fa9SJason A. Donenfeld  * Copyright (C) 2018 ARM Limited or its affiliates.
7d2825fa9SJason A. Donenfeld  * Copyright (c) 2021 Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
8d2825fa9SJason A. Donenfeld  */
9d2825fa9SJason A. Donenfeld 
10d2825fa9SJason A. Donenfeld #include <linux/module.h>
11d2825fa9SJason A. Donenfeld #include <asm/unaligned.h>
12d2825fa9SJason A. Donenfeld #include <crypto/sm4.h>
13d2825fa9SJason A. Donenfeld 
1473c919d3STianjia Zhang static const u32 ____cacheline_aligned fk[4] = {
15d2825fa9SJason A. Donenfeld 	0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
16d2825fa9SJason A. Donenfeld };
17d2825fa9SJason A. Donenfeld 
18d2825fa9SJason A. Donenfeld static const u32 ____cacheline_aligned ck[32] = {
19d2825fa9SJason A. Donenfeld 	0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
20d2825fa9SJason A. Donenfeld 	0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
21d2825fa9SJason A. Donenfeld 	0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
22d2825fa9SJason A. Donenfeld 	0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
23d2825fa9SJason A. Donenfeld 	0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
24d2825fa9SJason A. Donenfeld 	0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
25d2825fa9SJason A. Donenfeld 	0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
26d2825fa9SJason A. Donenfeld 	0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
27d2825fa9SJason A. Donenfeld };
28d2825fa9SJason A. Donenfeld 
29d2825fa9SJason A. Donenfeld static const u8 ____cacheline_aligned sbox[256] = {
30d2825fa9SJason A. Donenfeld 	0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
31d2825fa9SJason A. Donenfeld 	0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
32d2825fa9SJason A. Donenfeld 	0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
33d2825fa9SJason A. Donenfeld 	0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
34d2825fa9SJason A. Donenfeld 	0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
35d2825fa9SJason A. Donenfeld 	0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
36d2825fa9SJason A. Donenfeld 	0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
37d2825fa9SJason A. Donenfeld 	0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
38d2825fa9SJason A. Donenfeld 	0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
39d2825fa9SJason A. Donenfeld 	0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
40d2825fa9SJason A. Donenfeld 	0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
41d2825fa9SJason A. Donenfeld 	0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
42d2825fa9SJason A. Donenfeld 	0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
43d2825fa9SJason A. Donenfeld 	0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
44d2825fa9SJason A. Donenfeld 	0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
45d2825fa9SJason A. Donenfeld 	0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
46d2825fa9SJason A. Donenfeld 	0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
47d2825fa9SJason A. Donenfeld 	0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
48d2825fa9SJason A. Donenfeld 	0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
49d2825fa9SJason A. Donenfeld 	0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
50d2825fa9SJason A. Donenfeld 	0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
51d2825fa9SJason A. Donenfeld 	0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
52d2825fa9SJason A. Donenfeld 	0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
53d2825fa9SJason A. Donenfeld 	0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
54d2825fa9SJason A. Donenfeld 	0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
55d2825fa9SJason A. Donenfeld 	0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
56d2825fa9SJason A. Donenfeld 	0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
57d2825fa9SJason A. Donenfeld 	0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
58d2825fa9SJason A. Donenfeld 	0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
59d2825fa9SJason A. Donenfeld 	0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
60d2825fa9SJason A. Donenfeld 	0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
61d2825fa9SJason A. Donenfeld 	0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
62d2825fa9SJason A. Donenfeld };
63d2825fa9SJason A. Donenfeld 
6473c919d3STianjia Zhang extern const u32 crypto_sm4_fk[4] __alias(fk);
6573c919d3STianjia Zhang extern const u32 crypto_sm4_ck[32] __alias(ck);
6673c919d3STianjia Zhang extern const u8 crypto_sm4_sbox[256] __alias(sbox);
6773c919d3STianjia Zhang 
6873c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_fk);
6973c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_ck);
7073c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_sbox);
7173c919d3STianjia Zhang 
sm4_t_non_lin_sub(u32 x)72d2825fa9SJason A. Donenfeld static inline u32 sm4_t_non_lin_sub(u32 x)
73d2825fa9SJason A. Donenfeld {
74d2825fa9SJason A. Donenfeld 	u32 out;
75d2825fa9SJason A. Donenfeld 
76d2825fa9SJason A. Donenfeld 	out  = (u32)sbox[x & 0xff];
77d2825fa9SJason A. Donenfeld 	out |= (u32)sbox[(x >> 8) & 0xff] << 8;
78d2825fa9SJason A. Donenfeld 	out |= (u32)sbox[(x >> 16) & 0xff] << 16;
79d2825fa9SJason A. Donenfeld 	out |= (u32)sbox[(x >> 24) & 0xff] << 24;
80d2825fa9SJason A. Donenfeld 
81d2825fa9SJason A. Donenfeld 	return out;
82d2825fa9SJason A. Donenfeld }
83d2825fa9SJason A. Donenfeld 
sm4_key_lin_sub(u32 x)84d2825fa9SJason A. Donenfeld static inline u32 sm4_key_lin_sub(u32 x)
85d2825fa9SJason A. Donenfeld {
86d2825fa9SJason A. Donenfeld 	return x ^ rol32(x, 13) ^ rol32(x, 23);
87d2825fa9SJason A. Donenfeld }
88d2825fa9SJason A. Donenfeld 
sm4_enc_lin_sub(u32 x)89d2825fa9SJason A. Donenfeld static inline u32 sm4_enc_lin_sub(u32 x)
90d2825fa9SJason A. Donenfeld {
91d2825fa9SJason A. Donenfeld 	return x ^ rol32(x, 2) ^ rol32(x, 10) ^ rol32(x, 18) ^ rol32(x, 24);
92d2825fa9SJason A. Donenfeld }
93d2825fa9SJason A. Donenfeld 
sm4_key_sub(u32 x)94d2825fa9SJason A. Donenfeld static inline u32 sm4_key_sub(u32 x)
95d2825fa9SJason A. Donenfeld {
96d2825fa9SJason A. Donenfeld 	return sm4_key_lin_sub(sm4_t_non_lin_sub(x));
97d2825fa9SJason A. Donenfeld }
98d2825fa9SJason A. Donenfeld 
sm4_enc_sub(u32 x)99d2825fa9SJason A. Donenfeld static inline u32 sm4_enc_sub(u32 x)
100d2825fa9SJason A. Donenfeld {
101d2825fa9SJason A. Donenfeld 	return sm4_enc_lin_sub(sm4_t_non_lin_sub(x));
102d2825fa9SJason A. Donenfeld }
103d2825fa9SJason A. Donenfeld 
sm4_round(u32 x0,u32 x1,u32 x2,u32 x3,u32 rk)104d2825fa9SJason A. Donenfeld static inline u32 sm4_round(u32 x0, u32 x1, u32 x2, u32 x3, u32 rk)
105d2825fa9SJason A. Donenfeld {
106d2825fa9SJason A. Donenfeld 	return x0 ^ sm4_enc_sub(x1 ^ x2 ^ x3 ^ rk);
107d2825fa9SJason A. Donenfeld }
108d2825fa9SJason A. Donenfeld 
109d2825fa9SJason A. Donenfeld 
110d2825fa9SJason A. Donenfeld /**
111d2825fa9SJason A. Donenfeld  * sm4_expandkey - Expands the SM4 key as described in GB/T 32907-2016
112d2825fa9SJason A. Donenfeld  * @ctx:	The location where the computed key will be stored.
113d2825fa9SJason A. Donenfeld  * @in_key:	The supplied key.
114d2825fa9SJason A. Donenfeld  * @key_len:	The length of the supplied key.
115d2825fa9SJason A. Donenfeld  *
116d2825fa9SJason A. Donenfeld  * Returns 0 on success. The function fails only if an invalid key size (or
117d2825fa9SJason A. Donenfeld  * pointer) is supplied.
118d2825fa9SJason A. Donenfeld  */
sm4_expandkey(struct sm4_ctx * ctx,const u8 * in_key,unsigned int key_len)119d2825fa9SJason A. Donenfeld int sm4_expandkey(struct sm4_ctx *ctx, const u8 *in_key,
120d2825fa9SJason A. Donenfeld 			  unsigned int key_len)
121d2825fa9SJason A. Donenfeld {
122d2825fa9SJason A. Donenfeld 	u32 rk[4];
123d2825fa9SJason A. Donenfeld 	const u32 *key = (u32 *)in_key;
124d2825fa9SJason A. Donenfeld 	int i;
125d2825fa9SJason A. Donenfeld 
126d2825fa9SJason A. Donenfeld 	if (key_len != SM4_KEY_SIZE)
127d2825fa9SJason A. Donenfeld 		return -EINVAL;
128d2825fa9SJason A. Donenfeld 
129d2825fa9SJason A. Donenfeld 	rk[0] = get_unaligned_be32(&key[0]) ^ fk[0];
130d2825fa9SJason A. Donenfeld 	rk[1] = get_unaligned_be32(&key[1]) ^ fk[1];
131d2825fa9SJason A. Donenfeld 	rk[2] = get_unaligned_be32(&key[2]) ^ fk[2];
132d2825fa9SJason A. Donenfeld 	rk[3] = get_unaligned_be32(&key[3]) ^ fk[3];
133d2825fa9SJason A. Donenfeld 
134d2825fa9SJason A. Donenfeld 	for (i = 0; i < 32; i += 4) {
135d2825fa9SJason A. Donenfeld 		rk[0] ^= sm4_key_sub(rk[1] ^ rk[2] ^ rk[3] ^ ck[i + 0]);
136d2825fa9SJason A. Donenfeld 		rk[1] ^= sm4_key_sub(rk[2] ^ rk[3] ^ rk[0] ^ ck[i + 1]);
137d2825fa9SJason A. Donenfeld 		rk[2] ^= sm4_key_sub(rk[3] ^ rk[0] ^ rk[1] ^ ck[i + 2]);
138d2825fa9SJason A. Donenfeld 		rk[3] ^= sm4_key_sub(rk[0] ^ rk[1] ^ rk[2] ^ ck[i + 3]);
139d2825fa9SJason A. Donenfeld 
140d2825fa9SJason A. Donenfeld 		ctx->rkey_enc[i + 0] = rk[0];
141d2825fa9SJason A. Donenfeld 		ctx->rkey_enc[i + 1] = rk[1];
142d2825fa9SJason A. Donenfeld 		ctx->rkey_enc[i + 2] = rk[2];
143d2825fa9SJason A. Donenfeld 		ctx->rkey_enc[i + 3] = rk[3];
144d2825fa9SJason A. Donenfeld 		ctx->rkey_dec[31 - 0 - i] = rk[0];
145d2825fa9SJason A. Donenfeld 		ctx->rkey_dec[31 - 1 - i] = rk[1];
146d2825fa9SJason A. Donenfeld 		ctx->rkey_dec[31 - 2 - i] = rk[2];
147d2825fa9SJason A. Donenfeld 		ctx->rkey_dec[31 - 3 - i] = rk[3];
148d2825fa9SJason A. Donenfeld 	}
149d2825fa9SJason A. Donenfeld 
150d2825fa9SJason A. Donenfeld 	return 0;
151d2825fa9SJason A. Donenfeld }
152d2825fa9SJason A. Donenfeld EXPORT_SYMBOL_GPL(sm4_expandkey);
153d2825fa9SJason A. Donenfeld 
154d2825fa9SJason A. Donenfeld /**
155d2825fa9SJason A. Donenfeld  * sm4_crypt_block - Encrypt or decrypt a single SM4 block
156d2825fa9SJason A. Donenfeld  * @rk:		The rkey_enc for encrypt or rkey_dec for decrypt
157d2825fa9SJason A. Donenfeld  * @out:	Buffer to store output data
158d2825fa9SJason A. Donenfeld  * @in: 	Buffer containing the input data
159d2825fa9SJason A. Donenfeld  */
sm4_crypt_block(const u32 * rk,u8 * out,const u8 * in)160d2825fa9SJason A. Donenfeld void sm4_crypt_block(const u32 *rk, u8 *out, const u8 *in)
161d2825fa9SJason A. Donenfeld {
162d2825fa9SJason A. Donenfeld 	u32 x[4], i;
163d2825fa9SJason A. Donenfeld 
164d2825fa9SJason A. Donenfeld 	x[0] = get_unaligned_be32(in + 0 * 4);
165d2825fa9SJason A. Donenfeld 	x[1] = get_unaligned_be32(in + 1 * 4);
166d2825fa9SJason A. Donenfeld 	x[2] = get_unaligned_be32(in + 2 * 4);
167d2825fa9SJason A. Donenfeld 	x[3] = get_unaligned_be32(in + 3 * 4);
168d2825fa9SJason A. Donenfeld 
169d2825fa9SJason A. Donenfeld 	for (i = 0; i < 32; i += 4) {
170d2825fa9SJason A. Donenfeld 		x[0] = sm4_round(x[0], x[1], x[2], x[3], rk[i + 0]);
171d2825fa9SJason A. Donenfeld 		x[1] = sm4_round(x[1], x[2], x[3], x[0], rk[i + 1]);
172d2825fa9SJason A. Donenfeld 		x[2] = sm4_round(x[2], x[3], x[0], x[1], rk[i + 2]);
173d2825fa9SJason A. Donenfeld 		x[3] = sm4_round(x[3], x[0], x[1], x[2], rk[i + 3]);
174d2825fa9SJason A. Donenfeld 	}
175d2825fa9SJason A. Donenfeld 
176d2825fa9SJason A. Donenfeld 	put_unaligned_be32(x[3 - 0], out + 0 * 4);
177d2825fa9SJason A. Donenfeld 	put_unaligned_be32(x[3 - 1], out + 1 * 4);
178d2825fa9SJason A. Donenfeld 	put_unaligned_be32(x[3 - 2], out + 2 * 4);
179d2825fa9SJason A. Donenfeld 	put_unaligned_be32(x[3 - 3], out + 3 * 4);
180d2825fa9SJason A. Donenfeld }
181d2825fa9SJason A. Donenfeld EXPORT_SYMBOL_GPL(sm4_crypt_block);
182d2825fa9SJason A. Donenfeld 
183d2825fa9SJason A. Donenfeld MODULE_DESCRIPTION("Generic SM4 library");
184d2825fa9SJason A. Donenfeld MODULE_LICENSE("GPL v2");
185