Coverage Report

Created: 2025-07-23 06:59

/src/wolfssl-normal-math/wolfcrypt/src/sm4.c
Line
Count
Source (jump to first uncovered line)
1
/* sm4.c
2
 *
3
 * Copyright (C) 2006-2024 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
/* For more info on the algorithm, see:
23
 *  https://datatracker.ietf.org/doc/html/draft-ribose-cfrg-sm4
24
 */
25
26
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
27
28
#ifdef WOLFSSL_SM4
29
30
#include <wolfssl/wolfcrypt/sm4.h>
31
32
#ifdef NO_INLINE
33
    #include <wolfssl/wolfcrypt/misc.h>
34
#else
35
    #define WOLFSSL_MISC_INCLUDED
36
    #include <wolfcrypt/src/misc.c>
37
#endif
38
39
40
#ifdef LITTLE_ENDIAN_ORDER
41
42
/* Load unsigned 32-bit word from big-endian byte array.
43
 *
44
 * @param [in] b  Byte array with big-endian data.
45
 * @return  Unsigned 32-bit word.
46
 */
47
#define LOAD_U32_BE(b, v0, v1, v2, v3)  \
48
0
    XMEMCPY(&v0, b +  0, sizeof(v0));   \
49
0
    XMEMCPY(&v1, b +  4, sizeof(v1));   \
50
0
    XMEMCPY(&v2, b +  8, sizeof(v2));   \
51
0
    XMEMCPY(&v3, b + 12, sizeof(v3));   \
52
0
    v0 = ByteReverseWord32(v0);         \
53
0
    v1 = ByteReverseWord32(v1);         \
54
0
    v2 = ByteReverseWord32(v2);         \
55
0
    v3 = ByteReverseWord32(v3)
56
57
/* Store unsigned 32-bit word as big-endian byte array.
58
 *
59
 * @param [in]  v  Unsigned 32-bit value.
60
 * @param [out] b  Byte array to hold big-endian data.
61
 */
62
#define STORE_U32_BE(v0, v1, v2, v3, b) \
63
0
    v0 = ByteReverseWord32(v0);         \
64
0
    v1 = ByteReverseWord32(v1);         \
65
0
    v2 = ByteReverseWord32(v2);         \
66
0
    v3 = ByteReverseWord32(v3);         \
67
0
    XMEMCPY(b +  0, &v3, sizeof(v3));   \
68
0
    XMEMCPY(b +  4, &v2, sizeof(v2));   \
69
0
    XMEMCPY(b +  8, &v1, sizeof(v1));   \
70
0
    XMEMCPY(b + 12, &v0, sizeof(v0))
71
72
#else
73
74
/* Load unsigned 32-bit word from big-endian byte array.
75
 *
76
 * @param [in] b  Byte array with big-endian data.
77
 * @return  Unsigned 32-bit word.
78
 */
79
#define LOAD_U32_BE(b, v0, v1, v2, v3)  \
80
    XMEMCPY(&v0, b +  0, sizeof(v0));   \
81
    XMEMCPY(&v1, b +  4, sizeof(v1));   \
82
    XMEMCPY(&v2, b +  8, sizeof(v2));   \
83
    XMEMCPY(&v3, b + 12, sizeof(v3))
84
85
/* Store unsigned 32-bit word as big-endian byte array.
86
 *
87
 * @param [in]  v  Unsigned 32-bit value.
88
 * @param [out] b  Byte array to hold big-endian data.
89
 */
90
#define STORE_U32_BE(v0, v1, v2, v3, b) \
91
    XMEMCPY(b +  0, &v3, sizeof(v3));   \
92
    XMEMCPY(b +  4, &v2, sizeof(v2));   \
93
    XMEMCPY(b +  8, &v1, sizeof(v1));   \
94
    XMEMCPY(b + 12, &v0, sizeof(v0))
95
96
#endif
97
98
99
/* Constant key values used in creating key schedule. */
100
static word32 sm4_ck[32] = {
101
    0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
102
    0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
103
    0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
104
    0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
105
    0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
106
    0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
107
    0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
108
    0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
109
};
110
111
/* Family key values used in creating key schedule. */
112
static word32 sm4_fk[4] = {
113
    0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC
114
};
115
116
117
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
118
119
/* S-box used in nonlinear transformation tau. */
120
static byte sm4_sbox[256] = {
121
    0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7,
122
    0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
123
    0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3,
124
    0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
125
    0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,
126
    0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
127
    0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95,
128
    0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
129
    0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA,
130
    0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
131
    0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B,
132
    0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
133
    0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2,
134
    0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87,
135
    0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
136
    0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,
137
    0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5,
138
    0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
139
    0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55,
140
    0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
141
    0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60,
142
    0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,
143
    0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F,
144
    0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,
145
    0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,
146
    0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8,
147
    0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD,
148
    0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0,
149
    0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E,
150
    0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
151
    0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20,
152
    0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48
153
};
154
155
#ifndef WOLFSSL_SM4_SMALL
156
157
/* S-boxes used in nonlinear transformation tau.
158
 * Linear transformation applied to each byte.
159
 *
160
 * Generated using script: ruby scripts/sm4/tables.rb
161
 */
162
static const word32 sm4_sbox_0[256] = {
163
    0xd55b5b8e, 0x924242d0, 0xeaa7a74d, 0xfdfbfb06, 0xcf3333fc, 0xe2878765,
164
    0x3df4f4c9, 0xb5dede6b, 0x1658584e, 0xb4dada6e, 0x14505044, 0xc10b0bca,
165
    0x28a0a088, 0xf8efef17, 0x2cb0b09c, 0x05141411, 0x2bacac87, 0x669d9dfb,
166
    0x986a6af2, 0x77d9d9ae, 0x2aa8a882, 0xbcfafa46, 0x04101014, 0xc00f0fcf,
167
    0xa8aaaa02, 0x45111154, 0x134c4c5f, 0x269898be, 0x4825256d, 0x841a1a9e,
168
    0x0618181e, 0x9b6666fd, 0x9e7272ec, 0x4309094a, 0x51414110, 0xf7d3d324,
169
    0x934646d5, 0xecbfbf53, 0x9a6262f8, 0x7be9e992, 0x33ccccff, 0x55515104,
170
    0x0b2c2c27, 0x420d0d4f, 0xeeb7b759, 0xcc3f3ff3, 0xaeb2b21c, 0x638989ea,
171
    0xe7939374, 0xb1cece7f, 0x1c70706c, 0xaba6a60d, 0xca2727ed, 0x08202028,
172
    0xeba3a348, 0x975656c1, 0x82020280, 0xdc7f7fa3, 0x965252c4, 0xf9ebeb12,
173
    0x74d5d5a1, 0x8d3e3eb3, 0x3ffcfcc3, 0xa49a9a3e, 0x461d1d5b, 0x071c1c1b,
174
    0xa59e9e3b, 0xfff3f30c, 0xf0cfcf3f, 0x72cdcdbf, 0x175c5c4b, 0xb8eaea52,
175
    0x810e0e8f, 0x5865653d, 0x3cf0f0cc, 0x1964647d, 0xe59b9b7e, 0x87161691,
176
    0x4e3d3d73, 0xaaa2a208, 0x69a1a1c8, 0x6aadadc7, 0x83060685, 0xb0caca7a,
177
    0x70c5c5b5, 0x659191f4, 0xd96b6bb2, 0x892e2ea7, 0xfbe3e318, 0xe8afaf47,
178
    0x0f3c3c33, 0x4a2d2d67, 0x71c1c1b0, 0x5759590e, 0x9f7676e9, 0x35d4d4e1,
179
    0x1e787866, 0x249090b4, 0x0e383836, 0x5f797926, 0x628d8def, 0x59616138,
180
    0xd2474795, 0xa08a8a2a, 0x259494b1, 0x228888aa, 0x7df1f18c, 0x3bececd7,
181
    0x01040405, 0x218484a5, 0x79e1e198, 0x851e1e9b, 0xd7535384, 0x00000000,
182
    0x4719195e, 0x565d5d0b, 0x9d7e7ee3, 0xd04f4f9f, 0x279c9cbb, 0x5349491a,
183
    0x4d31317c, 0x36d8d8ee, 0x0208080a, 0xe49f9f7b, 0xa2828220, 0xc71313d4,
184
    0xcb2323e8, 0x9c7a7ae6, 0xe9abab42, 0xbdfefe43, 0x882a2aa2, 0xd14b4b9a,
185
    0x41010140, 0xc41f1fdb, 0x38e0e0d8, 0xb7d6d661, 0xa18e8e2f, 0xf4dfdf2b,
186
    0xf1cbcb3a, 0xcd3b3bf6, 0xfae7e71d, 0x608585e5, 0x15545441, 0xa3868625,
187
    0xe3838360, 0xacbaba16, 0x5c757529, 0xa6929234, 0x996e6ef7, 0x34d0d0e4,
188
    0x1a686872, 0x54555501, 0xafb6b619, 0x914e4edf, 0x32c8c8fa, 0x30c0c0f0,
189
    0xf6d7d721, 0x8e3232bc, 0xb3c6c675, 0xe08f8f6f, 0x1d747469, 0xf5dbdb2e,
190
    0xe18b8b6a, 0x2eb8b896, 0x800a0a8a, 0x679999fe, 0xc92b2be2, 0x618181e0,
191
    0xc30303c0, 0x29a4a48d, 0x238c8caf, 0xa9aeae07, 0x0d343439, 0x524d4d1f,
192
    0x4f393976, 0x6ebdbdd3, 0xd6575781, 0xd86f6fb7, 0x37dcdceb, 0x44151551,
193
    0xdd7b7ba6, 0xfef7f709, 0x8c3a3ab6, 0x2fbcbc93, 0x030c0c0f, 0xfcffff03,
194
    0x6ba9a9c2, 0x73c9c9ba, 0x6cb5b5d9, 0x6db1b1dc, 0x5a6d6d37, 0x50454515,
195
    0x8f3636b9, 0x1b6c6c77, 0xadbebe13, 0x904a4ada, 0xb9eeee57, 0xde7777a9,
196
    0xbef2f24c, 0x7efdfd83, 0x11444455, 0xda6767bd, 0x5d71712c, 0x40050545,
197
    0x1f7c7c63, 0x10404050, 0x5b696932, 0xdb6363b8, 0x0a282822, 0xc20707c5,
198
    0x31c4c4f5, 0x8a2222a8, 0xa7969631, 0xce3737f9, 0x7aeded97, 0xbff6f649,
199
    0x2db4b499, 0x75d1d1a4, 0xd3434390, 0x1248485a, 0xbae2e258, 0xe6979771,
200
    0xb6d2d264, 0xb2c2c270, 0x8b2626ad, 0x68a5a5cd, 0x955e5ecb, 0x4b292962,
201
    0x0c30303c, 0x945a5ace, 0x76ddddab, 0x7ff9f986, 0x649595f1, 0xbbe6e65d,
202
    0xf2c7c735, 0x0924242d, 0xc61717d1, 0x6fb9b9d6, 0xc51b1bde, 0x86121294,
203
    0x18606078, 0xf3c3c330, 0x7cf5f589, 0xefb3b35c, 0x3ae8e8d2, 0xdf7373ac,
204
    0x4c353579, 0x208080a0, 0x78e5e59d, 0xedbbbb56, 0x5e7d7d23, 0x3ef8f8c6,
205
    0xd45f5f8b, 0xc82f2fe7, 0x39e4e4dd, 0x49212168,
206
};
207
static const word32 sm4_sbox_1[256] = {
208
    0x5b5b8ed5, 0x4242d092, 0xa7a74dea, 0xfbfb06fd, 0x3333fccf, 0x878765e2,
209
    0xf4f4c93d, 0xdede6bb5, 0x58584e16, 0xdada6eb4, 0x50504414, 0x0b0bcac1,
210
    0xa0a08828, 0xefef17f8, 0xb0b09c2c, 0x14141105, 0xacac872b, 0x9d9dfb66,
211
    0x6a6af298, 0xd9d9ae77, 0xa8a8822a, 0xfafa46bc, 0x10101404, 0x0f0fcfc0,
212
    0xaaaa02a8, 0x11115445, 0x4c4c5f13, 0x9898be26, 0x25256d48, 0x1a1a9e84,
213
    0x18181e06, 0x6666fd9b, 0x7272ec9e, 0x09094a43, 0x41411051, 0xd3d324f7,
214
    0x4646d593, 0xbfbf53ec, 0x6262f89a, 0xe9e9927b, 0xccccff33, 0x51510455,
215
    0x2c2c270b, 0x0d0d4f42, 0xb7b759ee, 0x3f3ff3cc, 0xb2b21cae, 0x8989ea63,
216
    0x939374e7, 0xcece7fb1, 0x70706c1c, 0xa6a60dab, 0x2727edca, 0x20202808,
217
    0xa3a348eb, 0x5656c197, 0x02028082, 0x7f7fa3dc, 0x5252c496, 0xebeb12f9,
218
    0xd5d5a174, 0x3e3eb38d, 0xfcfcc33f, 0x9a9a3ea4, 0x1d1d5b46, 0x1c1c1b07,
219
    0x9e9e3ba5, 0xf3f30cff, 0xcfcf3ff0, 0xcdcdbf72, 0x5c5c4b17, 0xeaea52b8,
220
    0x0e0e8f81, 0x65653d58, 0xf0f0cc3c, 0x64647d19, 0x9b9b7ee5, 0x16169187,
221
    0x3d3d734e, 0xa2a208aa, 0xa1a1c869, 0xadadc76a, 0x06068583, 0xcaca7ab0,
222
    0xc5c5b570, 0x9191f465, 0x6b6bb2d9, 0x2e2ea789, 0xe3e318fb, 0xafaf47e8,
223
    0x3c3c330f, 0x2d2d674a, 0xc1c1b071, 0x59590e57, 0x7676e99f, 0xd4d4e135,
224
    0x7878661e, 0x9090b424, 0x3838360e, 0x7979265f, 0x8d8def62, 0x61613859,
225
    0x474795d2, 0x8a8a2aa0, 0x9494b125, 0x8888aa22, 0xf1f18c7d, 0xececd73b,
226
    0x04040501, 0x8484a521, 0xe1e19879, 0x1e1e9b85, 0x535384d7, 0x00000000,
227
    0x19195e47, 0x5d5d0b56, 0x7e7ee39d, 0x4f4f9fd0, 0x9c9cbb27, 0x49491a53,
228
    0x31317c4d, 0xd8d8ee36, 0x08080a02, 0x9f9f7be4, 0x828220a2, 0x1313d4c7,
229
    0x2323e8cb, 0x7a7ae69c, 0xabab42e9, 0xfefe43bd, 0x2a2aa288, 0x4b4b9ad1,
230
    0x01014041, 0x1f1fdbc4, 0xe0e0d838, 0xd6d661b7, 0x8e8e2fa1, 0xdfdf2bf4,
231
    0xcbcb3af1, 0x3b3bf6cd, 0xe7e71dfa, 0x8585e560, 0x54544115, 0x868625a3,
232
    0x838360e3, 0xbaba16ac, 0x7575295c, 0x929234a6, 0x6e6ef799, 0xd0d0e434,
233
    0x6868721a, 0x55550154, 0xb6b619af, 0x4e4edf91, 0xc8c8fa32, 0xc0c0f030,
234
    0xd7d721f6, 0x3232bc8e, 0xc6c675b3, 0x8f8f6fe0, 0x7474691d, 0xdbdb2ef5,
235
    0x8b8b6ae1, 0xb8b8962e, 0x0a0a8a80, 0x9999fe67, 0x2b2be2c9, 0x8181e061,
236
    0x0303c0c3, 0xa4a48d29, 0x8c8caf23, 0xaeae07a9, 0x3434390d, 0x4d4d1f52,
237
    0x3939764f, 0xbdbdd36e, 0x575781d6, 0x6f6fb7d8, 0xdcdceb37, 0x15155144,
238
    0x7b7ba6dd, 0xf7f709fe, 0x3a3ab68c, 0xbcbc932f, 0x0c0c0f03, 0xffff03fc,
239
    0xa9a9c26b, 0xc9c9ba73, 0xb5b5d96c, 0xb1b1dc6d, 0x6d6d375a, 0x45451550,
240
    0x3636b98f, 0x6c6c771b, 0xbebe13ad, 0x4a4ada90, 0xeeee57b9, 0x7777a9de,
241
    0xf2f24cbe, 0xfdfd837e, 0x44445511, 0x6767bdda, 0x71712c5d, 0x05054540,
242
    0x7c7c631f, 0x40405010, 0x6969325b, 0x6363b8db, 0x2828220a, 0x0707c5c2,
243
    0xc4c4f531, 0x2222a88a, 0x969631a7, 0x3737f9ce, 0xeded977a, 0xf6f649bf,
244
    0xb4b4992d, 0xd1d1a475, 0x434390d3, 0x48485a12, 0xe2e258ba, 0x979771e6,
245
    0xd2d264b6, 0xc2c270b2, 0x2626ad8b, 0xa5a5cd68, 0x5e5ecb95, 0x2929624b,
246
    0x30303c0c, 0x5a5ace94, 0xddddab76, 0xf9f9867f, 0x9595f164, 0xe6e65dbb,
247
    0xc7c735f2, 0x24242d09, 0x1717d1c6, 0xb9b9d66f, 0x1b1bdec5, 0x12129486,
248
    0x60607818, 0xc3c330f3, 0xf5f5897c, 0xb3b35cef, 0xe8e8d23a, 0x7373acdf,
249
    0x3535794c, 0x8080a020, 0xe5e59d78, 0xbbbb56ed, 0x7d7d235e, 0xf8f8c63e,
250
    0x5f5f8bd4, 0x2f2fe7c8, 0xe4e4dd39, 0x21216849,
251
};
252
static const word32 sm4_sbox_2[256] = {
253
    0x5b8ed55b, 0x42d09242, 0xa74deaa7, 0xfb06fdfb, 0x33fccf33, 0x8765e287,
254
    0xf4c93df4, 0xde6bb5de, 0x584e1658, 0xda6eb4da, 0x50441450, 0x0bcac10b,
255
    0xa08828a0, 0xef17f8ef, 0xb09c2cb0, 0x14110514, 0xac872bac, 0x9dfb669d,
256
    0x6af2986a, 0xd9ae77d9, 0xa8822aa8, 0xfa46bcfa, 0x10140410, 0x0fcfc00f,
257
    0xaa02a8aa, 0x11544511, 0x4c5f134c, 0x98be2698, 0x256d4825, 0x1a9e841a,
258
    0x181e0618, 0x66fd9b66, 0x72ec9e72, 0x094a4309, 0x41105141, 0xd324f7d3,
259
    0x46d59346, 0xbf53ecbf, 0x62f89a62, 0xe9927be9, 0xccff33cc, 0x51045551,
260
    0x2c270b2c, 0x0d4f420d, 0xb759eeb7, 0x3ff3cc3f, 0xb21caeb2, 0x89ea6389,
261
    0x9374e793, 0xce7fb1ce, 0x706c1c70, 0xa60daba6, 0x27edca27, 0x20280820,
262
    0xa348eba3, 0x56c19756, 0x02808202, 0x7fa3dc7f, 0x52c49652, 0xeb12f9eb,
263
    0xd5a174d5, 0x3eb38d3e, 0xfcc33ffc, 0x9a3ea49a, 0x1d5b461d, 0x1c1b071c,
264
    0x9e3ba59e, 0xf30cfff3, 0xcf3ff0cf, 0xcdbf72cd, 0x5c4b175c, 0xea52b8ea,
265
    0x0e8f810e, 0x653d5865, 0xf0cc3cf0, 0x647d1964, 0x9b7ee59b, 0x16918716,
266
    0x3d734e3d, 0xa208aaa2, 0xa1c869a1, 0xadc76aad, 0x06858306, 0xca7ab0ca,
267
    0xc5b570c5, 0x91f46591, 0x6bb2d96b, 0x2ea7892e, 0xe318fbe3, 0xaf47e8af,
268
    0x3c330f3c, 0x2d674a2d, 0xc1b071c1, 0x590e5759, 0x76e99f76, 0xd4e135d4,
269
    0x78661e78, 0x90b42490, 0x38360e38, 0x79265f79, 0x8def628d, 0x61385961,
270
    0x4795d247, 0x8a2aa08a, 0x94b12594, 0x88aa2288, 0xf18c7df1, 0xecd73bec,
271
    0x04050104, 0x84a52184, 0xe19879e1, 0x1e9b851e, 0x5384d753, 0x00000000,
272
    0x195e4719, 0x5d0b565d, 0x7ee39d7e, 0x4f9fd04f, 0x9cbb279c, 0x491a5349,
273
    0x317c4d31, 0xd8ee36d8, 0x080a0208, 0x9f7be49f, 0x8220a282, 0x13d4c713,
274
    0x23e8cb23, 0x7ae69c7a, 0xab42e9ab, 0xfe43bdfe, 0x2aa2882a, 0x4b9ad14b,
275
    0x01404101, 0x1fdbc41f, 0xe0d838e0, 0xd661b7d6, 0x8e2fa18e, 0xdf2bf4df,
276
    0xcb3af1cb, 0x3bf6cd3b, 0xe71dfae7, 0x85e56085, 0x54411554, 0x8625a386,
277
    0x8360e383, 0xba16acba, 0x75295c75, 0x9234a692, 0x6ef7996e, 0xd0e434d0,
278
    0x68721a68, 0x55015455, 0xb619afb6, 0x4edf914e, 0xc8fa32c8, 0xc0f030c0,
279
    0xd721f6d7, 0x32bc8e32, 0xc675b3c6, 0x8f6fe08f, 0x74691d74, 0xdb2ef5db,
280
    0x8b6ae18b, 0xb8962eb8, 0x0a8a800a, 0x99fe6799, 0x2be2c92b, 0x81e06181,
281
    0x03c0c303, 0xa48d29a4, 0x8caf238c, 0xae07a9ae, 0x34390d34, 0x4d1f524d,
282
    0x39764f39, 0xbdd36ebd, 0x5781d657, 0x6fb7d86f, 0xdceb37dc, 0x15514415,
283
    0x7ba6dd7b, 0xf709fef7, 0x3ab68c3a, 0xbc932fbc, 0x0c0f030c, 0xff03fcff,
284
    0xa9c26ba9, 0xc9ba73c9, 0xb5d96cb5, 0xb1dc6db1, 0x6d375a6d, 0x45155045,
285
    0x36b98f36, 0x6c771b6c, 0xbe13adbe, 0x4ada904a, 0xee57b9ee, 0x77a9de77,
286
    0xf24cbef2, 0xfd837efd, 0x44551144, 0x67bdda67, 0x712c5d71, 0x05454005,
287
    0x7c631f7c, 0x40501040, 0x69325b69, 0x63b8db63, 0x28220a28, 0x07c5c207,
288
    0xc4f531c4, 0x22a88a22, 0x9631a796, 0x37f9ce37, 0xed977aed, 0xf649bff6,
289
    0xb4992db4, 0xd1a475d1, 0x4390d343, 0x485a1248, 0xe258bae2, 0x9771e697,
290
    0xd264b6d2, 0xc270b2c2, 0x26ad8b26, 0xa5cd68a5, 0x5ecb955e, 0x29624b29,
291
    0x303c0c30, 0x5ace945a, 0xddab76dd, 0xf9867ff9, 0x95f16495, 0xe65dbbe6,
292
    0xc735f2c7, 0x242d0924, 0x17d1c617, 0xb9d66fb9, 0x1bdec51b, 0x12948612,
293
    0x60781860, 0xc330f3c3, 0xf5897cf5, 0xb35cefb3, 0xe8d23ae8, 0x73acdf73,
294
    0x35794c35, 0x80a02080, 0xe59d78e5, 0xbb56edbb, 0x7d235e7d, 0xf8c63ef8,
295
    0x5f8bd45f, 0x2fe7c82f, 0xe4dd39e4, 0x21684921,
296
};
297
static const word32 sm4_sbox_3[256] = {
298
    0x8ed55b5b, 0xd0924242, 0x4deaa7a7, 0x06fdfbfb, 0xfccf3333, 0x65e28787,
299
    0xc93df4f4, 0x6bb5dede, 0x4e165858, 0x6eb4dada, 0x44145050, 0xcac10b0b,
300
    0x8828a0a0, 0x17f8efef, 0x9c2cb0b0, 0x11051414, 0x872bacac, 0xfb669d9d,
301
    0xf2986a6a, 0xae77d9d9, 0x822aa8a8, 0x46bcfafa, 0x14041010, 0xcfc00f0f,
302
    0x02a8aaaa, 0x54451111, 0x5f134c4c, 0xbe269898, 0x6d482525, 0x9e841a1a,
303
    0x1e061818, 0xfd9b6666, 0xec9e7272, 0x4a430909, 0x10514141, 0x24f7d3d3,
304
    0xd5934646, 0x53ecbfbf, 0xf89a6262, 0x927be9e9, 0xff33cccc, 0x04555151,
305
    0x270b2c2c, 0x4f420d0d, 0x59eeb7b7, 0xf3cc3f3f, 0x1caeb2b2, 0xea638989,
306
    0x74e79393, 0x7fb1cece, 0x6c1c7070, 0x0daba6a6, 0xedca2727, 0x28082020,
307
    0x48eba3a3, 0xc1975656, 0x80820202, 0xa3dc7f7f, 0xc4965252, 0x12f9ebeb,
308
    0xa174d5d5, 0xb38d3e3e, 0xc33ffcfc, 0x3ea49a9a, 0x5b461d1d, 0x1b071c1c,
309
    0x3ba59e9e, 0x0cfff3f3, 0x3ff0cfcf, 0xbf72cdcd, 0x4b175c5c, 0x52b8eaea,
310
    0x8f810e0e, 0x3d586565, 0xcc3cf0f0, 0x7d196464, 0x7ee59b9b, 0x91871616,
311
    0x734e3d3d, 0x08aaa2a2, 0xc869a1a1, 0xc76aadad, 0x85830606, 0x7ab0caca,
312
    0xb570c5c5, 0xf4659191, 0xb2d96b6b, 0xa7892e2e, 0x18fbe3e3, 0x47e8afaf,
313
    0x330f3c3c, 0x674a2d2d, 0xb071c1c1, 0x0e575959, 0xe99f7676, 0xe135d4d4,
314
    0x661e7878, 0xb4249090, 0x360e3838, 0x265f7979, 0xef628d8d, 0x38596161,
315
    0x95d24747, 0x2aa08a8a, 0xb1259494, 0xaa228888, 0x8c7df1f1, 0xd73becec,
316
    0x05010404, 0xa5218484, 0x9879e1e1, 0x9b851e1e, 0x84d75353, 0x00000000,
317
    0x5e471919, 0x0b565d5d, 0xe39d7e7e, 0x9fd04f4f, 0xbb279c9c, 0x1a534949,
318
    0x7c4d3131, 0xee36d8d8, 0x0a020808, 0x7be49f9f, 0x20a28282, 0xd4c71313,
319
    0xe8cb2323, 0xe69c7a7a, 0x42e9abab, 0x43bdfefe, 0xa2882a2a, 0x9ad14b4b,
320
    0x40410101, 0xdbc41f1f, 0xd838e0e0, 0x61b7d6d6, 0x2fa18e8e, 0x2bf4dfdf,
321
    0x3af1cbcb, 0xf6cd3b3b, 0x1dfae7e7, 0xe5608585, 0x41155454, 0x25a38686,
322
    0x60e38383, 0x16acbaba, 0x295c7575, 0x34a69292, 0xf7996e6e, 0xe434d0d0,
323
    0x721a6868, 0x01545555, 0x19afb6b6, 0xdf914e4e, 0xfa32c8c8, 0xf030c0c0,
324
    0x21f6d7d7, 0xbc8e3232, 0x75b3c6c6, 0x6fe08f8f, 0x691d7474, 0x2ef5dbdb,
325
    0x6ae18b8b, 0x962eb8b8, 0x8a800a0a, 0xfe679999, 0xe2c92b2b, 0xe0618181,
326
    0xc0c30303, 0x8d29a4a4, 0xaf238c8c, 0x07a9aeae, 0x390d3434, 0x1f524d4d,
327
    0x764f3939, 0xd36ebdbd, 0x81d65757, 0xb7d86f6f, 0xeb37dcdc, 0x51441515,
328
    0xa6dd7b7b, 0x09fef7f7, 0xb68c3a3a, 0x932fbcbc, 0x0f030c0c, 0x03fcffff,
329
    0xc26ba9a9, 0xba73c9c9, 0xd96cb5b5, 0xdc6db1b1, 0x375a6d6d, 0x15504545,
330
    0xb98f3636, 0x771b6c6c, 0x13adbebe, 0xda904a4a, 0x57b9eeee, 0xa9de7777,
331
    0x4cbef2f2, 0x837efdfd, 0x55114444, 0xbdda6767, 0x2c5d7171, 0x45400505,
332
    0x631f7c7c, 0x50104040, 0x325b6969, 0xb8db6363, 0x220a2828, 0xc5c20707,
333
    0xf531c4c4, 0xa88a2222, 0x31a79696, 0xf9ce3737, 0x977aeded, 0x49bff6f6,
334
    0x992db4b4, 0xa475d1d1, 0x90d34343, 0x5a124848, 0x58bae2e2, 0x71e69797,
335
    0x64b6d2d2, 0x70b2c2c2, 0xad8b2626, 0xcd68a5a5, 0xcb955e5e, 0x624b2929,
336
    0x3c0c3030, 0xce945a5a, 0xab76dddd, 0x867ff9f9, 0xf1649595, 0x5dbbe6e6,
337
    0x35f2c7c7, 0x2d092424, 0xd1c61717, 0xd66fb9b9, 0xdec51b1b, 0x94861212,
338
    0x78186060, 0x30f3c3c3, 0x897cf5f5, 0x5cefb3b3, 0xd23ae8e8, 0xacdf7373,
339
    0x794c3535, 0xa0208080, 0x9d78e5e5, 0x56edbbbb, 0x235e7d7d, 0xc63ef8f8,
340
    0x8bd45f5f, 0xe7c82f2f, 0xdd39e4e4, 0x68492121,
341
};
342
343
/* Linear transformation of nonlinear transformation tau.
344
 *
345
 * Each S-box value has had the linear transformation applied.
346
 *
347
 * @param [in] x  Unsigned 32-bit value to transform.
348
 * @return  Unsigned 32-bit bit value.
349
 */
350
static WC_INLINE word32 sm4_t(word32 x)
351
0
{
352
0
    return sm4_sbox_3[(byte)(x >> 24)] ^
353
0
           sm4_sbox_2[(byte)(x >> 16)] ^
354
0
           sm4_sbox_1[(byte)(x >>  8)] ^
355
0
           sm4_sbox_0[(byte)(x >>  0)];
356
0
}
357
358
#else
359
360
/* Linear transformation of nonlinear transformation tau.
361
 *
362
 * @param [in] x  Unsigned 32-bit value to transform.
363
 * @return  Unsigned 32-bit bit value.
364
 */
365
static word32 sm4_t(word32 x)
366
{
367
    word32 t;
368
369
    /* Nonlinear transformation. */
370
    t  = ((word32)sm4_sbox[(byte)(x >> 24)]) << 24;
371
    t |= ((word32)sm4_sbox[(byte)(x >> 16)]) << 16;
372
    t |= ((word32)sm4_sbox[(byte)(x >>  8)]) <<  8;
373
    t |=          sm4_sbox[(byte) x       ]       ;
374
375
    /* Linear transformation. */
376
    return t ^ rotlFixed(t, 2) ^ rotlFixed(t, 10) ^ rotlFixed(t, 18) ^
377
        rotlFixed(t, 24);
378
}
379
380
#endif
381
382
#endif /* !__aarch64__ || !WOLFSSL_ARMASM_CRYPTO_SM4 */
383
384
/* Key schedule calculation.
385
 *
386
 * @param [in]  key  Array of bytes representing key.
387
 * @param [out] ks   Array of unsigned 32-bit values that are the key schedule.
388
 */
389
static void sm4_key_schedule(const byte* key, word32* ks)
390
0
{
391
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
392
#ifndef WOLFSSL_SMALL_STACK
393
    word32 k[36];
394
    word32 t;
395
    word32 x;
396
    int i;
397
398
    /* Load key into words. */
399
    LOAD_U32_BE(key, k[0], k[1], k[2], k[3]);
400
    k[0] ^= sm4_fk[0];
401
    k[1] ^= sm4_fk[1];
402
    k[2] ^= sm4_fk[2];
403
    k[3] ^= sm4_fk[3];
404
405
    /* Calculate each word of key schedule. */
406
    for (i = 0; i < SM4_KEY_SCHEDULE; ++i) {
407
        x = k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ sm4_ck[i];
408
409
        /* Nonlinear operation tau */
410
        t = ((word32)sm4_sbox[(byte)(x >> 24)]) << 24 |
411
            ((word32)sm4_sbox[(byte)(x >> 16)]) << 16 |
412
            ((word32)sm4_sbox[(byte)(x >>  8)]) <<  8 |
413
            ((word32)sm4_sbox[(byte)(x      )])       ;
414
415
        /* Linear operation L' */
416
        k[i+4] = k[i] ^ (t ^ rotlFixed(t, 13) ^ rotlFixed(t, 23));
417
        ks[i] = k[i + 4];
418
    }
419
#else
420
0
    word32 k[8];
421
0
    word32 t;
422
0
    word32 x;
423
0
    int i;
424
425
    /* Load key into words. */
426
0
    LOAD_U32_BE(key, k[0], k[1], k[2], k[3]);
427
0
    k[0] ^= sm4_fk[0];
428
0
    k[1] ^= sm4_fk[1];
429
0
    k[2] ^= sm4_fk[2];
430
0
    k[3] ^= sm4_fk[3];
431
432
    /* Calculate first 4 words of key schedule using k. */
433
0
    for (i = 0; i < 4; ++i) {
434
0
        x = k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ sm4_ck[i];
435
436
        /* Nonlinear operation tau */
437
0
        t = ((word32)sm4_sbox[(byte)(x >> 24)]) << 24 |
438
0
            ((word32)sm4_sbox[(byte)(x >> 16)]) << 16 |
439
0
            ((word32)sm4_sbox[(byte)(x >>  8)]) <<  8 |
440
0
            ((word32)sm4_sbox[(byte)(x      )])       ;
441
442
        /* Linear operation L' */
443
0
        k[i + 4] = k[i] ^ (t ^ rotlFixed(t, 13) ^ rotlFixed(t, 23));
444
0
        ks[i] = k[i + 4];
445
0
    }
446
    /* Calculate remaining words of key schedule without k. */
447
0
    for (; i < SM4_KEY_SCHEDULE; ++i) {
448
0
        x = ks[i - 3] ^ ks[i - 2] ^ ks[i - 1] ^ sm4_ck[i];
449
450
        /* Nonlinear operation tau */
451
0
        t = ((word32)sm4_sbox[(byte)(x >> 24)]) << 24 |
452
0
            ((word32)sm4_sbox[(byte)(x >> 16)]) << 16 |
453
0
            ((word32)sm4_sbox[(byte)(x >>  8)]) <<  8 |
454
0
            ((word32)sm4_sbox[(byte)(x      )])       ;
455
456
        /* Linear operation L' */
457
0
        ks[i] = ks[i - 4] ^ (t ^ rotlFixed(t, 13) ^ rotlFixed(t, 23));
458
0
    }
459
0
#endif
460
#else
461
    word32* ck = sm4_ck;
462
463
    __asm__ volatile (
464
        "LD1  {v0.16b}, [%[key]]\n\t"
465
        "LD1  {v9.16b}, [%[fk]]\n\t"
466
        "REV32  v0.16B, v0.16B\n\t"
467
        "LD1  {v1.4S-v4.4S}, [%[ck]], #64\n\t"
468
        "EOR  v0.16B, v0.16B, v9.16B\n\t"
469
        "LD1  {v5.4S-v8.4S}, [%[ck]]\n\t"
470
471
        "SM4EKEY  v1.4S, v0.4S, v1.4S\n\t"
472
        "SM4EKEY  v2.4S, v1.4S, v2.4S\n\t"
473
        "SM4EKEY  v3.4S, v2.4S, v3.4S\n\t"
474
        "SM4EKEY  v4.4S, v3.4S, v4.4S\n\t"
475
        "SM4EKEY  v5.4S, v4.4S, v5.4S\n\t"
476
        "SM4EKEY  v6.4S, v5.4S, v6.4S\n\t"
477
        "SM4EKEY  v7.4S, v6.4S, v7.4S\n\t"
478
        "SM4EKEY  v8.4S, v7.4S, v8.4S\n\t"
479
480
        "ST4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
481
        "ST4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
482
        "ST4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
483
        "ST4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
484
        "ST4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
485
        "ST4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
486
        "ST4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
487
        "ST4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
488
        : [ks] "+r" (ks), [ck] "+r" (ck)
489
        : [key] "r" (key), [fk] "r" (sm4_fk)
490
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8",
491
          "v9"
492
    );
493
#endif
494
0
}
495
496
/* Round operation.
497
 *
498
 * Assumes x0, x1, x2, x3 are the current state.
499
 * Assumes ks is the key schedule.
500
 *
501
 * @param [in] k0  Index into key schedule for first word.
502
 * @param [in] k1  Index into key schedule for second word.
503
 * @param [in] k2  Index into key schedule for third word.
504
 * @param [in] k3  Index into key schedule for fourth word.
505
 */
506
#define SM4_ROUNDS(k0, k1, k2, k3)          \
507
0
        x0 ^= sm4_t(x1 ^ x2 ^ x3 ^ ks[k0]); \
508
0
        x1 ^= sm4_t(x0 ^ x2 ^ x3 ^ ks[k1]); \
509
0
        x2 ^= sm4_t(x0 ^ x1 ^ x3 ^ ks[k2]); \
510
0
        x3 ^= sm4_t(x0 ^ x1 ^ x2 ^ ks[k3])
511
512
/* Encrypt a block of data using SM4 algorithm.
513
 *
514
 * @param [in]  ks   Key schedule.
515
 * @param [in]  in   Block to encrypt.
516
 * @param [out] out  Encrypted block.
517
 */
518
static void sm4_encrypt(const word32* ks, const byte* in, byte* out)
519
0
{
520
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
521
0
    word32 x0, x1, x2, x3;
522
    /* Load block. */
523
0
    LOAD_U32_BE(in, x0, x1, x2, x3);
524
525
    /* Encrypt block. */
526
0
    SM4_ROUNDS( 0,  1,  2,  3);
527
0
    SM4_ROUNDS( 4,  5,  6,  7);
528
0
    SM4_ROUNDS( 8,  9, 10, 11);
529
0
    SM4_ROUNDS(12, 13, 14, 15);
530
0
    SM4_ROUNDS(16, 17, 18, 19);
531
0
    SM4_ROUNDS(20, 21, 22, 23);
532
0
    SM4_ROUNDS(24, 25, 26, 27);
533
0
    SM4_ROUNDS(28, 29, 30, 31);
534
535
    /* Store encrypted block. */
536
0
    STORE_U32_BE(x0, x1, x2, x3, out);
537
#else
538
    __asm__ volatile (
539
        "LD1  {v0.16b}, [%[in]]\n\t"
540
        "LD4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
541
        "LD4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
542
        "LD4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
543
        "LD4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
544
        "REV32  v0.16B, v0.16B\n\t"
545
        "LD4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
546
        "LD4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
547
        "LD4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
548
        "LD4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
549
550
        "SM4E v0.4S, v1.4S\n\t"
551
        "SM4E v0.4S, v2.4S\n\t"
552
        "SM4E v0.4S, v3.4S\n\t"
553
        "SM4E v0.4S, v4.4S\n\t"
554
        "SM4E v0.4S, v5.4S\n\t"
555
        "SM4E v0.4S, v6.4S\n\t"
556
        "SM4E v0.4S, v7.4S\n\t"
557
        "SM4E v0.4S, v8.4S\n\t"
558
559
        "REV64  v0.16B, v0.16B\n\t"
560
        "EXT  v0.16B, v0.16B, v0.16B, #8\n\t"
561
        "ST1  {v0.16b}, [%[out]]\n\t"
562
563
        : [ks] "+r" (ks), [out] "+r" (out)
564
        : [in] "r" (in)
565
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"
566
    );
567
#endif
568
0
}
569
570
#if defined(WOLFSSL_SM4_ECB) || defined(WOLFSSL_SM4_CBC)
571
/* Decrypt a block of data using SM4 algorithm.
572
 *
573
 * @param [in]  ks   Key schedule.
574
 * @param [in]  in   Block to decrypt.
575
 * @param [out] out  Decrypted block.
576
 */
577
static void sm4_decrypt(const word32* ks, const byte* in, byte* out)
578
0
{
579
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
580
0
    word32 x0, x1, x2, x3;
581
582
    /* Load block. */
583
0
    LOAD_U32_BE(in, x0, x1, x2, x3);
584
585
    /* Decrypt block. */
586
0
    SM4_ROUNDS(31, 30, 29, 28);
587
0
    SM4_ROUNDS(27, 26, 25, 24);
588
0
    SM4_ROUNDS(23, 22, 21, 20);
589
0
    SM4_ROUNDS(19, 18, 17, 16);
590
0
    SM4_ROUNDS(15, 14, 13, 12);
591
0
    SM4_ROUNDS(11, 10,  9,  8);
592
0
    SM4_ROUNDS( 7,  6,  5,  4);
593
0
    SM4_ROUNDS( 3,  2,  1,  0);
594
595
    /* Store decrypted block. */
596
0
    STORE_U32_BE(x0, x1, x2, x3, out);
597
#else
598
    __asm__ volatile (
599
        "LD1  {v0.16b}, [%[in]]\n\t"
600
        "LD4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
601
        "LD4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
602
        "LD4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
603
        "LD4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
604
        "REV32  v0.16B, v0.16B\n\t"
605
        "LD4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
606
        "LD4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
607
        "LD4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
608
        "LD4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
609
610
        "SM4E v0.4S, v8.4S\n\t"
611
        "SM4E v0.4S, v7.4S\n\t"
612
        "SM4E v0.4S, v6.4S\n\t"
613
        "SM4E v0.4S, v5.4S\n\t"
614
        "SM4E v0.4S, v4.4S\n\t"
615
        "SM4E v0.4S, v3.4S\n\t"
616
        "SM4E v0.4S, v2.4S\n\t"
617
        "SM4E v0.4S, v1.4S\n\t"
618
619
        "REV64  v0.16B, v0.16B\n\t"
620
        "EXT  v0.16B, v0.16B, v0.16B, #8\n\t"
621
        "ST1  {v0.16b}, [%[out]]\n\t"
622
623
        : [ks] "+r" (ks)
624
        : [in] "r" (in), [out] "r" (out)
625
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"
626
    );
627
#endif
628
0
}
629
#endif
630
631
632
/* Initialize the SM4 algorithm object.
633
 *
634
 * @param [in, out] sm4    SM4 algorithm object.
635
 * @param [in]      heap   Heap hint for dynamic memory allocation.
636
 * @param [in]      devId  Device identifier.
637
 * @return  0 on success.
638
 * @return  BAD_FUNC_ARG when sm4 is NULL.
639
 */
640
int wc_Sm4Init(wc_Sm4* sm4, void* heap, int devId)
641
0
{
642
0
    int ret = 0;
643
644
    /* No device support yet. */
645
0
    (void)devId;
646
647
    /* Validate parameters. */
648
0
    if (sm4 == NULL) {
649
0
        ret = BAD_FUNC_ARG;
650
0
    }
651
652
0
    if (ret == 0) {
653
        /* Set all fields to zero including bit fields. */
654
0
        XMEMSET(sm4, 0, sizeof(*sm4));
655
656
        /* Cache heap hint to use with any dynamic allocations. */
657
0
        sm4->heap = heap;
658
0
    }
659
660
0
    return ret;
661
0
}
662
663
/* Dispose of SM4 algorithm object.
664
 *
665
 * Zeroize sensitive data in object.
666
 *
667
 * @param [in, out] sm4  SM4 algorithm object.
668
 */
669
void wc_Sm4Free(wc_Sm4* sm4)
670
0
{
671
    /* Check we have something to work with. */
672
0
    if (sm4 != NULL) {
673
        /* Must zeroize key schedule. */
674
0
        ForceZero(sm4->ks, sizeof(sm4->ks));
675
0
    #if defined(WOLFSSL_SM4_CTR)
676
        /* For CBC, tmp is cipher text - no need to zeroize. */
677
        /* For CTR, tmp is encrypted counter that must be zeroized. */
678
0
        ForceZero(sm4->tmp, sizeof(sm4->tmp));
679
0
    #endif
680
0
    }
681
0
}
682
683
/* Set the key.
684
 *
685
 * @param [in, out] sm4  SM4 algorithm object.
686
 * @param [in]      key  Array of bytes representing key.
687
 */
688
static void sm4_set_key(wc_Sm4* sm4, const byte* key)
689
0
{
690
    /* Create key schedule. */
691
0
    sm4_key_schedule(key, sm4->ks);
692
    /* Mark key as having been set. */
693
0
    sm4->keySet = 1;
694
0
}
695
696
#if defined(WOLFSSL_SM4_ECB) || defined(WOLFSSL_SM4_CBC) || \
697
    defined(WOLFSSL_SM4_CTR) || defined(WOLFSSL_SM4_CCM)
698
/* Set the key.
699
 *
700
 * @param [in, out] sm4  SM4 algorithm object.
701
 * @param [in]      key  Array of bytes representing key.
702
 * @param [in]      len  Length of key. Must be SM4_KEY_SIZE.
703
 * @return  0 on success.
704
 * @return  BAD_FUNC_ARG when sm4 or key is NULL.
705
 * @return  BAD_FUNC_ARG when len is not SM4_KEY_SIZE.
706
 */
707
int wc_Sm4SetKey(wc_Sm4* sm4, const byte* key, word32 len)
708
0
{
709
0
    int ret = 0;
710
711
    /* Validate parameters. */
712
0
    if ((sm4 == NULL) || (key == NULL) || (len != SM4_KEY_SIZE)) {
713
0
        ret = BAD_FUNC_ARG;
714
0
    }
715
716
0
    if (ret == 0) {
717
0
        sm4_set_key(sm4, key);
718
0
    }
719
720
0
    return ret;
721
0
}
722
#endif
723
724
#if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR) || \
725
    defined(WOLFSSL_SM4_GCM)
726
/* Set the IV.
727
 *
728
 * @param [in, out] sm4  SM4 algorithm object.
729
 * @param [in]      iv   Array of bytes representing IV. May be NULL.
730
 */
731
static void sm4_set_iv(wc_Sm4* sm4, const byte* iv)
732
0
{
733
    /* Set IV. */
734
0
    XMEMCPY(sm4->iv, iv, SM4_IV_SIZE);
735
0
#ifdef WOLFSSL_SM4_CTR
736
    /* Unused count of encrypted counter for CTR mode. */
737
0
    sm4->unused = 0;
738
0
#endif
739
0
    sm4->ivSet = 1;
740
0
}
741
#endif
742
743
#if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR)
744
/* Set the IV.
745
 *
746
 * @param [in, out] sm4  SM4 algorithm object.
747
 * @param [in]      iv   Array of bytes representing IV. May be NULL.
748
 * @return  0 on success.
749
 * @return  BAD_FUNC_ARG when sm4 or iv is NULL.
750
 */
751
int wc_Sm4SetIV(wc_Sm4* sm4, const byte* iv)
752
0
{
753
0
    int ret = 0;
754
755
    /* Validate parameters. */
756
0
    if ((sm4 == NULL) || (iv == NULL)) {
757
0
        ret = BAD_FUNC_ARG;
758
0
    }
759
760
0
    if (ret == 0) {
761
0
        sm4_set_iv(sm4, iv);
762
0
    }
763
764
0
    return ret;
765
0
}
766
#endif
767
768
#ifdef WOLFSSL_SM4_ECB
769
770
/* Encrypt bytes using SM4-ECB.
771
 *
772
 * Length of input must be a multiple of the block size.
773
 * Assumes out is at least sz bytes long.
774
 *
775
 * @param [in]  sm4  SM4 algorithm object.
776
 * @param [out] out  Byte array in which to place encrypted data.
777
 * @param [in]  in   Array of bytes to encrypt.
778
 * @param [in]  sz   Number of bytes to encrypt.
779
 * @return  0 on success.
780
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
781
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
782
 * @return  MISSING_KEY when a key has not been set.
783
 */
784
int wc_Sm4EcbEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
785
0
{
786
0
    int ret = 0;
787
788
    /* Validate parameters. */
789
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
790
0
        ret = BAD_FUNC_ARG;
791
0
    }
792
    /* Can only work on multiples of block size of bytes. */
793
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
794
0
        ret = BAD_FUNC_ARG;
795
0
    }
796
797
    /* Ensure a key has been set. */
798
0
    if ((ret == 0) && (!sm4->keySet)) {
799
0
        ret = MISSING_KEY;
800
0
    }
801
802
0
    if (ret == 0) {
803
        /* Encrypt all bytes. */
804
0
        while (sz > 0) {
805
            /* Encrypt a block. */
806
0
            sm4_encrypt(sm4->ks, in, out);
807
            /* Move on to next block. */
808
0
            in += SM4_BLOCK_SIZE;
809
0
            out += SM4_BLOCK_SIZE;
810
0
            sz -= SM4_BLOCK_SIZE;
811
0
        }
812
0
    }
813
814
0
    return ret;
815
0
}
816
817
/* Decrypt bytes using SM4-ECB.
818
 *
819
 * Length of input must be a multiple of the block size.
820
 * Assumes out is at least sz bytes long.
821
 *
822
 * @param [in]  sm4  SM4 algorithm object.
823
 * @param [out] out  Byte array in which to place decrypted data.
824
 * @param [in]  in   Array of bytes to decrypt.
825
 * @param [in]  sz   Number of bytes to decrypt.
826
 * @return  0 on success.
827
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
828
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
829
 * @return  MISSING_KEY when a key has not been set.
830
 */
831
int wc_Sm4EcbDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
832
0
{
833
834
0
    int ret = 0;
835
836
    /* Validate parameters. */
837
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
838
0
        ret = BAD_FUNC_ARG;
839
0
    }
840
    /* Can only work on multiples of block size of bytes. */
841
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
842
0
        ret = BAD_FUNC_ARG;
843
0
    }
844
845
    /* Ensure a key has been set. */
846
0
    if ((ret == 0) && (!sm4->keySet)) {
847
0
        ret = MISSING_KEY;
848
0
    }
849
850
0
    if (ret == 0) {
851
       /* Decrypt all bytes. */
852
0
        while (sz > 0) {
853
            /* Decrypt a block. */
854
0
            sm4_decrypt(sm4->ks, in, out);
855
            /* Move on to next block. */
856
0
            in += SM4_BLOCK_SIZE;
857
0
            out += SM4_BLOCK_SIZE;
858
0
            sz -= SM4_BLOCK_SIZE;
859
0
        }
860
0
    }
861
862
0
    return ret;
863
0
}
864
865
#endif /* WOLFSSL_SM4_ECB */
866
867
#ifdef WOLFSSL_SM4_CBC
868
869
/* Encrypt bytes using SM4-CBC.
870
 *
871
 * Length of input must be a multiple of the block size.
872
 * Assumes out is at least sz bytes long.
873
 *
874
 * @param [in]  sm4  SM4 algorithm object.
875
 * @param [out] out  Byte array in which to place encrypted data.
876
 * @param [in]  in   Array of bytes to encrypt.
877
 * @param [in]  sz   Number of bytes to encrypt.
878
 * @return  0 on success.
879
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
880
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
881
 * @return  MISSING_KEY when a key has not been set.
882
 * @return  MISSING_IV when an IV has not been set.
883
 */
884
int wc_Sm4CbcEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
885
0
{
886
0
    int ret = 0;
887
888
    /* Validate parameters. */
889
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
890
0
        ret = BAD_FUNC_ARG;
891
0
    }
892
    /* Can only work on multiples of block size of bytes. */
893
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
894
0
        ret = BAD_FUNC_ARG;
895
0
    }
896
897
    /* Ensure a key and IV have been set. */
898
0
    if ((ret == 0) && (!sm4->keySet)) {
899
0
        ret = MISSING_KEY;
900
0
    }
901
0
    if ((ret == 0) && (!sm4->ivSet)) {
902
0
        ret = MISSING_IV;
903
0
    }
904
905
0
    if (ret == 0) {
906
        /* Encrypt all bytes. */
907
0
        while (sz > 0) {
908
            /* XOR next block into IV. */
909
0
            xorbuf(sm4->iv, in, SM4_BLOCK_SIZE);
910
            /* Encrypt IV XORed with block. */
911
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->iv);
912
            /* Use output block as next IV. */
913
0
            XMEMCPY(out, sm4->iv, SM4_BLOCK_SIZE);
914
915
            /* Move on to next block. */
916
0
            in += SM4_BLOCK_SIZE;
917
0
            out += SM4_BLOCK_SIZE;
918
0
            sz -= SM4_BLOCK_SIZE;
919
0
        }
920
0
    }
921
922
0
    return ret;
923
0
}
924
925
/* Decrypt bytes using SM4-CBC.
926
 *
927
 * Length of input must be a multiple of the block size.
928
 * Assumes out is at least sz bytes long.
929
 *
930
 * @param [in]  sm4  SM4 algorithm object.
931
 * @param [out] out  Byte array in which to place decrypted data.
932
 * @param [in]  in   Array of bytes to decrypt.
933
 * @param [in]  sz   Number of bytes to decrypt.
934
 * @return  0 on success.
935
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
936
 * @return  MISSING_KEY when a key has not been set.
937
 * @return  MISSING_IV when an IV has not been set.
938
 */
939
int wc_Sm4CbcDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
940
0
{
941
0
    int ret = 0;
942
943
    /* Validate parameters. */
944
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
945
0
        ret = BAD_FUNC_ARG;
946
0
    }
947
    /* Can only work on multiples of block size of bytes. */
948
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
949
0
        ret = BAD_FUNC_ARG;
950
0
    }
951
952
    /* Ensure a key and IV have been set. */
953
0
    if ((ret == 0) && (!sm4->keySet)) {
954
0
        ret = MISSING_KEY;
955
0
    }
956
0
    if ((ret == 0) && (!sm4->ivSet)) {
957
0
        ret = MISSING_IV;
958
0
    }
959
960
0
    if (ret == 0) {
961
0
    #ifndef WOLFSSL_SM4_SMALL
962
0
        if (in != out) {
963
0
            while (sz > 0) {
964
                /* Decrypt next block. */
965
0
                sm4_decrypt(sm4->ks, in, sm4->tmp);
966
                /* XOR decrypted block with IV to create output. */
967
0
                xorbufout(out, sm4->tmp, sm4->iv, SM4_BLOCK_SIZE);
968
                /* This encrypted block is the IV for next decryption. */
969
0
                XMEMCPY(sm4->iv, in, SM4_BLOCK_SIZE);
970
971
                /* Move on to next block. */
972
0
                in += SM4_BLOCK_SIZE;
973
0
                out += SM4_BLOCK_SIZE;
974
0
                sz -= SM4_BLOCK_SIZE;
975
0
            }
976
0
        }
977
0
        else
978
0
    #endif
979
0
        {
980
0
            while (sz > 0) {
981
                /* Cache encrypted block as it is next IV. */
982
0
                XMEMCPY(sm4->tmp, in, SM4_BLOCK_SIZE);
983
                /* Decrypt next block. */
984
0
                sm4_decrypt(sm4->ks, sm4->tmp, out);
985
                /* XOR decrypted block with IV to create output. */
986
0
                xorbuf(out, sm4->iv, SM4_BLOCK_SIZE);
987
                /* Cached encrypted block is next IV. */
988
0
                XMEMCPY(sm4->iv, sm4->tmp, SM4_BLOCK_SIZE);
989
990
                /* Move on to next block. */
991
0
                in += SM4_BLOCK_SIZE;
992
0
                out += SM4_BLOCK_SIZE;
993
0
                sz -= SM4_BLOCK_SIZE;
994
0
            }
995
0
        }
996
0
    }
997
998
0
    return ret;
999
0
}
1000
1001
#endif /* WOLFSSL_SM4_CBC */
1002
1003
#ifdef WOLFSSL_SM4_CTR
1004
1005
/* Increment IV in big-endian representation.
1006
 *
1007
 * @param [in, out] counter  Counter value to increment.
1008
 */
1009
static WC_INLINE void sm4_increment_counter(byte* counter)
1010
0
{
1011
0
    int i;
1012
1013
    /* Big-endian number. */
1014
0
    for (i = SM4_BLOCK_SIZE - 1; i >= 0; i--) {
1015
        /* Increment byte and check for carry. */
1016
0
        if ((++counter[i]) != 0) {
1017
            /* No carry - done. */
1018
0
            break;
1019
0
        }
1020
0
    }
1021
0
}
1022
1023
/* Encrypt bytes using SM4-CTR.
1024
 *
1025
 * Assumes out is at least sz bytes long.
1026
 *
1027
 * @param [in]  sm4  SM4 algorithm object.
1028
 * @param [out] out  Byte array in which to place encrypted data.
1029
 * @param [in]  in   Array of bytes to encrypt.
1030
 * @param [in]  sz   Number of bytes to encrypt.
1031
 * @return  0 on success.
1032
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
1033
 * @return  MISSING_KEY when a key has not been set.
1034
 * @return  MISSING_IV when an IV has not been set.
1035
 */
1036
int wc_Sm4CtrEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
1037
0
{
1038
0
    int ret = 0;
1039
1040
    /* Validate parameters. */
1041
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
1042
0
        ret = BAD_FUNC_ARG;
1043
0
    }
1044
1045
    /* Ensure a key and IV have been set. */
1046
0
    if ((ret == 0) && (!sm4->keySet)) {
1047
0
        ret = MISSING_KEY;
1048
0
    }
1049
0
    if ((ret == 0) && (!sm4->ivSet)) {
1050
0
        ret = MISSING_IV;
1051
0
    }
1052
1053
    /* Continue if no error and bytes to encrypt. */
1054
0
    if ((ret == 0) && (sz > 0)) {
1055
        /* Check for unused bytes from previous encrypted counter. */
1056
0
        if (sm4->unused != 0) {
1057
            /* Calculate maximum length that can be encrypted. */
1058
0
            word32 len = min(sm4->unused, sz);
1059
1060
            /* XOR the encrypted counter with input into output. */
1061
0
            xorbufout(out, in, sm4->tmp + SM4_BLOCK_SIZE - sm4->unused, len);
1062
1063
            /* Move over processed data. */
1064
0
            in += len;
1065
0
            out += len;
1066
0
            sz -= len;
1067
            /* Some or all unused bytes used up. */
1068
0
            sm4->unused -= (byte)len;
1069
0
        }
1070
1071
        /* Do blocks at a time - only get here when there are no unused bytes.
1072
         */
1073
0
        while (sz >= SM4_BLOCK_SIZE) {
1074
            /* Encrypt the current IV into temporary buffer in object. */
1075
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->tmp);
1076
            /* XOR the encrypted IV with next block into output. */
1077
0
            xorbufout(out, in, sm4->tmp, SM4_BLOCK_SIZE);
1078
            /* Increment counter for next block. */
1079
0
            sm4_increment_counter(sm4->iv);
1080
1081
            /* Move on to next block. */
1082
0
            in += SM4_BLOCK_SIZE;
1083
0
            out += SM4_BLOCK_SIZE;
1084
0
            sz -= SM4_BLOCK_SIZE;
1085
0
        }
1086
1087
        /* Check for less than a block of data that needing to be encrypted. */
1088
0
        if (sz > 0) {
1089
            /* Encrypt the current IV into temporary buffer in object. */
1090
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->tmp);
1091
            /* Increment counter for next block. */
1092
0
            sm4_increment_counter(sm4->iv);
1093
            /* XOR the encrypted IV with remaining data into output. */
1094
0
            xorbufout(out, in, sm4->tmp, sz);
1095
            /* Record number of unused encrypted IV bytes. */
1096
0
            sm4->unused = (byte)(SM4_BLOCK_SIZE - sz);
1097
0
        }
1098
0
    }
1099
1100
0
    return ret;
1101
0
}
1102
1103
#endif /* WOLFSSL_SM4_CTR */
1104
1105
#ifdef WOLFSSL_SM4_GCM
1106
/* Calculate the value of H for the GMAC operation.
1107
 *
1108
 * @param [in]  sm4  SM4 algorithm object.
1109
 * @param [in]  iv   Initial IV.
1110
 */
1111
static void sm4_gcm_calc_h(wc_Sm4* sm4, byte* iv)
1112
0
{
1113
#if defined(__aarch64__) && defined(WOLFSSL_ARMASM)
1114
    word32* pt = (word32*)sm4->gcm.H;
1115
#endif
1116
1117
    /* Encrypt all zeros IV to create hash key for GCM. */
1118
0
    sm4_encrypt(sm4->ks, iv, sm4->gcm.H);
1119
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM)
1120
0
    #if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT)
1121
        /* Generate table from hash key. */
1122
0
        GenerateM0(&sm4->gcm);
1123
0
    #endif /* GCM_TABLE */
1124
#else
1125
    /* Reverse the bits of H for use in assembly. */
1126
    __asm__ volatile (
1127
        "LD1 {v0.16b}, [%[h]] \n"
1128
        "RBIT v0.16b, v0.16b \n"
1129
        "ST1 {v0.16b}, [%[out]] \n"
1130
        : [out] "=r" (pt)
1131
        : [h] "0" (pt)
1132
        : "cc", "memory", "v0"
1133
    );
1134
#endif
1135
0
}
1136
1137
/* Increment counter for GCM.
1138
 *
1139
 * @param [in, out] counter  4-byte big endian number.
1140
 */
1141
static WC_INLINE void sm4_increment_gcm_counter(byte* counter)
1142
0
{
1143
0
    int i;
1144
1145
    /* Big-endian number in last 4 bytes. */
1146
0
    for (i = SM4_BLOCK_SIZE - 1; i >= SM4_BLOCK_SIZE - CTR_SZ; i--) {
1147
        /* Increment byte and check for carry. */
1148
0
        if ((++counter[i]) != 0) {
1149
            /* No carry - done. */
1150
0
            break;
1151
0
        }
1152
0
    }
1153
0
}
1154
1155
/* Encrypt bytes using SM4-GCM implementation in C.
1156
 *
1157
 * @param [in]  sm4      SM4 algorithm object.
1158
 * @param [out] out      Byte array in which to place encrypted data.
1159
 * @param [in]  in       Array of bytes to encrypt.
1160
 * @param [in]  sz       Number of bytes to encrypt.
1161
 * @param [in]  nonce    Array of bytes holding nonce.
1162
 * @param [in]  nonceSz  Length of nonce in bytes.
1163
 * @param [out] tag      Authentication tag calculated using GCM.
1164
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1165
 *                       Must be no more than SM4_BLOCK_SIZE.
1166
 * @param [in]  aad      Additional authentication data. May be NULL.
1167
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1168
 */
1169
static void sm4_gcm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1170
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz,
1171
    const byte* aad, word32 aadSz)
1172
0
{
1173
0
    word32 blocks = sz / SM4_BLOCK_SIZE;
1174
0
    word32 partial = sz % SM4_BLOCK_SIZE;
1175
0
    byte* c = out;
1176
0
    ALIGN16 byte counter[SM4_BLOCK_SIZE];
1177
0
    ALIGN16 byte encCounter[SM4_BLOCK_SIZE];
1178
1179
    /* Check for 12 bytes of nonce to use as is with 4 bytes of counter. */
1180
0
    if (nonceSz == GCM_NONCE_MID_SZ) {
1181
        /* Counter is nonce with bottom 4 bytes set to: 0x00,0x00,0x00,0x01. */
1182
0
        XMEMCPY(counter, nonce, nonceSz);
1183
0
        XMEMSET(counter + GCM_NONCE_MID_SZ, 0, CTR_SZ - 1);
1184
0
        counter[SM4_BLOCK_SIZE - 1] = 1;
1185
0
    }
1186
0
    else {
1187
        /* Counter is GHASH of nonce. */
1188
0
        GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE);
1189
#ifdef WOLFSSL_ARMASM
1190
        GMULT(counter, sm4->gcm.H);
1191
#endif
1192
0
    }
1193
    /* Encrypt the initial counter for GMAC. */
1194
0
    sm4_encrypt(sm4->ks, counter, encCounter);
1195
1196
0
#if defined(WOLFSSL_SM4_ECB)
1197
    /* Encrypting multiple blocks at a time can be faster. */
1198
0
    if ((c != in) && (blocks > 0)) {
1199
        /* Set the counters for a multiple of block size into the output. */
1200
0
        while (blocks--) {
1201
            /* Increment last 4 bytes of big-endian counter. */
1202
0
            sm4_increment_gcm_counter(counter);
1203
            /* Copy into output. */
1204
0
            XMEMCPY(c, counter, SM4_BLOCK_SIZE);
1205
            /* Move output position past this block. */
1206
0
            c += SM4_BLOCK_SIZE;
1207
0
        }
1208
1209
        /* Reset number of blocks. */
1210
0
        blocks = sz / SM4_BLOCK_SIZE;
1211
        /* Encrypt the counters. */
1212
0
        wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks);
1213
        /* XOR in the plaintext to create cipher text. */
1214
0
        xorbuf(out, in, SM4_BLOCK_SIZE * blocks);
1215
        /* Step over handled plaintext */
1216
0
        in += SM4_BLOCK_SIZE * blocks;
1217
0
    }
1218
0
    else
1219
0
#endif /* HAVE_SM4_ECB */
1220
0
    {
1221
0
        ALIGN32 byte scratch[SM4_BLOCK_SIZE];
1222
1223
        /* For each full block of data, encrypt. */
1224
0
        while (blocks--) {
1225
            /* Increment last 4 bytes of big-endian counter. */
1226
0
            sm4_increment_gcm_counter(counter);
1227
            /* Encrypt the counter into scratch. */
1228
0
            sm4_encrypt(sm4->ks, counter, scratch);
1229
            /* XOR encryted counter with plaintext into output. */
1230
0
            xorbufout(c, scratch, in, SM4_BLOCK_SIZE);
1231
            /* Move plaintext and cipher text position past this block. */
1232
0
            in += SM4_BLOCK_SIZE;
1233
0
            c += SM4_BLOCK_SIZE;
1234
0
        }
1235
0
    }
1236
1237
0
    if (partial != 0) {
1238
        /* Increment last 4 bytes of big-endian counter. */
1239
0
        sm4_increment_gcm_counter(counter);
1240
        /* Encrypt the last counter. */
1241
0
        sm4_encrypt(sm4->ks, counter, counter);
1242
        /* XOR encryted counter with partial block plaintext into output. */
1243
0
        xorbufout(c, counter, in, partial);
1244
0
    }
1245
1246
    /* Calculate GHASH on additional authentication data and cipher text. */
1247
0
#ifndef WOLFSSL_ARMASM
1248
0
    GHASH(&sm4->gcm, aad, aadSz, out, sz, tag, tagSz);
1249
#else
1250
    GHASH(&sm4->gcm, aad, aadSz, out, sz, counter, SM4_BLOCK_SIZE);
1251
    GMULT(counter, sm4->gcm.H);
1252
    XMEMCPY(tag, counter, tagSz);
1253
#endif
1254
    /* XOR the encrypted initial counter into tag. */
1255
0
    xorbuf(tag, encCounter, tagSz);
1256
0
}
1257
1258
/* Decrypt bytes using SM4-GCM implementation in C.
1259
 *
1260
 * @param [in]  sm4      SM4 algorithm object.
1261
 * @param [out] out      Byte array in which to place decrypted data.
1262
 * @param [in]  in       Array of bytes to decrypt.
1263
 * @param [in]  sz       Number of bytes to decrypt.
1264
 * @param [in]  nonce    Array of bytes holding initialization vector.
1265
 * @param [in]  nonceSz  Length of nonce in bytes.
1266
 * @param [in]  tag      Authentication tag calculated using GCM.
1267
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1268
 *                       Must be no more than SM4_BLOCK_SIZE.
1269
 * @param [in]  aad      Additional authentication data. May be NULL.
1270
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1271
 * @return  0 on success.
1272
 * @return  SM4_GCM_AUTH_E when authentication tag calculated does not match
1273
 *          the one passed in.
1274
 */
1275
static int sm4_gcm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1276
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1277
    const byte* aad, word32 aadSz)
1278
0
{
1279
0
    int ret;
1280
0
    word32 blocks = sz / SM4_BLOCK_SIZE;
1281
0
    word32 partial = sz % SM4_BLOCK_SIZE;
1282
0
    byte* p = out;
1283
0
    ALIGN16 byte counter[SM4_BLOCK_SIZE];
1284
0
    ALIGN16 byte calcTag[SM4_BLOCK_SIZE];
1285
0
    ALIGN16 byte scratch[SM4_BLOCK_SIZE];
1286
0
    sword32 res;
1287
1288
0
    if (nonceSz == GCM_NONCE_MID_SZ) {
1289
        /* Counter is nonce with bottom 4 bytes set to: 0x00,0x00,0x00,0x01. */
1290
0
        XMEMCPY(counter, nonce, nonceSz);
1291
0
        XMEMSET(counter + GCM_NONCE_MID_SZ, 0, CTR_SZ - 1);
1292
0
        counter[SM4_BLOCK_SIZE - 1] = 1;
1293
0
    }
1294
0
    else {
1295
        /* Counter is GHASH of nonce. */
1296
0
        GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE);
1297
#ifdef WOLFSSL_ARMASM
1298
        GMULT(counter, sm4->gcm.H);
1299
#endif
1300
0
    }
1301
1302
    /* Calculate GHASH on additional authentication data and cipher text. */
1303
0
#ifndef WOLFSSL_ARMASM
1304
0
    GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, sizeof(calcTag));
1305
#else
1306
    GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, SM4_BLOCK_SIZE);
1307
    GMULT(calcTag, sm4->gcm.H);
1308
#endif
1309
    /* Encrypt the initial counter. */
1310
0
    sm4_encrypt(sm4->ks, counter, scratch);
1311
    /* XOR the encrypted initial counter into calculated tag. */
1312
0
    xorbuf(calcTag, scratch, sizeof(calcTag));
1313
#ifdef WC_SM4_GCM_DEC_AUTH_EARLY
1314
    /* Compare tag and calculated tag in constant time. */
1315
    res = ConstantCompare(tag, calcTag, tagSz);
1316
    /* Create mask based on comparison result in constant time */
1317
    res = 0 - (sword32)(((word32)(0 - res)) >> 31U);
1318
    /* Mask error code to get return value. */
1319
    ret = res & SM4_GCM_AUTH_E;
1320
    /* Decrypt data when no error. */
1321
    if (ret == 0)
1322
#endif
1323
0
    {
1324
0
    #if defined(WOLFSSL_SM4_ECB)
1325
0
        if ((in != p) && (blocks > 0)) {
1326
            /* Set the counters for a multiple of block size into the output. */
1327
0
            while (blocks--) {
1328
                /* Increment last 4 bytes of big-endian counter. */
1329
0
                sm4_increment_gcm_counter(counter);
1330
                /* Copy into output. */
1331
0
                XMEMCPY(p, counter, SM4_BLOCK_SIZE);
1332
                /* Move output position past this block. */
1333
0
                p += SM4_BLOCK_SIZE;
1334
0
            }
1335
1336
            /* Reset number of blocks. */
1337
0
            blocks = sz / SM4_BLOCK_SIZE;
1338
            /* Encrypt the counters. */
1339
0
            wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks);
1340
            /* XOR in the plaintext to create cipher text. */
1341
0
            xorbuf(out, in, SM4_BLOCK_SIZE * blocks);
1342
            /* Step over handled plaintext */
1343
0
            in += SM4_BLOCK_SIZE * blocks;
1344
0
        }
1345
0
        else
1346
0
    #endif /* WOLFSSL_SM4_ECB */
1347
0
        {
1348
0
            while (blocks--) {
1349
                /* Increment last 4 bytes of big-endian counter. */
1350
0
                sm4_increment_gcm_counter(counter);
1351
                /* Encrypt the counter into scratch. */
1352
0
                sm4_encrypt(sm4->ks, counter, scratch);
1353
                /* XOR encryted counter with cipher text into output. */
1354
0
                xorbufout(p, scratch, in, SM4_BLOCK_SIZE);
1355
                /* Move plaintext and cipher text position past this block. */
1356
0
                p += SM4_BLOCK_SIZE;
1357
0
                in += SM4_BLOCK_SIZE;
1358
0
            }
1359
0
        }
1360
1361
0
        if (partial != 0) {
1362
            /* Increment last 4 bytes of big-endian counter. */
1363
0
            sm4_increment_gcm_counter(counter);
1364
            /* Encrypt the last counter. */
1365
0
            sm4_encrypt(sm4->ks, counter, counter);
1366
            /* XOR encryted counter with partial block cipher text into output.
1367
             */
1368
0
            xorbufout(p, counter, in, partial);
1369
0
        }
1370
1371
0
    #ifndef WC_SM4_GCM_DEC_AUTH_EARLY
1372
        /* Compare tag and calculated tag in constant time. */
1373
0
        res = ConstantCompare(tag, calcTag, (int)tagSz);
1374
        /* Create mask based on comparison result in constant time */
1375
0
        res = 0 - (sword32)(((word32)(0 - res)) >> 31U);
1376
        /* Mask error code to get return value. */
1377
0
        ret = res & SM4_GCM_AUTH_E;
1378
0
    #endif
1379
0
    }
1380
0
    return ret;
1381
0
}
1382
1383
/* Set the SM4-GCM key.
1384
 *
1385
 * Calculates key based table here.
1386
 *
1387
 * @param [in, out] sm4  SM4 algorithm object.
1388
 * @param [in]      key  Array of bytes representing key.
1389
 * @param [in]      len  Length of key. Must be SM4_KEY_SIZE.
1390
 * @return  0 on success.
1391
 * @return  BAD_FUNC_ARG when sm4 or key is NULL.
1392
 * @return  BAD_FUNC_ARG when len is not SM4_KEY_SIZE.
1393
 */
1394
int wc_Sm4GcmSetKey(wc_Sm4* sm4, const byte* key, word32 len)
1395
0
{
1396
0
    int ret = 0;
1397
0
    byte iv[SM4_BLOCK_SIZE];
1398
1399
    /* Validate parameters. */
1400
0
    if ((sm4 == NULL) || (key == NULL) || (len != SM4_KEY_SIZE)) {
1401
0
        ret = BAD_FUNC_ARG;
1402
0
    }
1403
1404
0
    if (ret == 0) {
1405
        /* Set key. */
1406
0
        sm4_set_key(sm4, key);
1407
        /* Reset IV to all zeros. */
1408
0
        XMEMSET(iv, 0, sizeof(iv));
1409
        /* Set IV. */
1410
0
        sm4_set_iv(sm4, iv);
1411
        /* Calculate H for GMAC operation */
1412
0
        sm4_gcm_calc_h(sm4, iv);
1413
0
    }
1414
1415
0
    return ret;
1416
0
}
1417
1418
/* Encrypt bytes using SM4-GCM.
1419
 *
1420
 * Assumes out is at least sz bytes long.
1421
 *
1422
 * @param [in]  sm4      SM4 algorithm object.
1423
 * @param [out] out      Byte array in which to place encrypted data.
1424
 * @param [in]  in       Array of bytes to encrypt.
1425
 * @param [in]  sz       Number of bytes to encrypt.
1426
 * @param [in]  nonce    Array of bytes holding initialization vector.
1427
 * @param [in]  nonceSz  Length of nonce in bytes.
1428
 * @param [out] tag      Authentication tag calculated using GCM.
1429
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1430
 *                       Must be no more than SM4_BLOCK_SIZE.
1431
 * @param [in]  aad      Additional authentication data. May be NULL.
1432
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1433
 * @return  0 on success.
1434
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1435
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1436
 *          WOLFSSL_MIN_AUTH_TAG_SZ or is more than SM4_BLOCK_SIZE.
1437
 * @return  BAD_FUNC_ARG when nonce length is 0.
1438
 * @return  MISSING_KEY when a key has not been set.
1439
 */
1440
int wc_Sm4GcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1441
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1442
    word32 aadSz)
1443
0
{
1444
0
    int ret = 0;
1445
1446
    /* Validate parameters. */
1447
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1448
0
            (nonce == NULL) || (tag == NULL)) {
1449
0
        ret = BAD_FUNC_ARG;
1450
0
    }
1451
0
    if ((tagSz < WOLFSSL_MIN_AUTH_TAG_SZ) || (tagSz > SM4_BLOCK_SIZE)) {
1452
0
        ret = BAD_FUNC_ARG;
1453
0
    }
1454
0
    if (nonceSz == 0) {
1455
0
        ret = BAD_FUNC_ARG;
1456
0
    }
1457
1458
    /* Ensure a key has been set. */
1459
0
    if ((ret == 0) && (!sm4->keySet)) {
1460
0
        ret = MISSING_KEY;
1461
0
    }
1462
1463
0
    if (ret == 0) {
1464
    #ifdef OPENSSL_EXTRA
1465
        sm4->nonceSz = (int)nonceSz;
1466
    #endif
1467
        /* Perform encryption using C implementation. */
1468
0
        sm4_gcm_encrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz, aad,
1469
0
            aadSz);
1470
0
    }
1471
1472
0
    return ret;
1473
0
}
1474
1475
/* Decrypt bytes using SM4-GCM.
1476
 *
1477
 * Assumes out is at least sz bytes long.
1478
 *
1479
 * @param [in]  sm4      SM4 algorithm object.
1480
 * @param [out] out      Byte array in which to place decrypted data.
1481
 * @param [in]  in       Array of bytes to decrypt.
1482
 * @param [in]  sz       Number of bytes to decrypt.
1483
 * @param [in]  nonce    Array of bytes holding initialization vector.
1484
 * @param [in]  nonceSz  Length of nonce in bytes.
1485
 * @param [in]  tag      Authentication tag to compare against calculated.
1486
 * @param [in]  tagSz    Length of authentication tag in bytes.
1487
 *                       Must be no more than SM4_BLOCK_SIZE.
1488
 * @param [in]  aad      Additional authentication data. May be NULL.
1489
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1490
 * @return  0 on success.
1491
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1492
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1493
 *          WOLFSSL_MIN_AUTH_TAG_SZ or is more than SM4_BLOCK_SIZE.
1494
 * @return  BAD_FUNC_ARG when nonce length is 0.
1495
 * @return  MISSING_KEY when a key has not been set.
1496
 * @return  SM4_GCM_AUTH_E when authentication tag calculated does not match
1497
 *          the one passed in.
1498
 */
1499
int wc_Sm4GcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1500
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1501
    const byte* aad, word32 aadSz)
1502
0
{
1503
0
    int ret = 0;
1504
1505
    /* Validate parameters. */
1506
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1507
0
            (nonce == NULL) || (tag == NULL)) {
1508
0
        ret = BAD_FUNC_ARG;
1509
0
    }
1510
0
    if ((tagSz < WOLFSSL_MIN_AUTH_TAG_SZ) || (tagSz > SM4_BLOCK_SIZE)) {
1511
0
        ret = BAD_FUNC_ARG;
1512
0
    }
1513
0
    if (nonceSz == 0) {
1514
0
        ret = BAD_FUNC_ARG;
1515
0
    }
1516
1517
    /* Ensure a key has been set. */
1518
0
    if ((ret == 0) && (!sm4->keySet)) {
1519
0
        ret = MISSING_KEY;
1520
0
    }
1521
1522
0
    if (ret == 0) {
1523
    #ifdef OPENSSL_EXTRA
1524
        sm4->nonceSz = (int)nonceSz;
1525
    #endif
1526
        /* Perform decryption using C implementation. */
1527
0
        ret = sm4_gcm_decrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz,
1528
0
            aad, aadSz);
1529
0
    }
1530
1531
0
    return ret;
1532
0
}
1533
1534
#endif /* WOLFSSL_SM4_GCM */
1535
1536
#ifdef WOLFSSL_SM4_CCM
1537
1538
/* Roll up data.
1539
 *
1540
 * Encrypt each block XORed into out.
1541
 *
1542
 * @param [in]      sm4  SM4 algorithm object.
1543
 * @param [in]      in   Data to roll up.
1544
 * @param [in]      sz   Length in bytes of data.
1545
 * @param [in, out] out  Block XORed into and encrypted.
1546
 */
1547
static void sm4_ccm_roll_x(wc_Sm4* sm4, const byte* in, word32 sz, byte* out)
1548
0
{
1549
    /* XOR in each block and encrypt each result. */
1550
0
    while (sz >= SM4_BLOCK_SIZE) {
1551
        /* XOR in next block. */
1552
0
        xorbuf(out, in, SM4_BLOCK_SIZE);
1553
        /* Move on past block. */
1554
0
        in += SM4_BLOCK_SIZE;
1555
0
        sz -= SM4_BLOCK_SIZE;
1556
        /* Encrypt into self. */
1557
0
        sm4_encrypt(sm4->ks, out, out);
1558
0
    }
1559
1560
    /* XOR in a block of data and encrypt result. */
1561
0
    if (sz > 0) {
1562
        /* XOR in partial block. */
1563
0
        xorbuf(out, in, sz);
1564
        /* Encrypt into self. */
1565
0
        sm4_encrypt(sm4->ks, out, out);
1566
0
    }
1567
0
}
1568
1569
/* Roll up additional authentication data (AAD).
1570
 *
1571
 * First block has length plus ant AAD XORed in before being encrypted.
1572
 *
1573
 * @param [in]  sm4  SM4 algorithm object.
1574
 * @param [in]  in   Additional authentication data to roll up.
1575
 * @param [in]  sz   Length in bytes of data.
1576
 * @param [out] out  Block XORed into and encrypted.
1577
 */
1578
static void sm4_ccm_roll_aad(wc_Sm4* sm4, const byte* in, word32 sz, byte* out)
1579
0
{
1580
0
    word32 aadLenSz;
1581
0
    word32 remainder;
1582
1583
    /* XOR length at start of block. */
1584
0
    if (sz <= 0xFEFF) {
1585
        /* Two bytes used to represent length. */
1586
0
        aadLenSz = 2;
1587
0
        out[0] ^= ((sz & 0xFF00) >> 8);
1588
0
        out[1] ^=  (sz & 0x00FF);
1589
0
    }
1590
0
    else {
1591
        /* Four bytes used to represent length plus two unique bytes. */
1592
0
        aadLenSz = 6;
1593
0
        out[0] ^= 0xFF;
1594
0
        out[1] ^= 0xFE;
1595
0
        out[2] ^= (byte)((sz & 0xFF000000) >> 24);
1596
0
        out[3] ^= (byte)((sz & 0x00FF0000) >> 16);
1597
0
        out[4] ^= (byte)((sz & 0x0000FF00) >>  8);
1598
0
        out[5] ^= (byte) (sz & 0x000000FF);
1599
0
    }
1600
1601
    /* Calculate number of input bytes required to make up the block. */
1602
0
    remainder = SM4_BLOCK_SIZE - aadLenSz;
1603
    /* Check how much AAD available. */
1604
0
    if (sz >= remainder) {
1605
        /* XOR up to block into out. */
1606
0
        xorbuf(out + aadLenSz, in, remainder);
1607
        /* Move past data. */
1608
0
        sz -= remainder;
1609
0
        in += remainder;
1610
0
    }
1611
0
    else {
1612
        /* XOR in AAD available. */
1613
0
        xorbuf(out + aadLenSz, in, sz);
1614
        /* All AAD used. */
1615
0
        sz = 0;
1616
0
    }
1617
    /* Encrypt into self. */
1618
0
    sm4_encrypt(sm4->ks, out, out);
1619
1620
0
    if (sz > 0) {
1621
        /* Roll up any remaining AAD. */
1622
0
        sm4_ccm_roll_x(sm4, in, sz, out);
1623
0
    }
1624
0
}
1625
1626
/* Last bytes incremented as a big-endian number.
1627
 *
1628
 * Bytes not the nonce and length are incremented.
1629
 *
1630
 * @param [in, out] b      IV block.
1631
 * @param [in]      ctrSz  Length of counter.
1632
 */
1633
static WC_INLINE void sm4_ccm_ctr_inc(byte* b, word32 ctrSz)
1634
0
{
1635
0
    word32 i;
1636
1637
    /* Only last bytes that make up counter. */
1638
0
    for (i = 0; i < ctrSz; i++) {
1639
        /* Increment byte and check for carry. */
1640
0
        if ((++b[SM4_BLOCK_SIZE - 1 - i]) != 0) {
1641
            /* No carry - done. */
1642
0
            break;
1643
0
        }
1644
0
    }
1645
0
}
1646
1647
/* Encipher bytes using SM4-CCM.
1648
 *
1649
 * @param [in]       sm4    SM4 algorithm object.
1650
 * @param [out]      out    Byte array in which to place encrypted data.
1651
 * @param [in]       in     Array of bytes to encrypt.
1652
 * @param [in]       sz     Number of bytes to encrypt.
1653
 * @param [in, out]  b      IV block.
1654
 * @param [in]       ctrSz  Number of counter bytes in IV block.
1655
 */
1656
static WC_INLINE void sm4_ccm_crypt(wc_Sm4* sm4, byte* out, const byte* in,
1657
    word32 sz, byte* b, byte ctrSz)
1658
0
{
1659
0
    ALIGN16 byte a[SM4_BLOCK_SIZE];
1660
1661
    /* Nonce and length have been set and counter 0 except for last byte. */
1662
1663
    /* Set counter to 1. */
1664
0
    b[SM4_BLOCK_SIZE - 1] = 1;
1665
    /* Encrypting full blocks at a time. */
1666
0
    while (sz >= SM4_BLOCK_SIZE) {
1667
        /* Encrypt counter. */
1668
0
        sm4_encrypt(sm4->ks, b, a);
1669
        /* XOR in plaintext. */
1670
0
        xorbuf(a, in, SM4_BLOCK_SIZE);
1671
        /* Copy cipher text out. */
1672
0
        XMEMCPY(out, a, SM4_BLOCK_SIZE);
1673
1674
        /* Increment counter for next block. */
1675
0
        sm4_ccm_ctr_inc(b, ctrSz);
1676
        /* Move over block. */
1677
0
        sz -= SM4_BLOCK_SIZE;
1678
0
        in += SM4_BLOCK_SIZE;
1679
0
        out += SM4_BLOCK_SIZE;
1680
0
    }
1681
0
    if (sz > 0) {
1682
        /* Encrypt counter. */
1683
0
        sm4_encrypt(sm4->ks, b, a);
1684
        /* XOR in remaining plaintext. */
1685
0
        xorbuf(a, in, sz);
1686
        /* Copy cipher text out. */
1687
0
        XMEMCPY(out, a, sz);
1688
0
    }
1689
0
}
1690
1691
/* Calculate authentication tag for SM4-CCM.
1692
 *
1693
 * @param [in]       sm4    SM4 algorithm object.
1694
 * @param [in]       plain  Array of bytes to encrypt.
1695
 * @param [in]       sz     Number of bytes to encrypt.
1696
 * @param [in]       aad    Additional authentication data. May be NULL.
1697
 * @param [in]       aadSz  Length of additional authentication data in bytes.
1698
 * @param [in, out]  b      IV block.
1699
 * @param [in]       ctrSz  Number of counter bytes in IV block.
1700
 * @param [out]      tag    Authentication tag calculated using CCM.
1701
 * @param [in]       tagSz  Length of authentication tag to calculate in bytes.
1702
 */
1703
static WC_INLINE void sm4_ccm_calc_auth_tag(wc_Sm4* sm4, const byte* plain,
1704
    word32 sz, const byte* aad, word32 aadSz, byte* b, byte ctrSz,
1705
    byte* tag, word32 tagSz)
1706
0
{
1707
0
    ALIGN16 byte a[SM4_BLOCK_SIZE];
1708
0
    byte t[SM4_BLOCK_SIZE];
1709
0
    word32 i;
1710
1711
    /* Nonce is in place. */
1712
1713
    /* Set first byte to length and flags. */
1714
0
    b[0] = (byte)((((aad != NULL) && (aadSz > 0)) ? 0x40 : 0x00) +
1715
0
                  (8 * (((byte)tagSz - 2) / 2)) + (ctrSz - 1));
1716
    /* Set the counter bytes to length of data - 4 bytes of length only. */
1717
0
    for (i = 0; i < ctrSz && i < sizeof(word32); i++) {
1718
0
        b[SM4_BLOCK_SIZE - 1 - i] = (byte)(sz >> (8 * i));
1719
0
    }
1720
    /* Set remaining counter bytes to 0. */
1721
0
    for (; i < ctrSz; i++) {
1722
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0x00;
1723
0
    }
1724
    /* Encrypt block into authentication tag block. */
1725
0
    sm4_encrypt(sm4->ks, b, a);
1726
1727
0
    if ((aad != NULL) && (aadSz > 0)) {
1728
        /* Roll up any AAD. */
1729
0
        sm4_ccm_roll_aad(sm4, aad, aadSz, a);
1730
0
    }
1731
0
    if (sz > 0) {
1732
        /* Roll up any plaintext. */
1733
0
        sm4_ccm_roll_x(sm4, plain, sz, a);
1734
0
    }
1735
1736
    /* Nonce remains in place. */
1737
    /* Set first byte to counter size - 1. */
1738
0
    b[0] = ctrSz - 1;
1739
    /* Set counter to 0. */
1740
0
    for (i = 0; i < ctrSz; i++) {
1741
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0;
1742
0
    }
1743
    /* Encrypt block into authentication tag block. */
1744
0
    sm4_encrypt(sm4->ks, b, t);
1745
    /* XOR in other authentication tag data. */
1746
0
    xorbufout(tag, t, a, tagSz);
1747
0
}
1748
1749
/* Encrypt bytes using SM4-CCM implementation in C.
1750
 *
1751
 * @param [in]  sm4      SM4 algorithm object.
1752
 * @param [out] out      Byte array in which to place encrypted data.
1753
 * @param [in]  in       Array of bytes to encrypt.
1754
 * @param [in]  sz       Number of bytes to encrypt.
1755
 * @param [in]  nonce    Array of bytes holding initialization vector.
1756
 * @param [in]  nonceSz  Length of nonce in bytes.
1757
 * @param [out] tag      Authentication tag calculated using CCM.
1758
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1759
 *                       Must be no more than SM4_BLOCK_SIZE.
1760
 * @param [in]  aad      Additional authentication data. May be NULL.
1761
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1762
 */
1763
static void sm4_ccm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1764
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1765
    word32 aadSz)
1766
0
{
1767
0
    ALIGN16 byte b[SM4_BLOCK_SIZE];
1768
0
    byte ctrSz;
1769
1770
    /* Calculate length of counter. */
1771
0
    ctrSz = SM4_BLOCK_SIZE - 1 - (byte)nonceSz;
1772
    /* Copy nonce in after length byte. */
1773
0
    XMEMCPY(b + 1, nonce, nonceSz);
1774
1775
    /* Calculate authentication tag. */
1776
0
    sm4_ccm_calc_auth_tag(sm4, in, sz, aad, aadSz, b, ctrSz, tag, tagSz);
1777
    /* b is left with first byte counter size - 1 and counter part set to zero.
1778
     */
1779
1780
0
    if (sz > 0) {
1781
        /* Encrypt plaintext to cipher text. */
1782
0
        sm4_ccm_crypt(sm4, out, in, sz, b, ctrSz);
1783
0
    }
1784
0
}
1785
1786
/* Decrypt bytes using SM4-CCM implementation in C.
1787
 *
1788
 * @param [in]  sm4      SM4 algorithm object.
1789
 * @param [out] out      Byte array in which to place decrypted data.
1790
 * @param [in]  in       Array of bytes to decrypt.
1791
 * @param [in]  sz       Number of bytes to decrypt.
1792
 * @param [in]  nonce    Array of bytes holding initialization vector.
1793
 * @param [in]  nonceSz  Length of nonce in bytes.
1794
 * @param [in]  tag      Authentication tag calculated using GCM.
1795
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1796
 *                       Must be no more than SM4_BLOCK_SIZE.
1797
 * @param [in]  aad      Additional authentication data. May be NULL.
1798
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1799
 * @return  0 on success.
1800
 * @return  SM4_CCM_AUTH_E when authentication tag calculated does not match
1801
 *          the one passed in.
1802
 */
1803
static int sm4_ccm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1804
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1805
    const byte* aad, word32 aadSz)
1806
0
{
1807
0
    ALIGN16 byte b[SM4_BLOCK_SIZE];
1808
0
    ALIGN16 byte t[SM4_BLOCK_SIZE];
1809
0
    byte ctrSz;
1810
0
    word32 i;
1811
0
    int ret = 0;
1812
1813
    /* Calculate length of counter. */
1814
0
    ctrSz = SM4_BLOCK_SIZE - 1 - (byte)nonceSz;
1815
    /* Copy nonce in after length byte. */
1816
0
    XMEMCPY(b + 1, nonce, nonceSz);
1817
1818
    /* Set length byte to counter size - 1. */
1819
0
    b[0] = ctrSz - 1;
1820
    /* Set all bytes but least significant of counter to 0. */
1821
0
    for (i = 1; i < ctrSz; i++) {
1822
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0;
1823
0
    }
1824
0
    if (sz > 0) {
1825
        /* Decrypt cipher text to plaintext. */
1826
0
        sm4_ccm_crypt(sm4, out, in, sz, b, ctrSz);
1827
        /* b still has nonce in place. */
1828
0
    }
1829
1830
    /* Calculate authentication tag. */
1831
0
    sm4_ccm_calc_auth_tag(sm4, out, sz, aad, aadSz, b, ctrSz, t, tagSz);
1832
1833
    /* Compare calculated tag with passed in tag. */
1834
0
    if (ConstantCompare(t, tag, (int)tagSz) != 0) {
1835
        /* Set CCM authentication error return. */
1836
0
        ret = SM4_CCM_AUTH_E;
1837
0
    }
1838
1839
0
    return ret;
1840
0
}
1841
1842
/* Encrypt bytes using SM4-CCM.
1843
 *
1844
 * Assumes out is at least sz bytes long.
1845
 *
1846
 * @param [in]  sm4      SM4 algorithm object.
1847
 * @param [out] out      Byte array in which to place encrypted data.
1848
 * @param [in]  in       Array of bytes to encrypt.
1849
 * @param [in]  sz       Number of bytes to encrypt.
1850
 * @param [in]  nonce    Array of bytes holding initialization vector.
1851
 * @param [in]  nonceSz  Length of nonce in bytes.
1852
 * @param [out] tag      Authentication tag calculated using CCM.
1853
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1854
 *                       Must be no more than SM4_BLOCK_SIZE.
1855
 * @param [in]  aad      Additional authentication data. May be NULL.
1856
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1857
 * @return  0 on success.
1858
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1859
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1860
 *          4 or is more than SM4_BLOCK_SIZE or an odd value.
1861
 * @return  BAD_FUNC_ARG when nonce length is less than CCM_NONCE_MIN_SZ or
1862
 *          greater than CCM_NONCE_MAX_SZ.
1863
 * @return  MISSING_KEY when a key has not been set.
1864
 */
1865
int wc_Sm4CcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1866
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1867
    word32 aadSz)
1868
0
{
1869
0
    int ret = 0;
1870
1871
    /* Validate parameters. */
1872
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1873
0
            (nonce == NULL) || (tag == NULL)) {
1874
0
        ret = BAD_FUNC_ARG;
1875
0
    }
1876
    /* Tag size is even number 4..16. */
1877
0
    if ((tagSz < 4) || (tagSz > SM4_BLOCK_SIZE) || ((tagSz & 1) == 1)) {
1878
0
        ret = BAD_FUNC_ARG;
1879
0
    }
1880
    /* Nonce must be within supported range. */
1881
0
    if ((nonceSz < CCM_NONCE_MIN_SZ) || (nonceSz > CCM_NONCE_MAX_SZ)) {
1882
0
        ret = BAD_FUNC_ARG;
1883
0
    }
1884
1885
    /* Ensure a key has been set. */
1886
0
    if ((ret == 0) && (!sm4->keySet)) {
1887
0
        ret = MISSING_KEY;
1888
0
    }
1889
1890
0
    if (ret == 0) {
1891
    #ifdef OPENSSL_EXTRA
1892
        sm4->nonceSz = (int)nonceSz;
1893
    #endif
1894
        /* Perform encryption using C implementation. */
1895
0
        sm4_ccm_encrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz, aad,
1896
0
            aadSz);
1897
0
    }
1898
1899
0
    return ret;
1900
0
}
1901
1902
/* Decrypt bytes using SM4-CCM.
1903
 *
1904
 * Assumes out is at least sz bytes long.
1905
 *
1906
 * @param [in]  sm4      SM4 algorithm object.
1907
 * @param [out] out      Byte array in which to place decrypted data.
1908
 * @param [in]  in       Array of bytes to decrypt.
1909
 * @param [in]  sz       Number of bytes to decrypt.
1910
 * @param [in]  nonce    Array of bytes holding initialization vector.
1911
 * @param [in]  nonceSz  Length of nonce in bytes.
1912
 * @param [in]  tag      Authentication tag to compare against calculated.
1913
 * @param [in]  tagSz    Length of authentication tag in bytes.
1914
 *                       Must be no more than SM4_BLOCK_SIZE.
1915
 * @param [in]  aad      Additional authentication data. May be NULL.
1916
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1917
 * @return  0 on success.
1918
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1919
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1920
 *          4 or is more than SM4_BLOCK_SIZE or an odd value.
1921
 * @return  BAD_FUNC_ARG when nonce length is less than CCM_NONCE_MIN_SZ or
1922
 *          greater than CCM_NONCE_MAX_SZ.
1923
 * @return  MISSING_KEY when a key has not been set.
1924
 * @return  SM4_CCM_AUTH_E when authentication tag calculated does not match
1925
 *          the one passed in.
1926
 */
1927
int wc_Sm4CcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1928
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1929
    const byte* aad, word32 aadSz)
1930
0
{
1931
0
    int ret = 0;
1932
1933
    /* Validate parameters. */
1934
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1935
0
            (nonce == NULL) || (tag == NULL)) {
1936
0
        ret = BAD_FUNC_ARG;
1937
0
    }
1938
    /* Tag size is even number 4..16. */
1939
0
    if ((tagSz < 4) || (tagSz > SM4_BLOCK_SIZE) || ((tagSz & 1) == 1)) {
1940
0
        ret = BAD_FUNC_ARG;
1941
0
    }
1942
    /* Nonce must be within supported range. */
1943
0
    if ((nonceSz < CCM_NONCE_MIN_SZ) || (nonceSz > CCM_NONCE_MAX_SZ)) {
1944
0
        ret = BAD_FUNC_ARG;
1945
0
    }
1946
1947
    /* Ensure a key has been set. */
1948
0
    if ((ret == 0) && (!sm4->keySet)) {
1949
0
        ret = MISSING_KEY;
1950
0
    }
1951
1952
0
    if (ret == 0) {
1953
    #ifdef OPENSSL_EXTRA
1954
        sm4->nonceSz = (int)nonceSz;
1955
    #endif
1956
        /* Perform decryption using C implementation. */
1957
0
        ret = sm4_ccm_decrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz,
1958
0
            aad, aadSz);
1959
0
    }
1960
1961
0
    return ret;
1962
0
}
1963
1964
#endif
1965
1966
#endif /* WOLFSSL_SM4 */
1967