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
14*73c919d3STianjia 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
64*73c919d3STianjia Zhang extern const u32 crypto_sm4_fk[4] __alias(fk);
65*73c919d3STianjia Zhang extern const u32 crypto_sm4_ck[32] __alias(ck);
66*73c919d3STianjia Zhang extern const u8 crypto_sm4_sbox[256] __alias(sbox);
67*73c919d3STianjia Zhang
68*73c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_fk);
69*73c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_ck);
70*73c919d3STianjia Zhang EXPORT_SYMBOL(crypto_sm4_sbox);
71*73c919d3STianjia 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