xref: /optee_os/core/crypto/sm4.c (revision b21f583d20f2bb9d7ec88860c2bace542b29de79)
1ade6f848SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2ade6f848SJerome Forissier /*
3ade6f848SJerome Forissier  * Copyright Copyright (c) 2019 Huawei Technologies Co., Ltd
4ade6f848SJerome Forissier  */
5ade6f848SJerome Forissier /*
6ade6f848SJerome Forissier  * SM4 Encryption algorithm (SMS4 algorithm)
7ade6f848SJerome Forissier  * GM/T 0002-2012 Chinese National Standard ref:http://www.oscca.gov.cn/
8ade6f848SJerome Forissier  * thanks to Xyssl
9ade6f848SJerome Forissier  * thnaks and refers to http://hi.baidu.com/numax/blog/item/80addfefddfb93e4cf1b3e61.html
10ade6f848SJerome Forissier  * author:goldboar
11ade6f848SJerome Forissier  * email:goldboar@163.com
12ade6f848SJerome Forissier  * 2012-4-20
13ade6f848SJerome Forissier  */
14ade6f848SJerome Forissier 
15ade6f848SJerome Forissier #include "sm4.h"
16ade6f848SJerome Forissier #include <assert.h>
17ade6f848SJerome Forissier #include <string.h>
18ade6f848SJerome Forissier 
19ade6f848SJerome Forissier #define GET_UINT32_BE(n, b, i)				\
20ade6f848SJerome Forissier 	do {						\
21ade6f848SJerome Forissier 		(n) = ((uint32_t)(b)[(i)] << 24)     |	\
22ade6f848SJerome Forissier 		      ((uint32_t)(b)[(i) + 1] << 16) |	\
23ade6f848SJerome Forissier 		      ((uint32_t)(b)[(i) + 2] <<  8) |	\
24ade6f848SJerome Forissier 		      ((uint32_t)(b)[(i) + 3]);		\
25ade6f848SJerome Forissier 	} while (0)
26ade6f848SJerome Forissier 
27ade6f848SJerome Forissier #define PUT_UINT32_BE(n, b, i)				\
28ade6f848SJerome Forissier 	do {						\
29ade6f848SJerome Forissier 		(b)[(i)] = (uint8_t)((n) >> 24);	\
30ade6f848SJerome Forissier 		(b)[(i) + 1] = (uint8_t)((n) >> 16);	\
31ade6f848SJerome Forissier 		(b)[(i) + 2] = (uint8_t)((n) >>  8);	\
32ade6f848SJerome Forissier 		(b)[(i) + 3] = (uint8_t)((n));		\
33ade6f848SJerome Forissier 	} while (0)
34ade6f848SJerome Forissier 
35ade6f848SJerome Forissier #define SHL(x, n)	(((x) & 0xFFFFFFFF) << (n))
36ade6f848SJerome Forissier #define ROTL(x, n)	(SHL((x), (n)) | ((x) >> (32 - (n))))
37ade6f848SJerome Forissier 
38ade6f848SJerome Forissier #define SWAP(a, b)	{ uint32_t t = a; a = b; b = t; t = 0; }
39ade6f848SJerome Forissier 
40ade6f848SJerome Forissier /*
41ade6f848SJerome Forissier  * Expanded SM4 S-boxes
42ade6f848SJerome Forissier  */
43ade6f848SJerome Forissier static const uint8_t SboxTable[16][16] =  {
44ade6f848SJerome Forissier 	{0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
45ade6f848SJerome Forissier 	 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05},
46ade6f848SJerome Forissier 	{0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
47ade6f848SJerome Forissier 	 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99},
48ade6f848SJerome Forissier 	{0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
49ade6f848SJerome Forissier 	 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62},
50ade6f848SJerome Forissier 	{0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
51ade6f848SJerome Forissier 	 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6},
52ade6f848SJerome Forissier 	{0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
53ade6f848SJerome Forissier 	 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8},
54ade6f848SJerome Forissier 	{0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
55ade6f848SJerome Forissier 	 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35},
56ade6f848SJerome Forissier 	{0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
57ade6f848SJerome Forissier 	 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87},
58ade6f848SJerome Forissier 	{0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
59ade6f848SJerome Forissier 	 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e},
60ade6f848SJerome Forissier 	{0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
61ade6f848SJerome Forissier 	 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1},
62ade6f848SJerome Forissier 	{0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
63ade6f848SJerome Forissier 	 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3},
64ade6f848SJerome Forissier 	{0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
65ade6f848SJerome Forissier 	 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f},
66ade6f848SJerome Forissier 	{0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
67ade6f848SJerome Forissier 	 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51},
68ade6f848SJerome Forissier 	{0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
69ade6f848SJerome Forissier 	 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8},
70ade6f848SJerome Forissier 	{0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
71ade6f848SJerome Forissier 	 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0},
72ade6f848SJerome Forissier 	{0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
73ade6f848SJerome Forissier 	 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84},
74ade6f848SJerome Forissier 	{0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
75ade6f848SJerome Forissier 	 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48}
76ade6f848SJerome Forissier };
77ade6f848SJerome Forissier 
78ade6f848SJerome Forissier /* System parameter */
79ade6f848SJerome Forissier static const uint32_t FK[4] = {
80ade6f848SJerome Forissier 	0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
81ade6f848SJerome Forissier };
82ade6f848SJerome Forissier 
83ade6f848SJerome Forissier /* Fixed parameter */
84ade6f848SJerome Forissier static const uint32_t CK[32] = {
85ade6f848SJerome Forissier 	0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
86ade6f848SJerome Forissier 	0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
87ade6f848SJerome Forissier 	0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
88ade6f848SJerome Forissier 	0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
89ade6f848SJerome Forissier 	0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
90ade6f848SJerome Forissier 	0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
91ade6f848SJerome Forissier 	0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
92ade6f848SJerome Forissier 	0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
93ade6f848SJerome Forissier };
94ade6f848SJerome Forissier 
sm4Sbox(uint8_t inch)95ade6f848SJerome Forissier static uint8_t sm4Sbox(uint8_t inch)
96ade6f848SJerome Forissier {
97ade6f848SJerome Forissier 	uint8_t *tab = (uint8_t *)SboxTable;
98ade6f848SJerome Forissier 
99ade6f848SJerome Forissier 	return tab[inch];
100ade6f848SJerome Forissier }
101ade6f848SJerome Forissier 
sm4Lt(uint32_t ka)102ade6f848SJerome Forissier static uint32_t sm4Lt(uint32_t ka)
103ade6f848SJerome Forissier {
104ade6f848SJerome Forissier 	uint32_t bb = 0;
105ade6f848SJerome Forissier 	uint8_t a[4];
106ade6f848SJerome Forissier 	uint8_t b[4];
107ade6f848SJerome Forissier 
108ade6f848SJerome Forissier 	PUT_UINT32_BE(ka, a, 0);
109ade6f848SJerome Forissier 	b[0] = sm4Sbox(a[0]);
110ade6f848SJerome Forissier 	b[1] = sm4Sbox(a[1]);
111ade6f848SJerome Forissier 	b[2] = sm4Sbox(a[2]);
112ade6f848SJerome Forissier 	b[3] = sm4Sbox(a[3]);
113ade6f848SJerome Forissier 	GET_UINT32_BE(bb, b, 0);
114ade6f848SJerome Forissier 
115ade6f848SJerome Forissier 	return bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
116ade6f848SJerome Forissier }
117ade6f848SJerome Forissier 
sm4F(uint32_t x0,uint32_t x1,uint32_t x2,uint32_t x3,uint32_t rk)118ade6f848SJerome Forissier static uint32_t sm4F(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3,
119ade6f848SJerome Forissier 		     uint32_t rk)
120ade6f848SJerome Forissier {
121ade6f848SJerome Forissier 	return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
122ade6f848SJerome Forissier }
123ade6f848SJerome Forissier 
sm4CalciRK(uint32_t ka)124ade6f848SJerome Forissier static uint32_t sm4CalciRK(uint32_t ka)
125ade6f848SJerome Forissier {
126ade6f848SJerome Forissier 	uint32_t bb = 0;
127ade6f848SJerome Forissier 	uint8_t a[4];
128ade6f848SJerome Forissier 	uint8_t b[4];
129ade6f848SJerome Forissier 
130ade6f848SJerome Forissier 	PUT_UINT32_BE(ka, a, 0);
131ade6f848SJerome Forissier 	b[0] = sm4Sbox(a[0]);
132ade6f848SJerome Forissier 	b[1] = sm4Sbox(a[1]);
133ade6f848SJerome Forissier 	b[2] = sm4Sbox(a[2]);
134ade6f848SJerome Forissier 	b[3] = sm4Sbox(a[3]);
135ade6f848SJerome Forissier 	GET_UINT32_BE(bb, b, 0);
136ade6f848SJerome Forissier 
137ade6f848SJerome Forissier 	return bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
138ade6f848SJerome Forissier }
139ade6f848SJerome Forissier 
sm4_setkey(uint32_t SK[32],const uint8_t key[16])140ade6f848SJerome Forissier static void sm4_setkey(uint32_t SK[32], const uint8_t key[16])
141ade6f848SJerome Forissier {
142ade6f848SJerome Forissier 	uint32_t MK[4];
143ade6f848SJerome Forissier 	uint32_t k[36];
144ade6f848SJerome Forissier 	uint32_t i = 0;
145ade6f848SJerome Forissier 
146ade6f848SJerome Forissier 	GET_UINT32_BE(MK[0], key, 0);
147ade6f848SJerome Forissier 	GET_UINT32_BE(MK[1], key, 4);
148ade6f848SJerome Forissier 	GET_UINT32_BE(MK[2], key, 8);
149ade6f848SJerome Forissier 	GET_UINT32_BE(MK[3], key, 12);
150ade6f848SJerome Forissier 
151ade6f848SJerome Forissier 	k[0] = MK[0] ^ FK[0];
152ade6f848SJerome Forissier 	k[1] = MK[1] ^ FK[1];
153ade6f848SJerome Forissier 	k[2] = MK[2] ^ FK[2];
154ade6f848SJerome Forissier 	k[3] = MK[3] ^ FK[3];
155ade6f848SJerome Forissier 
156ade6f848SJerome Forissier 	for (i = 0; i < 32; i++) {
157ade6f848SJerome Forissier 		k[i + 4] = k[i] ^ sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^
158ade6f848SJerome Forissier 					     CK[i]);
159ade6f848SJerome Forissier 		SK[i] = k[i + 4];
160ade6f848SJerome Forissier 	}
161ade6f848SJerome Forissier }
162ade6f848SJerome Forissier 
sm4_one_round(uint32_t sk[32],const uint8_t input[16],uint8_t output[16])163ade6f848SJerome Forissier static void sm4_one_round(uint32_t sk[32], const uint8_t input[16],
164ade6f848SJerome Forissier 			  uint8_t output[16])
165ade6f848SJerome Forissier {
166ade6f848SJerome Forissier 	uint32_t i = 0;
167ade6f848SJerome Forissier 	uint32_t ulbuf[36];
168ade6f848SJerome Forissier 
169ade6f848SJerome Forissier 	memset(ulbuf, 0, sizeof(ulbuf));
170ade6f848SJerome Forissier 
171ade6f848SJerome Forissier 	GET_UINT32_BE(ulbuf[0], input, 0);
172ade6f848SJerome Forissier 	GET_UINT32_BE(ulbuf[1], input, 4);
173ade6f848SJerome Forissier 	GET_UINT32_BE(ulbuf[2], input, 8);
174ade6f848SJerome Forissier 	GET_UINT32_BE(ulbuf[3], input, 12);
175ade6f848SJerome Forissier 
176ade6f848SJerome Forissier 	for (i = 0; i < 32; i++)
177ade6f848SJerome Forissier 		ulbuf[i + 4] = sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2],
178ade6f848SJerome Forissier 				    ulbuf[i + 3], sk[i]);
179ade6f848SJerome Forissier 
180ade6f848SJerome Forissier 	PUT_UINT32_BE(ulbuf[35], output, 0);
181ade6f848SJerome Forissier 	PUT_UINT32_BE(ulbuf[34], output, 4);
182ade6f848SJerome Forissier 	PUT_UINT32_BE(ulbuf[33], output, 8);
183ade6f848SJerome Forissier 	PUT_UINT32_BE(ulbuf[32], output, 12);
184ade6f848SJerome Forissier }
185ade6f848SJerome Forissier 
sm4_setkey_enc(struct sm4_context * ctx,const uint8_t key[16])186ade6f848SJerome Forissier void sm4_setkey_enc(struct sm4_context *ctx, const uint8_t key[16])
187ade6f848SJerome Forissier {
188ade6f848SJerome Forissier 	ctx->mode = SM4_ENCRYPT;
189ade6f848SJerome Forissier 	sm4_setkey(ctx->sk, key);
190ade6f848SJerome Forissier }
191ade6f848SJerome Forissier 
sm4_setkey_dec(struct sm4_context * ctx,const uint8_t key[16])192ade6f848SJerome Forissier void sm4_setkey_dec(struct sm4_context *ctx, const uint8_t key[16])
193ade6f848SJerome Forissier {
194ade6f848SJerome Forissier 	int i;
195ade6f848SJerome Forissier 
196ade6f848SJerome Forissier 	ctx->mode = SM4_DECRYPT;
197ade6f848SJerome Forissier 	sm4_setkey(ctx->sk, key);
198ade6f848SJerome Forissier 
199ade6f848SJerome Forissier 	for (i = 0; i < 16; i++)
200ade6f848SJerome Forissier 		SWAP(ctx->sk[i], ctx->sk[31 - i]);
201ade6f848SJerome Forissier }
202ade6f848SJerome Forissier 
sm4_crypt_ecb(struct sm4_context * ctx,size_t length,const uint8_t * input,uint8_t * output)203ade6f848SJerome Forissier void sm4_crypt_ecb(struct sm4_context *ctx, size_t length, const uint8_t *input,
204ade6f848SJerome Forissier 		   uint8_t *output)
205ade6f848SJerome Forissier {
206ade6f848SJerome Forissier 	assert(!(length % 16));
207ade6f848SJerome Forissier 
208ade6f848SJerome Forissier 	while (length > 0) {
209ade6f848SJerome Forissier 		sm4_one_round(ctx->sk, input, output);
210ade6f848SJerome Forissier 		input  += 16;
211ade6f848SJerome Forissier 		output += 16;
212ade6f848SJerome Forissier 		length -= 16;
213ade6f848SJerome Forissier 	}
214ade6f848SJerome Forissier }
215ade6f848SJerome Forissier 
sm4_crypt_cbc(struct sm4_context * ctx,size_t length,uint8_t iv[16],const uint8_t * input,uint8_t * output)216ade6f848SJerome Forissier void sm4_crypt_cbc(struct sm4_context *ctx, size_t length, uint8_t iv[16],
217ade6f848SJerome Forissier 		   const uint8_t *input, uint8_t *output)
218ade6f848SJerome Forissier {
219ade6f848SJerome Forissier 	int i;
220ade6f848SJerome Forissier 	uint8_t temp[16];
221ade6f848SJerome Forissier 
222ade6f848SJerome Forissier 	assert(!(length % 16));
223ade6f848SJerome Forissier 
224ade6f848SJerome Forissier 	if (ctx->mode == SM4_ENCRYPT) {
225ade6f848SJerome Forissier 		while (length > 0) {
226ade6f848SJerome Forissier 			for (i = 0; i < 16; i++)
227ade6f848SJerome Forissier 				output[i] = (uint8_t)(input[i] ^ iv[i]);
228ade6f848SJerome Forissier 			sm4_one_round(ctx->sk, output, output);
229ade6f848SJerome Forissier 			memcpy(iv, output, 16);
230ade6f848SJerome Forissier 			input  += 16;
231ade6f848SJerome Forissier 			output += 16;
232ade6f848SJerome Forissier 			length -= 16;
233ade6f848SJerome Forissier 		}
234ade6f848SJerome Forissier 	} else {
235ade6f848SJerome Forissier 		/* SM4_DECRYPT */
236ade6f848SJerome Forissier 		while (length > 0) {
237ade6f848SJerome Forissier 			memcpy(temp, input, 16);
238ade6f848SJerome Forissier 			sm4_one_round(ctx->sk, input, output);
239ade6f848SJerome Forissier 			for (i = 0; i < 16; i++)
240ade6f848SJerome Forissier 				output[i] = (uint8_t)(output[i] ^ iv[i]);
241ade6f848SJerome Forissier 			memcpy(iv, temp, 16);
242ade6f848SJerome Forissier 			input  += 16;
243ade6f848SJerome Forissier 			output += 16;
244ade6f848SJerome Forissier 			length -= 16;
245ade6f848SJerome Forissier 		}
246ade6f848SJerome Forissier 	}
247ade6f848SJerome Forissier }
248ade6f848SJerome Forissier 
sm4_crypt_ctr(struct sm4_context * ctx,size_t length,uint8_t ctr[16],const uint8_t * input,uint8_t * output)249ade6f848SJerome Forissier void sm4_crypt_ctr(struct sm4_context *ctx, size_t length, uint8_t ctr[16],
250ade6f848SJerome Forissier 		   const uint8_t *input, uint8_t *output)
251ade6f848SJerome Forissier {
252ade6f848SJerome Forissier 	int i;
253ade6f848SJerome Forissier 	uint8_t temp[16];
254ade6f848SJerome Forissier 
255ade6f848SJerome Forissier 	assert(!(length % 16));
256ade6f848SJerome Forissier 
257ade6f848SJerome Forissier 	while (length > 0) {
258ade6f848SJerome Forissier 		memcpy(temp, ctr, 16);
259ade6f848SJerome Forissier 		sm4_one_round(ctx->sk, ctr, ctr);
260ade6f848SJerome Forissier 		for (i = 0; i < 16; i++)
261ade6f848SJerome Forissier 			output[i] = (uint8_t)(input[i] ^ ctr[i]);
262ade6f848SJerome Forissier 		memcpy(ctr, temp, 16);
263ade6f848SJerome Forissier 		for (i = 16; i > 0; i--)
264ade6f848SJerome Forissier 			if (++ctr[i - 1])
265ade6f848SJerome Forissier 				break;
266ade6f848SJerome Forissier 		input  += 16;
267ade6f848SJerome Forissier 		output += 16;
268ade6f848SJerome Forissier 		length -= 16;
269ade6f848SJerome Forissier 	}
270ade6f848SJerome Forissier }
271*b21f583dSPingan Xie 
xts_multi(unsigned char * in,unsigned char * out)272*b21f583dSPingan Xie static void xts_multi(unsigned char *in, unsigned char *out)
273*b21f583dSPingan Xie {
274*b21f583dSPingan Xie 	uint8_t tt = 0;
275*b21f583dSPingan Xie 	uint8_t t = 0;
276*b21f583dSPingan Xie 	int i = 0;
277*b21f583dSPingan Xie 
278*b21f583dSPingan Xie 	for (i = 0; i < 16; i++) {
279*b21f583dSPingan Xie 		tt = in[i] >> 7;
280*b21f583dSPingan Xie 		out[i] = ((in[i] << 1) | t) & 0xFF;
281*b21f583dSPingan Xie 		t = tt;
282*b21f583dSPingan Xie 	}
283*b21f583dSPingan Xie 
284*b21f583dSPingan Xie 	out[0] ^= (0x87 & (0 - tt));
285*b21f583dSPingan Xie }
286*b21f583dSPingan Xie 
xor_128(const uint8_t a[16],const uint8_t b[16],uint8_t c[16])287*b21f583dSPingan Xie static void xor_128(const uint8_t a[16], const uint8_t b[16], uint8_t c[16])
288*b21f583dSPingan Xie {
289*b21f583dSPingan Xie 	int i = 0;
290*b21f583dSPingan Xie 
291*b21f583dSPingan Xie 	for (i = 0; i < 16; i++)
292*b21f583dSPingan Xie 		c[i] = a[i] ^ b[i];
293*b21f583dSPingan Xie }
294*b21f583dSPingan Xie 
sm4_crypt_xts(struct sm4_context * ctx,struct sm4_context * ctx_ek,struct sm4_context * ctx_dk,size_t len,uint8_t * iv,const uint8_t * input,uint8_t * output)295*b21f583dSPingan Xie void sm4_crypt_xts(struct sm4_context *ctx, struct sm4_context *ctx_ek,
296*b21f583dSPingan Xie 		   struct sm4_context *ctx_dk, size_t len, uint8_t *iv,
297*b21f583dSPingan Xie 		   const uint8_t *input, uint8_t *output)
298*b21f583dSPingan Xie {
299*b21f583dSPingan Xie 	uint8_t tweak[16] = { };
300*b21f583dSPingan Xie 	uint8_t tweak1[16] = { };
301*b21f583dSPingan Xie 	uint8_t ct[16] = { };
302*b21f583dSPingan Xie 	size_t i = 0;
303*b21f583dSPingan Xie 
304*b21f583dSPingan Xie 	assert(len >= 16);
305*b21f583dSPingan Xie 
306*b21f583dSPingan Xie 	sm4_one_round(ctx_ek->sk, iv, tweak);
307*b21f583dSPingan Xie 
308*b21f583dSPingan Xie 	if (ctx->mode == SM4_DECRYPT && (len % 16))
309*b21f583dSPingan Xie 		len -= 16;
310*b21f583dSPingan Xie 
311*b21f583dSPingan Xie 	while (len >= 16) {
312*b21f583dSPingan Xie 		xor_128(input, tweak, ct);
313*b21f583dSPingan Xie 		sm4_one_round(ctx->sk, ct, ct);
314*b21f583dSPingan Xie 		xor_128(ct, tweak, output);
315*b21f583dSPingan Xie 
316*b21f583dSPingan Xie 		xts_multi(tweak, tweak);
317*b21f583dSPingan Xie 		len -= 16;
318*b21f583dSPingan Xie 		if (len == 0) {
319*b21f583dSPingan Xie 			sm4_one_round(ctx_dk->sk, tweak, iv);
320*b21f583dSPingan Xie 			return;
321*b21f583dSPingan Xie 		}
322*b21f583dSPingan Xie 		input += 16;
323*b21f583dSPingan Xie 		output += 16;
324*b21f583dSPingan Xie 	}
325*b21f583dSPingan Xie 
326*b21f583dSPingan Xie 	if (ctx->mode == SM4_ENCRYPT) {
327*b21f583dSPingan Xie 		memcpy(ct, output - 16, 16);
328*b21f583dSPingan Xie 		for (i = 0; i < len; i++) {
329*b21f583dSPingan Xie 			output[i] = ct[i];
330*b21f583dSPingan Xie 			ct[i] = input[i];
331*b21f583dSPingan Xie 		}
332*b21f583dSPingan Xie 
333*b21f583dSPingan Xie 		xor_128(ct, tweak, ct);
334*b21f583dSPingan Xie 		sm4_one_round(ctx->sk, ct, ct);
335*b21f583dSPingan Xie 		xor_128(ct, tweak, ct);
336*b21f583dSPingan Xie 		memcpy(output - 16, ct, 16);
337*b21f583dSPingan Xie 	} else {
338*b21f583dSPingan Xie 		xts_multi(tweak, tweak1);
339*b21f583dSPingan Xie 		xor_128(input, tweak1, ct);
340*b21f583dSPingan Xie 		sm4_one_round(ctx->sk, ct, ct);
341*b21f583dSPingan Xie 		xor_128(ct, tweak1, ct);
342*b21f583dSPingan Xie 
343*b21f583dSPingan Xie 		for (i = 0; i < len; ++i) {
344*b21f583dSPingan Xie 			output[16 + i] = ct[i];
345*b21f583dSPingan Xie 			ct[i] = input[16 + i];
346*b21f583dSPingan Xie 		}
347*b21f583dSPingan Xie 		xor_128(ct, tweak, ct);
348*b21f583dSPingan Xie 		sm4_one_round(ctx->sk, ct, ct);
349*b21f583dSPingan Xie 		xor_128(ct, tweak, output);
350*b21f583dSPingan Xie 	}
351*b21f583dSPingan Xie }
352