Coverage Report

Created: 2026-08-15 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-heapmath/wolfcrypt/src/sm4.c
Line
Count
Source
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
    /* Round-key material must not be left on the stack. */
461
0
    ForceZero(k, sizeof(k));
462
0
    ForceZero(&t, sizeof(t));
463
0
    ForceZero(&x, sizeof(x));
464
#else
465
    word32* ck = sm4_ck;
466
467
    __asm__ volatile (
468
        "LD1  {v0.16b}, [%[key]]\n\t"
469
        "LD1  {v9.16b}, [%[fk]]\n\t"
470
        "REV32  v0.16B, v0.16B\n\t"
471
        "LD1  {v1.4S-v4.4S}, [%[ck]], #64\n\t"
472
        "EOR  v0.16B, v0.16B, v9.16B\n\t"
473
        "LD1  {v5.4S-v8.4S}, [%[ck]]\n\t"
474
475
        "SM4EKEY  v1.4S, v0.4S, v1.4S\n\t"
476
        "SM4EKEY  v2.4S, v1.4S, v2.4S\n\t"
477
        "SM4EKEY  v3.4S, v2.4S, v3.4S\n\t"
478
        "SM4EKEY  v4.4S, v3.4S, v4.4S\n\t"
479
        "SM4EKEY  v5.4S, v4.4S, v5.4S\n\t"
480
        "SM4EKEY  v6.4S, v5.4S, v6.4S\n\t"
481
        "SM4EKEY  v7.4S, v6.4S, v7.4S\n\t"
482
        "SM4EKEY  v8.4S, v7.4S, v8.4S\n\t"
483
484
        "ST4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
485
        "ST4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
486
        "ST4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
487
        "ST4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
488
        "ST4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
489
        "ST4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
490
        "ST4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
491
        "ST4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
492
        : [ks] "+r" (ks), [ck] "+r" (ck)
493
        : [key] "r" (key), [fk] "r" (sm4_fk)
494
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8",
495
          "v9"
496
    );
497
#endif
498
0
}
499
500
/* Round operation.
501
 *
502
 * Assumes x0, x1, x2, x3 are the current state.
503
 * Assumes ks is the key schedule.
504
 *
505
 * @param [in] k0  Index into key schedule for first word.
506
 * @param [in] k1  Index into key schedule for second word.
507
 * @param [in] k2  Index into key schedule for third word.
508
 * @param [in] k3  Index into key schedule for fourth word.
509
 */
510
#define SM4_ROUNDS(k0, k1, k2, k3)          \
511
0
        x0 ^= sm4_t(x1 ^ x2 ^ x3 ^ ks[k0]); \
512
0
        x1 ^= sm4_t(x0 ^ x2 ^ x3 ^ ks[k1]); \
513
0
        x2 ^= sm4_t(x0 ^ x1 ^ x3 ^ ks[k2]); \
514
0
        x3 ^= sm4_t(x0 ^ x1 ^ x2 ^ ks[k3])
515
516
/* Encrypt a block of data using SM4 algorithm.
517
 *
518
 * @param [in]  ks   Key schedule.
519
 * @param [in]  in   Block to encrypt.
520
 * @param [out] out  Encrypted block.
521
 */
522
static void sm4_encrypt(const word32* ks, const byte* in, byte* out)
523
0
{
524
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
525
0
    word32 x0, x1, x2, x3;
526
    /* Load block. */
527
0
    LOAD_U32_BE(in, x0, x1, x2, x3);
528
529
    /* Encrypt block. */
530
0
    SM4_ROUNDS( 0,  1,  2,  3);
531
0
    SM4_ROUNDS( 4,  5,  6,  7);
532
0
    SM4_ROUNDS( 8,  9, 10, 11);
533
0
    SM4_ROUNDS(12, 13, 14, 15);
534
0
    SM4_ROUNDS(16, 17, 18, 19);
535
0
    SM4_ROUNDS(20, 21, 22, 23);
536
0
    SM4_ROUNDS(24, 25, 26, 27);
537
0
    SM4_ROUNDS(28, 29, 30, 31);
538
539
    /* Store encrypted block. */
540
0
    STORE_U32_BE(x0, x1, x2, x3, out);
541
#else
542
    __asm__ volatile (
543
        "LD1  {v0.16b}, [%[in]]\n\t"
544
        "LD4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
545
        "LD4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
546
        "LD4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
547
        "LD4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
548
        "REV32  v0.16B, v0.16B\n\t"
549
        "LD4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
550
        "LD4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
551
        "LD4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
552
        "LD4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
553
554
        "SM4E v0.4S, v1.4S\n\t"
555
        "SM4E v0.4S, v2.4S\n\t"
556
        "SM4E v0.4S, v3.4S\n\t"
557
        "SM4E v0.4S, v4.4S\n\t"
558
        "SM4E v0.4S, v5.4S\n\t"
559
        "SM4E v0.4S, v6.4S\n\t"
560
        "SM4E v0.4S, v7.4S\n\t"
561
        "SM4E v0.4S, v8.4S\n\t"
562
563
        "REV64  v0.16B, v0.16B\n\t"
564
        "EXT  v0.16B, v0.16B, v0.16B, #8\n\t"
565
        "ST1  {v0.16b}, [%[out]]\n\t"
566
567
        : [ks] "+r" (ks), [out] "+r" (out)
568
        : [in] "r" (in)
569
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"
570
    );
571
#endif
572
0
}
573
574
#if defined(WOLFSSL_SM4_ECB) || defined(WOLFSSL_SM4_CBC)
575
/* Decrypt a block of data using SM4 algorithm.
576
 *
577
 * @param [in]  ks   Key schedule.
578
 * @param [in]  in   Block to decrypt.
579
 * @param [out] out  Decrypted block.
580
 */
581
static void sm4_decrypt(const word32* ks, const byte* in, byte* out)
582
0
{
583
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM_CRYPTO_SM4)
584
0
    word32 x0, x1, x2, x3;
585
586
    /* Load block. */
587
0
    LOAD_U32_BE(in, x0, x1, x2, x3);
588
589
    /* Decrypt block. */
590
0
    SM4_ROUNDS(31, 30, 29, 28);
591
0
    SM4_ROUNDS(27, 26, 25, 24);
592
0
    SM4_ROUNDS(23, 22, 21, 20);
593
0
    SM4_ROUNDS(19, 18, 17, 16);
594
0
    SM4_ROUNDS(15, 14, 13, 12);
595
0
    SM4_ROUNDS(11, 10,  9,  8);
596
0
    SM4_ROUNDS( 7,  6,  5,  4);
597
0
    SM4_ROUNDS( 3,  2,  1,  0);
598
599
    /* Store decrypted block. */
600
0
    STORE_U32_BE(x0, x1, x2, x3, out);
601
#else
602
    __asm__ volatile (
603
        "LD1  {v0.16b}, [%[in]]\n\t"
604
        "LD4  {v1.S-v4.S}[3], [%[ks]], #16\n\t"
605
        "LD4  {v5.S-v8.S}[3], [%[ks]], #16\n\t"
606
        "LD4  {v1.S-v4.S}[2], [%[ks]], #16\n\t"
607
        "LD4  {v5.S-v8.S}[2], [%[ks]], #16\n\t"
608
        "REV32  v0.16B, v0.16B\n\t"
609
        "LD4  {v1.S-v4.S}[1], [%[ks]], #16\n\t"
610
        "LD4  {v5.S-v8.S}[1], [%[ks]], #16\n\t"
611
        "LD4  {v1.S-v4.S}[0], [%[ks]], #16\n\t"
612
        "LD4  {v5.S-v8.S}[0], [%[ks]], #16\n\t"
613
614
        "SM4E v0.4S, v8.4S\n\t"
615
        "SM4E v0.4S, v7.4S\n\t"
616
        "SM4E v0.4S, v6.4S\n\t"
617
        "SM4E v0.4S, v5.4S\n\t"
618
        "SM4E v0.4S, v4.4S\n\t"
619
        "SM4E v0.4S, v3.4S\n\t"
620
        "SM4E v0.4S, v2.4S\n\t"
621
        "SM4E v0.4S, v1.4S\n\t"
622
623
        "REV64  v0.16B, v0.16B\n\t"
624
        "EXT  v0.16B, v0.16B, v0.16B, #8\n\t"
625
        "ST1  {v0.16b}, [%[out]]\n\t"
626
627
        : [ks] "+r" (ks)
628
        : [in] "r" (in), [out] "r" (out)
629
        : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"
630
    );
631
#endif
632
0
}
633
#endif
634
635
636
/* Initialize the SM4 algorithm object.
637
 *
638
 * @param [in, out] sm4    SM4 algorithm object.
639
 * @param [in]      heap   Heap hint for dynamic memory allocation.
640
 * @param [in]      devId  Device identifier.
641
 * @return  0 on success.
642
 * @return  BAD_FUNC_ARG when sm4 is NULL.
643
 */
644
int wc_Sm4Init(wc_Sm4* sm4, void* heap, int devId)
645
0
{
646
0
    int ret = 0;
647
648
    /* No device support yet. */
649
0
    (void)devId;
650
651
    /* Validate parameters. */
652
0
    if (sm4 == NULL) {
653
0
        ret = BAD_FUNC_ARG;
654
0
    }
655
656
0
    if (ret == 0) {
657
        /* Set all fields to zero including bit fields. */
658
0
        XMEMSET(sm4, 0, sizeof(*sm4));
659
660
        /* Cache heap hint to use with any dynamic allocations. */
661
0
        sm4->heap = heap;
662
0
    }
663
664
0
    return ret;
665
0
}
666
667
/* Dispose of SM4 algorithm object.
668
 *
669
 * Zeroize sensitive data in object.
670
 *
671
 * @param [in, out] sm4  SM4 algorithm object.
672
 */
673
void wc_Sm4Free(wc_Sm4* sm4)
674
0
{
675
    /* Check we have something to work with. */
676
0
    if (sm4 != NULL) {
677
        /* Must zeroize key schedule. */
678
0
        ForceZero(sm4->ks, sizeof(sm4->ks));
679
0
    #if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR)
680
        /* CTR keystream and CBC decrypt plaintext both land in tmp. */
681
0
        ForceZero(sm4->tmp, sizeof(sm4->tmp));
682
0
    #endif
683
0
    #ifdef WOLFSSL_SM4_GCM
684
        /* gcm.H is the GHASH subkey derived from the key. */
685
0
        ForceZero(&sm4->gcm, sizeof(sm4->gcm));
686
0
    #endif
687
0
    }
688
0
}
689
690
/* Set the key.
691
 *
692
 * @param [in, out] sm4  SM4 algorithm object.
693
 * @param [in]      key  Array of bytes representing key.
694
 */
695
static void sm4_set_key(wc_Sm4* sm4, const byte* key)
696
0
{
697
    /* Create key schedule. */
698
0
    sm4_key_schedule(key, sm4->ks);
699
    /* Mark key as having been set. */
700
0
    sm4->keySet = 1;
701
0
}
702
703
#if defined(WOLFSSL_SM4_ECB) || defined(WOLFSSL_SM4_CBC) || \
704
    defined(WOLFSSL_SM4_CTR) || defined(WOLFSSL_SM4_CCM)
705
/* Set the key.
706
 *
707
 * @param [in, out] sm4  SM4 algorithm object.
708
 * @param [in]      key  Array of bytes representing key.
709
 * @param [in]      len  Length of key. Must be SM4_KEY_SIZE.
710
 * @return  0 on success.
711
 * @return  BAD_FUNC_ARG when sm4 or key is NULL.
712
 * @return  BAD_FUNC_ARG when len is not SM4_KEY_SIZE.
713
 */
714
int wc_Sm4SetKey(wc_Sm4* sm4, const byte* key, word32 len)
715
0
{
716
0
    int ret = 0;
717
718
    /* Validate parameters. */
719
0
    if ((sm4 == NULL) || (key == NULL) || (len != SM4_KEY_SIZE)) {
720
0
        ret = BAD_FUNC_ARG;
721
0
    }
722
723
0
    if (ret == 0) {
724
0
        sm4_set_key(sm4, key);
725
0
    }
726
727
0
    return ret;
728
0
}
729
#endif
730
731
#if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR) || \
732
    defined(WOLFSSL_SM4_GCM)
733
/* Set the IV.
734
 *
735
 * @param [in, out] sm4  SM4 algorithm object.
736
 * @param [in]      iv   Array of bytes representing IV. May be NULL.
737
 */
738
static void sm4_set_iv(wc_Sm4* sm4, const byte* iv)
739
0
{
740
    /* Set IV. */
741
0
    XMEMCPY(sm4->iv, iv, SM4_IV_SIZE);
742
0
#ifdef WOLFSSL_SM4_CTR
743
    /* Unused count of encrypted counter for CTR mode. */
744
0
    sm4->unused = 0;
745
0
#endif
746
0
    sm4->ivSet = 1;
747
0
}
748
#endif
749
750
#if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR)
751
/* Set the IV.
752
 *
753
 * @param [in, out] sm4  SM4 algorithm object.
754
 * @param [in]      iv   Array of bytes representing IV. May be NULL.
755
 * @return  0 on success.
756
 * @return  BAD_FUNC_ARG when sm4 or iv is NULL.
757
 */
758
int wc_Sm4SetIV(wc_Sm4* sm4, const byte* iv)
759
0
{
760
0
    int ret = 0;
761
762
    /* Validate parameters. */
763
0
    if ((sm4 == NULL) || (iv == NULL)) {
764
0
        ret = BAD_FUNC_ARG;
765
0
    }
766
767
0
    if (ret == 0) {
768
0
        sm4_set_iv(sm4, iv);
769
0
    }
770
771
0
    return ret;
772
0
}
773
#endif
774
775
#ifdef WOLFSSL_SM4_ECB
776
777
/* Encrypt bytes using SM4-ECB.
778
 *
779
 * Length of input must be a multiple of the block size.
780
 * Assumes out is at least sz bytes long.
781
 *
782
 * @param [in]  sm4  SM4 algorithm object.
783
 * @param [out] out  Byte array in which to place encrypted data.
784
 * @param [in]  in   Array of bytes to encrypt.
785
 * @param [in]  sz   Number of bytes to encrypt.
786
 * @return  0 on success.
787
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
788
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
789
 * @return  MISSING_KEY when a key has not been set.
790
 */
791
int wc_Sm4EcbEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
792
0
{
793
0
    int ret = 0;
794
795
    /* Validate parameters. */
796
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
797
0
        ret = BAD_FUNC_ARG;
798
0
    }
799
    /* Can only work on multiples of block size of bytes. */
800
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
801
0
        ret = BAD_FUNC_ARG;
802
0
    }
803
804
    /* Ensure a key has been set. */
805
0
    if ((ret == 0) && (!sm4->keySet)) {
806
0
        ret = MISSING_KEY;
807
0
    }
808
809
0
    if (ret == 0) {
810
        /* Encrypt all bytes. */
811
0
        while (sz > 0) {
812
            /* Encrypt a block. */
813
0
            sm4_encrypt(sm4->ks, in, out);
814
            /* Move on to next block. */
815
0
            in += SM4_BLOCK_SIZE;
816
0
            out += SM4_BLOCK_SIZE;
817
0
            sz -= SM4_BLOCK_SIZE;
818
0
        }
819
0
    }
820
821
0
    return ret;
822
0
}
823
824
/* Decrypt bytes using SM4-ECB.
825
 *
826
 * Length of input must be a multiple of the block size.
827
 * Assumes out is at least sz bytes long.
828
 *
829
 * @param [in]  sm4  SM4 algorithm object.
830
 * @param [out] out  Byte array in which to place decrypted data.
831
 * @param [in]  in   Array of bytes to decrypt.
832
 * @param [in]  sz   Number of bytes to decrypt.
833
 * @return  0 on success.
834
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
835
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
836
 * @return  MISSING_KEY when a key has not been set.
837
 */
838
int wc_Sm4EcbDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
839
0
{
840
841
0
    int ret = 0;
842
843
    /* Validate parameters. */
844
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
845
0
        ret = BAD_FUNC_ARG;
846
0
    }
847
    /* Can only work on multiples of block size of bytes. */
848
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
849
0
        ret = BAD_FUNC_ARG;
850
0
    }
851
852
    /* Ensure a key has been set. */
853
0
    if ((ret == 0) && (!sm4->keySet)) {
854
0
        ret = MISSING_KEY;
855
0
    }
856
857
0
    if (ret == 0) {
858
       /* Decrypt all bytes. */
859
0
        while (sz > 0) {
860
            /* Decrypt a block. */
861
0
            sm4_decrypt(sm4->ks, in, out);
862
            /* Move on to next block. */
863
0
            in += SM4_BLOCK_SIZE;
864
0
            out += SM4_BLOCK_SIZE;
865
0
            sz -= SM4_BLOCK_SIZE;
866
0
        }
867
0
    }
868
869
0
    return ret;
870
0
}
871
872
#endif /* WOLFSSL_SM4_ECB */
873
874
#ifdef WOLFSSL_SM4_CBC
875
876
/* Encrypt bytes using SM4-CBC.
877
 *
878
 * Length of input must be a multiple of the block size.
879
 * Assumes out is at least sz bytes long.
880
 *
881
 * @param [in]  sm4  SM4 algorithm object.
882
 * @param [out] out  Byte array in which to place encrypted data.
883
 * @param [in]  in   Array of bytes to encrypt.
884
 * @param [in]  sz   Number of bytes to encrypt.
885
 * @return  0 on success.
886
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
887
 * @return  BAD_FUNC_ARG when sz is not a multiple of SM4_BLOCK_SIZE.
888
 * @return  MISSING_KEY when a key has not been set.
889
 * @return  MISSING_IV when an IV has not been set.
890
 */
891
int wc_Sm4CbcEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
892
0
{
893
0
    int ret = 0;
894
895
    /* Validate parameters. */
896
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
897
0
        ret = BAD_FUNC_ARG;
898
0
    }
899
    /* Can only work on multiples of block size of bytes. */
900
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
901
0
        ret = BAD_FUNC_ARG;
902
0
    }
903
904
    /* Ensure a key and IV have been set. */
905
0
    if ((ret == 0) && (!sm4->keySet)) {
906
0
        ret = MISSING_KEY;
907
0
    }
908
0
    if ((ret == 0) && (!sm4->ivSet)) {
909
0
        ret = MISSING_IV;
910
0
    }
911
912
0
    if (ret == 0) {
913
        /* Encrypt all bytes. */
914
0
        while (sz > 0) {
915
            /* XOR next block into IV. */
916
0
            xorbuf(sm4->iv, in, SM4_BLOCK_SIZE);
917
            /* Encrypt IV XORed with block. */
918
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->iv);
919
            /* Use output block as next IV. */
920
0
            XMEMCPY(out, sm4->iv, SM4_BLOCK_SIZE);
921
922
            /* Move on to next block. */
923
0
            in += SM4_BLOCK_SIZE;
924
0
            out += SM4_BLOCK_SIZE;
925
0
            sz -= SM4_BLOCK_SIZE;
926
0
        }
927
0
    }
928
929
0
    return ret;
930
0
}
931
932
/* Decrypt bytes using SM4-CBC.
933
 *
934
 * Length of input must be a multiple of the block size.
935
 * Assumes out is at least sz bytes long.
936
 *
937
 * @param [in]  sm4  SM4 algorithm object.
938
 * @param [out] out  Byte array in which to place decrypted data.
939
 * @param [in]  in   Array of bytes to decrypt.
940
 * @param [in]  sz   Number of bytes to decrypt.
941
 * @return  0 on success.
942
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
943
 * @return  MISSING_KEY when a key has not been set.
944
 * @return  MISSING_IV when an IV has not been set.
945
 */
946
int wc_Sm4CbcDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
947
0
{
948
0
    int ret = 0;
949
950
    /* Validate parameters. */
951
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
952
0
        ret = BAD_FUNC_ARG;
953
0
    }
954
    /* Can only work on multiples of block size of bytes. */
955
0
    if ((ret == 0) && ((sz & (SM4_BLOCK_SIZE - 1)) != 0)) {
956
0
        ret = BAD_FUNC_ARG;
957
0
    }
958
959
    /* Ensure a key and IV have been set. */
960
0
    if ((ret == 0) && (!sm4->keySet)) {
961
0
        ret = MISSING_KEY;
962
0
    }
963
0
    if ((ret == 0) && (!sm4->ivSet)) {
964
0
        ret = MISSING_IV;
965
0
    }
966
967
0
    if (ret == 0) {
968
0
    #ifndef WOLFSSL_SM4_SMALL
969
0
        if (in != out) {
970
0
            while (sz > 0) {
971
                /* Decrypt next block. */
972
0
                sm4_decrypt(sm4->ks, in, sm4->tmp);
973
                /* XOR decrypted block with IV to create output. */
974
0
                xorbufout(out, sm4->tmp, sm4->iv, SM4_BLOCK_SIZE);
975
                /* This encrypted block is the IV for next decryption. */
976
0
                XMEMCPY(sm4->iv, in, SM4_BLOCK_SIZE);
977
978
                /* Move on to next block. */
979
0
                in += SM4_BLOCK_SIZE;
980
0
                out += SM4_BLOCK_SIZE;
981
0
                sz -= SM4_BLOCK_SIZE;
982
0
            }
983
0
        }
984
0
        else
985
0
    #endif
986
0
        {
987
0
            while (sz > 0) {
988
                /* Cache encrypted block as it is next IV. */
989
0
                XMEMCPY(sm4->tmp, in, SM4_BLOCK_SIZE);
990
                /* Decrypt next block. */
991
0
                sm4_decrypt(sm4->ks, sm4->tmp, out);
992
                /* XOR decrypted block with IV to create output. */
993
0
                xorbuf(out, sm4->iv, SM4_BLOCK_SIZE);
994
                /* Cached encrypted block is next IV. */
995
0
                XMEMCPY(sm4->iv, sm4->tmp, SM4_BLOCK_SIZE);
996
997
                /* Move on to next block. */
998
0
                in += SM4_BLOCK_SIZE;
999
0
                out += SM4_BLOCK_SIZE;
1000
0
                sz -= SM4_BLOCK_SIZE;
1001
0
            }
1002
0
        }
1003
0
    }
1004
1005
0
    return ret;
1006
0
}
1007
1008
#endif /* WOLFSSL_SM4_CBC */
1009
1010
#ifdef WOLFSSL_SM4_CTR
1011
1012
/* Increment IV in big-endian representation.
1013
 *
1014
 * @param [in, out] counter  Counter value to increment.
1015
 */
1016
static WC_INLINE void sm4_increment_counter(byte* counter)
1017
0
{
1018
0
    int i;
1019
1020
    /* Big-endian number. */
1021
0
    for (i = SM4_BLOCK_SIZE - 1; i >= 0; i--) {
1022
        /* Increment byte and check for carry. */
1023
0
        if ((++counter[i]) != 0) {
1024
            /* No carry - done. */
1025
0
            break;
1026
0
        }
1027
0
    }
1028
0
}
1029
1030
/* Encrypt bytes using SM4-CTR.
1031
 *
1032
 * Assumes out is at least sz bytes long.
1033
 *
1034
 * @param [in]  sm4  SM4 algorithm object.
1035
 * @param [out] out  Byte array in which to place encrypted data.
1036
 * @param [in]  in   Array of bytes to encrypt.
1037
 * @param [in]  sz   Number of bytes to encrypt.
1038
 * @return  0 on success.
1039
 * @return  BAD_FUNC_ARG when sm4, out or in is NULL.
1040
 * @return  MISSING_KEY when a key has not been set.
1041
 * @return  MISSING_IV when an IV has not been set.
1042
 */
1043
int wc_Sm4CtrEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz)
1044
0
{
1045
0
    int ret = 0;
1046
1047
    /* Validate parameters. */
1048
0
    if ((sm4 == NULL) || (in == NULL) || (out == NULL)) {
1049
0
        ret = BAD_FUNC_ARG;
1050
0
    }
1051
1052
    /* Ensure a key and IV have been set. */
1053
0
    if ((ret == 0) && (!sm4->keySet)) {
1054
0
        ret = MISSING_KEY;
1055
0
    }
1056
0
    if ((ret == 0) && (!sm4->ivSet)) {
1057
0
        ret = MISSING_IV;
1058
0
    }
1059
1060
    /* Continue if no error and bytes to encrypt. */
1061
0
    if ((ret == 0) && (sz > 0)) {
1062
        /* Check for unused bytes from previous encrypted counter. */
1063
0
        if (sm4->unused != 0) {
1064
            /* Calculate maximum length that can be encrypted. */
1065
0
            word32 len = min(sm4->unused, sz);
1066
1067
            /* XOR the encrypted counter with input into output. */
1068
0
            xorbufout(out, in, sm4->tmp + SM4_BLOCK_SIZE - sm4->unused, len);
1069
1070
            /* Move over processed data. */
1071
0
            in += len;
1072
0
            out += len;
1073
0
            sz -= len;
1074
            /* Some or all unused bytes used up. */
1075
0
            sm4->unused -= (byte)len;
1076
0
        }
1077
1078
        /* Do blocks at a time - only get here when there are no unused bytes.
1079
         */
1080
0
        while (sz >= SM4_BLOCK_SIZE) {
1081
            /* Encrypt the current IV into temporary buffer in object. */
1082
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->tmp);
1083
            /* XOR the encrypted IV with next block into output. */
1084
0
            xorbufout(out, in, sm4->tmp, SM4_BLOCK_SIZE);
1085
            /* Increment counter for next block. */
1086
0
            sm4_increment_counter(sm4->iv);
1087
1088
            /* Move on to next block. */
1089
0
            in += SM4_BLOCK_SIZE;
1090
0
            out += SM4_BLOCK_SIZE;
1091
0
            sz -= SM4_BLOCK_SIZE;
1092
0
        }
1093
1094
        /* Check for less than a block of data that needing to be encrypted. */
1095
0
        if (sz > 0) {
1096
            /* Encrypt the current IV into temporary buffer in object. */
1097
0
            sm4_encrypt(sm4->ks, sm4->iv, sm4->tmp);
1098
            /* Increment counter for next block. */
1099
0
            sm4_increment_counter(sm4->iv);
1100
            /* XOR the encrypted IV with remaining data into output. */
1101
0
            xorbufout(out, in, sm4->tmp, sz);
1102
            /* Record number of unused encrypted IV bytes. */
1103
0
            sm4->unused = (byte)(SM4_BLOCK_SIZE - sz);
1104
0
        }
1105
0
    }
1106
1107
0
    return ret;
1108
0
}
1109
1110
#endif /* WOLFSSL_SM4_CTR */
1111
1112
#ifdef WOLFSSL_SM4_GCM
1113
/* Calculate the value of H for the GMAC operation.
1114
 *
1115
 * @param [in]  sm4  SM4 algorithm object.
1116
 * @param [in]  iv   Initial IV.
1117
 */
1118
static void sm4_gcm_calc_h(wc_Sm4* sm4, byte* iv)
1119
0
{
1120
#if defined(__aarch64__) && defined(WOLFSSL_ARMASM)
1121
    word32* pt = (word32*)sm4->gcm.H;
1122
#endif
1123
1124
    /* Encrypt all zeros IV to create hash key for GCM. */
1125
0
    sm4_encrypt(sm4->ks, iv, sm4->gcm.H);
1126
0
#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM)
1127
0
    #if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT)
1128
        /* Generate table from hash key. */
1129
0
        GenerateM0(&sm4->gcm);
1130
0
    #endif /* GCM_TABLE */
1131
#else
1132
    /* Reverse the bits of H for use in assembly. */
1133
    __asm__ volatile (
1134
        "LD1 {v0.16b}, [%[h]] \n"
1135
        "RBIT v0.16b, v0.16b \n"
1136
        "ST1 {v0.16b}, [%[out]] \n"
1137
        : [out] "=r" (pt)
1138
        : [h] "0" (pt)
1139
        : "cc", "memory", "v0"
1140
    );
1141
#endif
1142
0
}
1143
1144
/* Increment counter for GCM.
1145
 *
1146
 * @param [in, out] counter  4-byte big endian number.
1147
 */
1148
static WC_INLINE void sm4_increment_gcm_counter(byte* counter)
1149
0
{
1150
0
    int i;
1151
1152
    /* Big-endian number in last 4 bytes. */
1153
0
    for (i = SM4_BLOCK_SIZE - 1; i >= SM4_BLOCK_SIZE - CTR_SZ; i--) {
1154
        /* Increment byte and check for carry. */
1155
0
        if ((++counter[i]) != 0) {
1156
            /* No carry - done. */
1157
0
            break;
1158
0
        }
1159
0
    }
1160
0
}
1161
1162
/* Encrypt bytes using SM4-GCM implementation in C.
1163
 *
1164
 * @param [in]  sm4      SM4 algorithm object.
1165
 * @param [out] out      Byte array in which to place encrypted data.
1166
 * @param [in]  in       Array of bytes to encrypt.
1167
 * @param [in]  sz       Number of bytes to encrypt.
1168
 * @param [in]  nonce    Array of bytes holding nonce.
1169
 * @param [in]  nonceSz  Length of nonce in bytes.
1170
 * @param [out] tag      Authentication tag calculated using GCM.
1171
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1172
 *                       Must be no more than SM4_BLOCK_SIZE.
1173
 * @param [in]  aad      Additional authentication data. May be NULL.
1174
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1175
 */
1176
static void sm4_gcm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1177
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz,
1178
    const byte* aad, word32 aadSz)
1179
0
{
1180
0
    word32 blocks = sz / SM4_BLOCK_SIZE;
1181
0
    word32 partial = sz % SM4_BLOCK_SIZE;
1182
0
    byte* c = out;
1183
0
    ALIGN16 byte counter[SM4_BLOCK_SIZE];
1184
0
    ALIGN16 byte encCounter[SM4_BLOCK_SIZE];
1185
1186
    /* Check for 12 bytes of nonce to use as is with 4 bytes of counter. */
1187
0
    if (nonceSz == GCM_NONCE_MID_SZ) {
1188
        /* Counter is nonce with bottom 4 bytes set to: 0x00,0x00,0x00,0x01. */
1189
0
        XMEMCPY(counter, nonce, nonceSz);
1190
0
        XMEMSET(counter + GCM_NONCE_MID_SZ, 0, CTR_SZ - 1);
1191
0
        counter[SM4_BLOCK_SIZE - 1] = 1;
1192
0
    }
1193
0
    else {
1194
        /* Counter is GHASH of nonce. */
1195
0
        GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE);
1196
#ifdef WOLFSSL_ARMASM
1197
        GMULT(counter, sm4->gcm.H);
1198
#endif
1199
0
    }
1200
    /* Encrypt the initial counter for GMAC. */
1201
0
    sm4_encrypt(sm4->ks, counter, encCounter);
1202
1203
0
#if defined(WOLFSSL_SM4_ECB)
1204
    /* Encrypting multiple blocks at a time can be faster. */
1205
0
    if ((c != in) && (blocks > 0)) {
1206
        /* Set the counters for a multiple of block size into the output. */
1207
0
        while (blocks--) {
1208
            /* Increment last 4 bytes of big-endian counter. */
1209
0
            sm4_increment_gcm_counter(counter);
1210
            /* Copy into output. */
1211
0
            XMEMCPY(c, counter, SM4_BLOCK_SIZE);
1212
            /* Move output position past this block. */
1213
0
            c += SM4_BLOCK_SIZE;
1214
0
        }
1215
1216
        /* Reset number of blocks. */
1217
0
        blocks = sz / SM4_BLOCK_SIZE;
1218
        /* Encrypt the counters. */
1219
0
        wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks);
1220
        /* XOR in the plaintext to create cipher text. */
1221
0
        xorbuf(out, in, SM4_BLOCK_SIZE * blocks);
1222
        /* Step over handled plaintext */
1223
0
        in += SM4_BLOCK_SIZE * blocks;
1224
0
    }
1225
0
    else
1226
0
#endif /* HAVE_SM4_ECB */
1227
0
    {
1228
0
        ALIGN32 byte scratch[SM4_BLOCK_SIZE];
1229
1230
        /* For each full block of data, encrypt. */
1231
0
        while (blocks--) {
1232
            /* Increment last 4 bytes of big-endian counter. */
1233
0
            sm4_increment_gcm_counter(counter);
1234
            /* Encrypt the counter into scratch. */
1235
0
            sm4_encrypt(sm4->ks, counter, scratch);
1236
            /* XOR encryted counter with plaintext into output. */
1237
0
            xorbufout(c, scratch, in, SM4_BLOCK_SIZE);
1238
            /* Move plaintext and cipher text position past this block. */
1239
0
            in += SM4_BLOCK_SIZE;
1240
0
            c += SM4_BLOCK_SIZE;
1241
0
        }
1242
1243
0
        ForceZero(scratch, sizeof(scratch));
1244
0
    }
1245
1246
0
    if (partial != 0) {
1247
        /* Increment last 4 bytes of big-endian counter. */
1248
0
        sm4_increment_gcm_counter(counter);
1249
        /* Encrypt the last counter. */
1250
0
        sm4_encrypt(sm4->ks, counter, counter);
1251
        /* XOR encryted counter with partial block plaintext into output. */
1252
0
        xorbufout(c, counter, in, partial);
1253
0
    }
1254
1255
    /* Calculate GHASH on additional authentication data and cipher text. */
1256
0
#ifndef WOLFSSL_ARMASM
1257
0
    GHASH(&sm4->gcm, aad, aadSz, out, sz, tag, tagSz);
1258
#else
1259
    GHASH(&sm4->gcm, aad, aadSz, out, sz, counter, SM4_BLOCK_SIZE);
1260
    GMULT(counter, sm4->gcm.H);
1261
    XMEMCPY(tag, counter, tagSz);
1262
#endif
1263
    /* XOR the encrypted initial counter into tag. */
1264
0
    xorbuf(tag, encCounter, tagSz);
1265
1266
0
    ForceZero(counter, sizeof(counter));
1267
0
    ForceZero(encCounter, sizeof(encCounter));
1268
0
}
1269
1270
/* Decrypt bytes using SM4-GCM implementation in C.
1271
 *
1272
 * @param [in]  sm4      SM4 algorithm object.
1273
 * @param [out] out      Byte array in which to place decrypted data.
1274
 * @param [in]  in       Array of bytes to decrypt.
1275
 * @param [in]  sz       Number of bytes to decrypt.
1276
 * @param [in]  nonce    Array of bytes holding initialization vector.
1277
 * @param [in]  nonceSz  Length of nonce in bytes.
1278
 * @param [in]  tag      Authentication tag calculated using GCM.
1279
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1280
 *                       Must be no more than SM4_BLOCK_SIZE.
1281
 * @param [in]  aad      Additional authentication data. May be NULL.
1282
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1283
 * @return  0 on success.
1284
 * @return  SM4_GCM_AUTH_E when authentication tag calculated does not match
1285
 *          the one passed in.
1286
 */
1287
static int sm4_gcm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1288
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1289
    const byte* aad, word32 aadSz)
1290
0
{
1291
0
    int ret;
1292
0
    word32 blocks = sz / SM4_BLOCK_SIZE;
1293
0
    word32 partial = sz % SM4_BLOCK_SIZE;
1294
0
    byte* p = out;
1295
0
    ALIGN16 byte counter[SM4_BLOCK_SIZE];
1296
0
    ALIGN16 byte calcTag[SM4_BLOCK_SIZE];
1297
0
    ALIGN16 byte scratch[SM4_BLOCK_SIZE];
1298
0
    sword32 res;
1299
1300
0
    if (nonceSz == GCM_NONCE_MID_SZ) {
1301
        /* Counter is nonce with bottom 4 bytes set to: 0x00,0x00,0x00,0x01. */
1302
0
        XMEMCPY(counter, nonce, nonceSz);
1303
0
        XMEMSET(counter + GCM_NONCE_MID_SZ, 0, CTR_SZ - 1);
1304
0
        counter[SM4_BLOCK_SIZE - 1] = 1;
1305
0
    }
1306
0
    else {
1307
        /* Counter is GHASH of nonce. */
1308
0
        GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE);
1309
#ifdef WOLFSSL_ARMASM
1310
        GMULT(counter, sm4->gcm.H);
1311
#endif
1312
0
    }
1313
1314
    /* Calculate GHASH on additional authentication data and cipher text. */
1315
0
#ifndef WOLFSSL_ARMASM
1316
0
    GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, sizeof(calcTag));
1317
#else
1318
    GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, SM4_BLOCK_SIZE);
1319
    GMULT(calcTag, sm4->gcm.H);
1320
#endif
1321
    /* Encrypt the initial counter. */
1322
0
    sm4_encrypt(sm4->ks, counter, scratch);
1323
    /* XOR the encrypted initial counter into calculated tag. */
1324
0
    xorbuf(calcTag, scratch, sizeof(calcTag));
1325
#ifdef WC_SM4_GCM_DEC_AUTH_EARLY
1326
    /* Compare tag and calculated tag in constant time. */
1327
    res = ConstantCompare(tag, calcTag, tagSz);
1328
    /* Create mask based on comparison result in constant time */
1329
    res = 0 - (sword32)(((word32)(0 - res)) >> 31U);
1330
    /* Mask error code to get return value. */
1331
    ret = res & SM4_GCM_AUTH_E;
1332
    /* Decrypt data when no error. */
1333
    if (ret == 0)
1334
#endif
1335
0
    {
1336
0
    #if defined(WOLFSSL_SM4_ECB)
1337
0
        if ((in != p) && (blocks > 0)) {
1338
            /* Set the counters for a multiple of block size into the output. */
1339
0
            while (blocks--) {
1340
                /* Increment last 4 bytes of big-endian counter. */
1341
0
                sm4_increment_gcm_counter(counter);
1342
                /* Copy into output. */
1343
0
                XMEMCPY(p, counter, SM4_BLOCK_SIZE);
1344
                /* Move output position past this block. */
1345
0
                p += SM4_BLOCK_SIZE;
1346
0
            }
1347
1348
            /* Reset number of blocks. */
1349
0
            blocks = sz / SM4_BLOCK_SIZE;
1350
            /* Encrypt the counters. */
1351
0
            wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks);
1352
            /* XOR in the plaintext to create cipher text. */
1353
0
            xorbuf(out, in, SM4_BLOCK_SIZE * blocks);
1354
            /* Step over handled plaintext */
1355
0
            in += SM4_BLOCK_SIZE * blocks;
1356
0
        }
1357
0
        else
1358
0
    #endif /* WOLFSSL_SM4_ECB */
1359
0
        {
1360
0
            while (blocks--) {
1361
                /* Increment last 4 bytes of big-endian counter. */
1362
0
                sm4_increment_gcm_counter(counter);
1363
                /* Encrypt the counter into scratch. */
1364
0
                sm4_encrypt(sm4->ks, counter, scratch);
1365
                /* XOR encryted counter with cipher text into output. */
1366
0
                xorbufout(p, scratch, in, SM4_BLOCK_SIZE);
1367
                /* Move plaintext and cipher text position past this block. */
1368
0
                p += SM4_BLOCK_SIZE;
1369
0
                in += SM4_BLOCK_SIZE;
1370
0
            }
1371
0
        }
1372
1373
0
        if (partial != 0) {
1374
            /* Increment last 4 bytes of big-endian counter. */
1375
0
            sm4_increment_gcm_counter(counter);
1376
            /* Encrypt the last counter. */
1377
0
            sm4_encrypt(sm4->ks, counter, counter);
1378
            /* XOR encryted counter with partial block cipher text into output.
1379
             */
1380
0
            xorbufout(p, counter, in, partial);
1381
0
        }
1382
1383
0
    #ifndef WC_SM4_GCM_DEC_AUTH_EARLY
1384
        /* Compare tag and calculated tag in constant time. */
1385
0
        res = ConstantCompare(tag, calcTag, (int)tagSz);
1386
        /* Create mask based on comparison result in constant time */
1387
0
        res = 0 - (sword32)(((word32)(0 - res)) >> 31U);
1388
        /* Mask error code to get return value. */
1389
0
        ret = res & SM4_GCM_AUTH_E;
1390
0
    #endif
1391
0
    }
1392
1393
0
    ForceZero(counter, sizeof(counter));
1394
0
    ForceZero(calcTag, sizeof(calcTag));
1395
0
    ForceZero(scratch, sizeof(scratch));
1396
1397
0
    return ret;
1398
0
}
1399
1400
/* Set the SM4-GCM key.
1401
 *
1402
 * Calculates key based table here.
1403
 *
1404
 * @param [in, out] sm4  SM4 algorithm object.
1405
 * @param [in]      key  Array of bytes representing key.
1406
 * @param [in]      len  Length of key. Must be SM4_KEY_SIZE.
1407
 * @return  0 on success.
1408
 * @return  BAD_FUNC_ARG when sm4 or key is NULL.
1409
 * @return  BAD_FUNC_ARG when len is not SM4_KEY_SIZE.
1410
 */
1411
int wc_Sm4GcmSetKey(wc_Sm4* sm4, const byte* key, word32 len)
1412
0
{
1413
0
    int ret = 0;
1414
0
    byte iv[SM4_BLOCK_SIZE];
1415
1416
    /* Validate parameters. */
1417
0
    if ((sm4 == NULL) || (key == NULL) || (len != SM4_KEY_SIZE)) {
1418
0
        ret = BAD_FUNC_ARG;
1419
0
    }
1420
1421
0
    if (ret == 0) {
1422
        /* Set key. */
1423
0
        sm4_set_key(sm4, key);
1424
        /* Reset IV to all zeros. */
1425
0
        XMEMSET(iv, 0, sizeof(iv));
1426
        /* Set IV. */
1427
0
        sm4_set_iv(sm4, iv);
1428
        /* Calculate H for GMAC operation */
1429
0
        sm4_gcm_calc_h(sm4, iv);
1430
0
    }
1431
1432
0
    return ret;
1433
0
}
1434
1435
/* Encrypt bytes using SM4-GCM.
1436
 *
1437
 * Assumes out is at least sz bytes long.
1438
 *
1439
 * @param [in]  sm4      SM4 algorithm object.
1440
 * @param [out] out      Byte array in which to place encrypted data.
1441
 * @param [in]  in       Array of bytes to encrypt.
1442
 * @param [in]  sz       Number of bytes to encrypt.
1443
 * @param [in]  nonce    Array of bytes holding initialization vector.
1444
 * @param [in]  nonceSz  Length of nonce in bytes.
1445
 * @param [out] tag      Authentication tag calculated using GCM.
1446
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1447
 *                       Must be no more than SM4_BLOCK_SIZE.
1448
 * @param [in]  aad      Additional authentication data. May be NULL.
1449
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1450
 * @return  0 on success.
1451
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1452
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1453
 *          WOLFSSL_MIN_AUTH_TAG_SZ or is more than SM4_BLOCK_SIZE.
1454
 * @return  BAD_FUNC_ARG when nonce length is 0.
1455
 * @return  MISSING_KEY when a key has not been set.
1456
 */
1457
int wc_Sm4GcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1458
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1459
    word32 aadSz)
1460
0
{
1461
0
    int ret = 0;
1462
1463
    /* Validate parameters. */
1464
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1465
0
            (nonce == NULL) || (tag == NULL)) {
1466
0
        ret = BAD_FUNC_ARG;
1467
0
    }
1468
0
    if ((tagSz < WOLFSSL_MIN_AUTH_TAG_SZ) || (tagSz > SM4_BLOCK_SIZE)) {
1469
0
        ret = BAD_FUNC_ARG;
1470
0
    }
1471
0
    if (nonceSz == 0) {
1472
0
        ret = BAD_FUNC_ARG;
1473
0
    }
1474
1475
    /* Ensure a key has been set. */
1476
0
    if ((ret == 0) && (!sm4->keySet)) {
1477
0
        ret = MISSING_KEY;
1478
0
    }
1479
1480
0
    if (ret == 0) {
1481
    #ifdef OPENSSL_EXTRA
1482
        sm4->nonceSz = (int)nonceSz;
1483
    #endif
1484
        /* Perform encryption using C implementation. */
1485
0
        sm4_gcm_encrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz, aad,
1486
0
            aadSz);
1487
0
    }
1488
1489
0
    return ret;
1490
0
}
1491
1492
/* Decrypt bytes using SM4-GCM.
1493
 *
1494
 * Assumes out is at least sz bytes long.
1495
 *
1496
 * @param [in]  sm4      SM4 algorithm object.
1497
 * @param [out] out      Byte array in which to place decrypted data.
1498
 * @param [in]  in       Array of bytes to decrypt.
1499
 * @param [in]  sz       Number of bytes to decrypt.
1500
 * @param [in]  nonce    Array of bytes holding initialization vector.
1501
 * @param [in]  nonceSz  Length of nonce in bytes.
1502
 * @param [in]  tag      Authentication tag to compare against calculated.
1503
 * @param [in]  tagSz    Length of authentication tag in bytes.
1504
 *                       Must be no more than SM4_BLOCK_SIZE.
1505
 * @param [in]  aad      Additional authentication data. May be NULL.
1506
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1507
 * @return  0 on success.
1508
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1509
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1510
 *          WOLFSSL_MIN_AUTH_TAG_SZ or is more than SM4_BLOCK_SIZE.
1511
 * @return  BAD_FUNC_ARG when nonce length is 0.
1512
 * @return  MISSING_KEY when a key has not been set.
1513
 * @return  SM4_GCM_AUTH_E when authentication tag calculated does not match
1514
 *          the one passed in.
1515
 */
1516
int wc_Sm4GcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1517
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1518
    const byte* aad, word32 aadSz)
1519
0
{
1520
0
    int ret = 0;
1521
1522
    /* Validate parameters. */
1523
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1524
0
            (nonce == NULL) || (tag == NULL)) {
1525
0
        ret = BAD_FUNC_ARG;
1526
0
    }
1527
0
    if ((tagSz < WOLFSSL_MIN_AUTH_TAG_SZ) || (tagSz > SM4_BLOCK_SIZE)) {
1528
0
        ret = BAD_FUNC_ARG;
1529
0
    }
1530
0
    if (nonceSz == 0) {
1531
0
        ret = BAD_FUNC_ARG;
1532
0
    }
1533
1534
    /* Ensure a key has been set. */
1535
0
    if ((ret == 0) && (!sm4->keySet)) {
1536
0
        ret = MISSING_KEY;
1537
0
    }
1538
1539
0
    if (ret == 0) {
1540
    #ifdef OPENSSL_EXTRA
1541
        sm4->nonceSz = (int)nonceSz;
1542
    #endif
1543
        /* Perform decryption using C implementation. */
1544
0
        ret = sm4_gcm_decrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz,
1545
0
            aad, aadSz);
1546
0
    }
1547
1548
0
    return ret;
1549
0
}
1550
1551
#endif /* WOLFSSL_SM4_GCM */
1552
1553
#ifdef WOLFSSL_SM4_CCM
1554
1555
/* Roll up data.
1556
 *
1557
 * Encrypt each block XORed into out.
1558
 *
1559
 * @param [in]      sm4  SM4 algorithm object.
1560
 * @param [in]      in   Data to roll up.
1561
 * @param [in]      sz   Length in bytes of data.
1562
 * @param [in, out] out  Block XORed into and encrypted.
1563
 */
1564
static void sm4_ccm_roll_x(wc_Sm4* sm4, const byte* in, word32 sz, byte* out)
1565
0
{
1566
    /* XOR in each block and encrypt each result. */
1567
0
    while (sz >= SM4_BLOCK_SIZE) {
1568
        /* XOR in next block. */
1569
0
        xorbuf(out, in, SM4_BLOCK_SIZE);
1570
        /* Move on past block. */
1571
0
        in += SM4_BLOCK_SIZE;
1572
0
        sz -= SM4_BLOCK_SIZE;
1573
        /* Encrypt into self. */
1574
0
        sm4_encrypt(sm4->ks, out, out);
1575
0
    }
1576
1577
    /* XOR in a block of data and encrypt result. */
1578
0
    if (sz > 0) {
1579
        /* XOR in partial block. */
1580
0
        xorbuf(out, in, sz);
1581
        /* Encrypt into self. */
1582
0
        sm4_encrypt(sm4->ks, out, out);
1583
0
    }
1584
0
}
1585
1586
/* Roll up additional authentication data (AAD).
1587
 *
1588
 * First block has length plus ant AAD XORed in before being encrypted.
1589
 *
1590
 * @param [in]  sm4  SM4 algorithm object.
1591
 * @param [in]  in   Additional authentication data to roll up.
1592
 * @param [in]  sz   Length in bytes of data.
1593
 * @param [out] out  Block XORed into and encrypted.
1594
 */
1595
static void sm4_ccm_roll_aad(wc_Sm4* sm4, const byte* in, word32 sz, byte* out)
1596
0
{
1597
0
    word32 aadLenSz;
1598
0
    word32 remainder;
1599
1600
    /* XOR length at start of block. */
1601
0
    if (sz <= 0xFEFF) {
1602
        /* Two bytes used to represent length. */
1603
0
        aadLenSz = 2;
1604
0
        out[0] ^= ((sz & 0xFF00) >> 8);
1605
0
        out[1] ^=  (sz & 0x00FF);
1606
0
    }
1607
0
    else {
1608
        /* Four bytes used to represent length plus two unique bytes. */
1609
0
        aadLenSz = 6;
1610
0
        out[0] ^= 0xFF;
1611
0
        out[1] ^= 0xFE;
1612
0
        out[2] ^= (byte)((sz & 0xFF000000) >> 24);
1613
0
        out[3] ^= (byte)((sz & 0x00FF0000) >> 16);
1614
0
        out[4] ^= (byte)((sz & 0x0000FF00) >>  8);
1615
0
        out[5] ^= (byte) (sz & 0x000000FF);
1616
0
    }
1617
1618
    /* Calculate number of input bytes required to make up the block. */
1619
0
    remainder = SM4_BLOCK_SIZE - aadLenSz;
1620
    /* Check how much AAD available. */
1621
0
    if (sz >= remainder) {
1622
        /* XOR up to block into out. */
1623
0
        xorbuf(out + aadLenSz, in, remainder);
1624
        /* Move past data. */
1625
0
        sz -= remainder;
1626
0
        in += remainder;
1627
0
    }
1628
0
    else {
1629
        /* XOR in AAD available. */
1630
0
        xorbuf(out + aadLenSz, in, sz);
1631
        /* All AAD used. */
1632
0
        sz = 0;
1633
0
    }
1634
    /* Encrypt into self. */
1635
0
    sm4_encrypt(sm4->ks, out, out);
1636
1637
0
    if (sz > 0) {
1638
        /* Roll up any remaining AAD. */
1639
0
        sm4_ccm_roll_x(sm4, in, sz, out);
1640
0
    }
1641
0
}
1642
1643
/* Last bytes incremented as a big-endian number.
1644
 *
1645
 * Bytes not the nonce and length are incremented.
1646
 *
1647
 * @param [in, out] b      IV block.
1648
 * @param [in]      ctrSz  Length of counter.
1649
 */
1650
static WC_INLINE void sm4_ccm_ctr_inc(byte* b, word32 ctrSz)
1651
0
{
1652
0
    word32 i;
1653
1654
    /* Only last bytes that make up counter. */
1655
0
    for (i = 0; i < ctrSz; i++) {
1656
        /* Increment byte and check for carry. */
1657
0
        if ((++b[SM4_BLOCK_SIZE - 1 - i]) != 0) {
1658
            /* No carry - done. */
1659
0
            break;
1660
0
        }
1661
0
    }
1662
0
}
1663
1664
/* Encipher bytes using SM4-CCM.
1665
 *
1666
 * @param [in]       sm4    SM4 algorithm object.
1667
 * @param [out]      out    Byte array in which to place encrypted data.
1668
 * @param [in]       in     Array of bytes to encrypt.
1669
 * @param [in]       sz     Number of bytes to encrypt.
1670
 * @param [in, out]  b      IV block.
1671
 * @param [in]       ctrSz  Number of counter bytes in IV block.
1672
 */
1673
static WC_INLINE void sm4_ccm_crypt(wc_Sm4* sm4, byte* out, const byte* in,
1674
    word32 sz, byte* b, byte ctrSz)
1675
0
{
1676
0
    ALIGN16 byte a[SM4_BLOCK_SIZE];
1677
1678
    /* Nonce and length have been set and counter 0 except for last byte. */
1679
1680
    /* Set counter to 1. */
1681
0
    b[SM4_BLOCK_SIZE - 1] = 1;
1682
    /* Encrypting full blocks at a time. */
1683
0
    while (sz >= SM4_BLOCK_SIZE) {
1684
        /* Encrypt counter. */
1685
0
        sm4_encrypt(sm4->ks, b, a);
1686
        /* XOR in plaintext. */
1687
0
        xorbuf(a, in, SM4_BLOCK_SIZE);
1688
        /* Copy cipher text out. */
1689
0
        XMEMCPY(out, a, SM4_BLOCK_SIZE);
1690
1691
        /* Increment counter for next block. */
1692
0
        sm4_ccm_ctr_inc(b, ctrSz);
1693
        /* Move over block. */
1694
0
        sz -= SM4_BLOCK_SIZE;
1695
0
        in += SM4_BLOCK_SIZE;
1696
0
        out += SM4_BLOCK_SIZE;
1697
0
    }
1698
0
    if (sz > 0) {
1699
        /* Encrypt counter. */
1700
0
        sm4_encrypt(sm4->ks, b, a);
1701
        /* XOR in remaining plaintext. */
1702
0
        xorbuf(a, in, sz);
1703
        /* Copy cipher text out. */
1704
0
        XMEMCPY(out, a, sz);
1705
0
    }
1706
1707
0
    ForceZero(a, sizeof(a));
1708
0
}
1709
1710
/* Calculate authentication tag for SM4-CCM.
1711
 *
1712
 * @param [in]       sm4    SM4 algorithm object.
1713
 * @param [in]       plain  Array of bytes to encrypt.
1714
 * @param [in]       sz     Number of bytes to encrypt.
1715
 * @param [in]       aad    Additional authentication data. May be NULL.
1716
 * @param [in]       aadSz  Length of additional authentication data in bytes.
1717
 * @param [in, out]  b      IV block.
1718
 * @param [in]       ctrSz  Number of counter bytes in IV block.
1719
 * @param [out]      tag    Authentication tag calculated using CCM.
1720
 * @param [in]       tagSz  Length of authentication tag to calculate in bytes.
1721
 */
1722
static WC_INLINE void sm4_ccm_calc_auth_tag(wc_Sm4* sm4, const byte* plain,
1723
    word32 sz, const byte* aad, word32 aadSz, byte* b, byte ctrSz,
1724
    byte* tag, word32 tagSz)
1725
0
{
1726
0
    ALIGN16 byte a[SM4_BLOCK_SIZE];
1727
0
    byte t[SM4_BLOCK_SIZE];
1728
0
    word32 i;
1729
1730
    /* Nonce is in place. */
1731
1732
    /* Set first byte to length and flags. */
1733
0
    b[0] = (byte)((((aad != NULL) && (aadSz > 0)) ? 0x40 : 0x00) +
1734
0
                  (8 * (((byte)tagSz - 2) / 2)) + (ctrSz - 1));
1735
    /* Set the counter bytes to length of data - 4 bytes of length only. */
1736
0
    for (i = 0; i < ctrSz && i < sizeof(word32); i++) {
1737
0
        b[SM4_BLOCK_SIZE - 1 - i] = (byte)(sz >> (8 * i));
1738
0
    }
1739
    /* Set remaining counter bytes to 0. */
1740
0
    for (; i < ctrSz; i++) {
1741
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0x00;
1742
0
    }
1743
    /* Encrypt block into authentication tag block. */
1744
0
    sm4_encrypt(sm4->ks, b, a);
1745
1746
0
    if ((aad != NULL) && (aadSz > 0)) {
1747
        /* Roll up any AAD. */
1748
0
        sm4_ccm_roll_aad(sm4, aad, aadSz, a);
1749
0
    }
1750
0
    if (sz > 0) {
1751
        /* Roll up any plaintext. */
1752
0
        sm4_ccm_roll_x(sm4, plain, sz, a);
1753
0
    }
1754
1755
    /* Nonce remains in place. */
1756
    /* Set first byte to counter size - 1. */
1757
0
    b[0] = ctrSz - 1;
1758
    /* Set counter to 0. */
1759
0
    for (i = 0; i < ctrSz; i++) {
1760
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0;
1761
0
    }
1762
    /* Encrypt block into authentication tag block. */
1763
0
    sm4_encrypt(sm4->ks, b, t);
1764
    /* XOR in other authentication tag data. */
1765
0
    xorbufout(tag, t, a, tagSz);
1766
1767
0
    ForceZero(a, sizeof(a));
1768
0
    ForceZero(t, sizeof(t));
1769
0
}
1770
1771
/* Encrypt bytes using SM4-CCM implementation in C.
1772
 *
1773
 * @param [in]  sm4      SM4 algorithm object.
1774
 * @param [out] out      Byte array in which to place encrypted data.
1775
 * @param [in]  in       Array of bytes to encrypt.
1776
 * @param [in]  sz       Number of bytes to encrypt.
1777
 * @param [in]  nonce    Array of bytes holding initialization vector.
1778
 * @param [in]  nonceSz  Length of nonce in bytes.
1779
 * @param [out] tag      Authentication tag calculated using CCM.
1780
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1781
 *                       Must be no more than SM4_BLOCK_SIZE.
1782
 * @param [in]  aad      Additional authentication data. May be NULL.
1783
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1784
 */
1785
static void sm4_ccm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1786
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1787
    word32 aadSz)
1788
0
{
1789
0
    ALIGN16 byte b[SM4_BLOCK_SIZE];
1790
0
    byte ctrSz;
1791
1792
    /* Calculate length of counter. */
1793
0
    ctrSz = SM4_BLOCK_SIZE - 1 - (byte)nonceSz;
1794
    /* Copy nonce in after length byte. */
1795
0
    XMEMCPY(b + 1, nonce, nonceSz);
1796
1797
    /* Calculate authentication tag. */
1798
0
    sm4_ccm_calc_auth_tag(sm4, in, sz, aad, aadSz, b, ctrSz, tag, tagSz);
1799
    /* b is left with first byte counter size - 1 and counter part set to zero.
1800
     */
1801
1802
0
    if (sz > 0) {
1803
        /* Encrypt plaintext to cipher text. */
1804
0
        sm4_ccm_crypt(sm4, out, in, sz, b, ctrSz);
1805
0
    }
1806
1807
0
    ForceZero(b, sizeof(b));
1808
0
}
1809
1810
/* Decrypt bytes using SM4-CCM implementation in C.
1811
 *
1812
 * @param [in]  sm4      SM4 algorithm object.
1813
 * @param [out] out      Byte array in which to place decrypted data.
1814
 * @param [in]  in       Array of bytes to decrypt.
1815
 * @param [in]  sz       Number of bytes to decrypt.
1816
 * @param [in]  nonce    Array of bytes holding initialization vector.
1817
 * @param [in]  nonceSz  Length of nonce in bytes.
1818
 * @param [in]  tag      Authentication tag calculated using GCM.
1819
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1820
 *                       Must be no more than SM4_BLOCK_SIZE.
1821
 * @param [in]  aad      Additional authentication data. May be NULL.
1822
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1823
 * @return  0 on success.
1824
 * @return  SM4_CCM_AUTH_E when authentication tag calculated does not match
1825
 *          the one passed in.
1826
 */
1827
static int sm4_ccm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1828
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1829
    const byte* aad, word32 aadSz)
1830
0
{
1831
0
    ALIGN16 byte b[SM4_BLOCK_SIZE];
1832
0
    ALIGN16 byte t[SM4_BLOCK_SIZE];
1833
0
    byte ctrSz;
1834
0
    word32 i;
1835
0
    int ret = 0;
1836
1837
    /* Calculate length of counter. */
1838
0
    ctrSz = SM4_BLOCK_SIZE - 1 - (byte)nonceSz;
1839
    /* Copy nonce in after length byte. */
1840
0
    XMEMCPY(b + 1, nonce, nonceSz);
1841
1842
    /* Set length byte to counter size - 1. */
1843
0
    b[0] = ctrSz - 1;
1844
    /* Set all bytes but least significant of counter to 0. */
1845
0
    for (i = 1; i < ctrSz; i++) {
1846
0
        b[SM4_BLOCK_SIZE - 1 - i] = 0;
1847
0
    }
1848
0
    if (sz > 0) {
1849
        /* Decrypt cipher text to plaintext. */
1850
0
        sm4_ccm_crypt(sm4, out, in, sz, b, ctrSz);
1851
        /* b still has nonce in place. */
1852
0
    }
1853
1854
    /* Calculate authentication tag. */
1855
0
    sm4_ccm_calc_auth_tag(sm4, out, sz, aad, aadSz, b, ctrSz, t, tagSz);
1856
1857
    /* Compare calculated tag with passed in tag. */
1858
0
    if (ConstantCompare(t, tag, (int)tagSz) != 0) {
1859
        /* Set CCM authentication error return. */
1860
0
        ret = SM4_CCM_AUTH_E;
1861
0
    }
1862
1863
0
    ForceZero(b, sizeof(b));
1864
0
    ForceZero(t, sizeof(t));
1865
1866
0
    return ret;
1867
0
}
1868
1869
/* Encrypt bytes using SM4-CCM.
1870
 *
1871
 * Assumes out is at least sz bytes long.
1872
 *
1873
 * @param [in]  sm4      SM4 algorithm object.
1874
 * @param [out] out      Byte array in which to place encrypted data.
1875
 * @param [in]  in       Array of bytes to encrypt.
1876
 * @param [in]  sz       Number of bytes to encrypt.
1877
 * @param [in]  nonce    Array of bytes holding initialization vector.
1878
 * @param [in]  nonceSz  Length of nonce in bytes.
1879
 * @param [out] tag      Authentication tag calculated using CCM.
1880
 * @param [in]  tagSz    Length of authentication tag to calculate in bytes.
1881
 *                       Must be no more than SM4_BLOCK_SIZE.
1882
 * @param [in]  aad      Additional authentication data. May be NULL.
1883
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1884
 * @return  0 on success.
1885
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1886
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1887
 *          4 or is more than SM4_BLOCK_SIZE or an odd value.
1888
 * @return  BAD_FUNC_ARG when nonce length is less than CCM_NONCE_MIN_SZ or
1889
 *          greater than CCM_NONCE_MAX_SZ.
1890
 * @return  MISSING_KEY when a key has not been set.
1891
 */
1892
int wc_Sm4CcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1893
    const byte* nonce, word32 nonceSz, byte* tag, word32 tagSz, const byte* aad,
1894
    word32 aadSz)
1895
0
{
1896
0
    int ret = 0;
1897
1898
    /* Validate parameters. */
1899
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1900
0
            (nonce == NULL) || (tag == NULL)) {
1901
0
        ret = BAD_FUNC_ARG;
1902
0
    }
1903
    /* Tag size is even number 4..16. */
1904
0
    if ((tagSz < 4) || (tagSz > SM4_BLOCK_SIZE) || ((tagSz & 1) == 1)) {
1905
0
        ret = BAD_FUNC_ARG;
1906
0
    }
1907
    /* Nonce must be within supported range. */
1908
0
    if ((nonceSz < CCM_NONCE_MIN_SZ) || (nonceSz > CCM_NONCE_MAX_SZ)) {
1909
0
        ret = BAD_FUNC_ARG;
1910
0
    }
1911
    /* Message length must fit the CCM length field of (15 - nonceSz) bytes. */
1912
0
    if (ret == 0) {
1913
0
        word32 ctrSz = (word32)SM4_BLOCK_SIZE - 1 - nonceSz;
1914
0
        if ((ctrSz < sizeof(sz)) && (sz > (((word32)1 << (8 * ctrSz)) - 1))) {
1915
0
            ret = BAD_FUNC_ARG;
1916
0
        }
1917
0
    }
1918
1919
    /* Ensure a key has been set. */
1920
0
    if ((ret == 0) && (!sm4->keySet)) {
1921
0
        ret = MISSING_KEY;
1922
0
    }
1923
1924
0
    if (ret == 0) {
1925
    #ifdef OPENSSL_EXTRA
1926
        sm4->nonceSz = (int)nonceSz;
1927
    #endif
1928
        /* Perform encryption using C implementation. */
1929
0
        sm4_ccm_encrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz, aad,
1930
0
            aadSz);
1931
0
    }
1932
1933
0
    return ret;
1934
0
}
1935
1936
/* Decrypt bytes using SM4-CCM.
1937
 *
1938
 * Assumes out is at least sz bytes long.
1939
 *
1940
 * @param [in]  sm4      SM4 algorithm object.
1941
 * @param [out] out      Byte array in which to place decrypted data.
1942
 * @param [in]  in       Array of bytes to decrypt.
1943
 * @param [in]  sz       Number of bytes to decrypt.
1944
 * @param [in]  nonce    Array of bytes holding initialization vector.
1945
 * @param [in]  nonceSz  Length of nonce in bytes.
1946
 * @param [in]  tag      Authentication tag to compare against calculated.
1947
 * @param [in]  tagSz    Length of authentication tag in bytes.
1948
 *                       Must be no more than SM4_BLOCK_SIZE.
1949
 * @param [in]  aad      Additional authentication data. May be NULL.
1950
 * @param [in]  aadSz    Length of additional authentication data in bytes.
1951
 * @return  0 on success.
1952
 * @return  BAD_FUNC_ARG when sm4, in, out, nonce or tag is NULL.
1953
 * @return  BAD_FUNC_ARG when authentication tag data length is less than
1954
 *          4 or is more than SM4_BLOCK_SIZE or an odd value.
1955
 * @return  BAD_FUNC_ARG when nonce length is less than CCM_NONCE_MIN_SZ or
1956
 *          greater than CCM_NONCE_MAX_SZ.
1957
 * @return  MISSING_KEY when a key has not been set.
1958
 * @return  SM4_CCM_AUTH_E when authentication tag calculated does not match
1959
 *          the one passed in.
1960
 */
1961
int wc_Sm4CcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz,
1962
    const byte* nonce, word32 nonceSz, const byte* tag, word32 tagSz,
1963
    const byte* aad, word32 aadSz)
1964
0
{
1965
0
    int ret = 0;
1966
1967
    /* Validate parameters. */
1968
0
    if ((sm4 == NULL) || ((sz != 0) && ((in == NULL) || (out == NULL))) ||
1969
0
            (nonce == NULL) || (tag == NULL)) {
1970
0
        ret = BAD_FUNC_ARG;
1971
0
    }
1972
    /* Tag size is even number 4..16. */
1973
0
    if ((tagSz < 4) || (tagSz > SM4_BLOCK_SIZE) || ((tagSz & 1) == 1)) {
1974
0
        ret = BAD_FUNC_ARG;
1975
0
    }
1976
    /* Nonce must be within supported range. */
1977
0
    if ((nonceSz < CCM_NONCE_MIN_SZ) || (nonceSz > CCM_NONCE_MAX_SZ)) {
1978
0
        ret = BAD_FUNC_ARG;
1979
0
    }
1980
    /* Message length must fit the CCM length field of (15 - nonceSz) bytes. */
1981
0
    if (ret == 0) {
1982
0
        word32 ctrSz = (word32)SM4_BLOCK_SIZE - 1 - nonceSz;
1983
0
        if ((ctrSz < sizeof(sz)) && (sz > (((word32)1 << (8 * ctrSz)) - 1))) {
1984
0
            ret = BAD_FUNC_ARG;
1985
0
        }
1986
0
    }
1987
1988
    /* Ensure a key has been set. */
1989
0
    if ((ret == 0) && (!sm4->keySet)) {
1990
0
        ret = MISSING_KEY;
1991
0
    }
1992
1993
0
    if (ret == 0) {
1994
    #ifdef OPENSSL_EXTRA
1995
        sm4->nonceSz = (int)nonceSz;
1996
    #endif
1997
        /* Perform decryption using C implementation. */
1998
0
        ret = sm4_ccm_decrypt_c(sm4, out, in, sz, nonce, nonceSz, tag, tagSz,
1999
0
            aad, aadSz);
2000
0
    }
2001
2002
0
    return ret;
2003
0
}
2004
2005
#endif
2006
2007
#endif /* WOLFSSL_SM4 */
2008