SM4 is a block cipher standard published by the government of the People's Republic of China, and it was issued by the State Cryptography Administration on March 21, 2012. The standard is GM/T 0002-2012 "SM4 block cipher algorithm".
SM4 algorithm is a symmetric cipher algorithm in ShangMi cryptosystems. The block length and key length are both 128 bits. Both the encryption algorithm and the key derivation algorithm use 32 rounds of non-linear iterative structure, and the S box is a fixed 8 bits. The RFC 8998 specification defines the usage of ShangMi algorithm suite in TLS 1.3, etc. According to the State Cryptography Administration of China, its security and efficiency are equivalent to AES-128.
Reference specification: 1. http://www.gmbz.org.cn/upload/2018-04-04/1522788048733065051.pdf 2. http://gmbz.org.cn/main/viewfile/20180108015408199368.html 3. https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html 4. https://datatracker.ietf.org/doc/html/rfc8998
--- v2 changes: - use separate set_key functions to avoid two copies of the subkeys. - unify encryption and decryption operations with one function. - use unsigned type instead of uint32_t for loop counter i. - use four variables instead of four5-element array.
Tianjia Zhang (7): doc: Add Copyright of SM3 hash algorithm Introduce SM4 symmetric cipher algorithm testsuite: add test for SM4 symmetric algorithm nettle-benchmark: bench SM4 symmetric algorithm doc: documentation for SM4 cipher algorithm gcm: Add SM4 as the GCM underlying cipher doc: documentation for GCM using SM4 cipher
Makefile.in | 2 + examples/nettle-benchmark.c | 2 + gcm-sm4-meta.c | 60 ++++++++++ gcm-sm4.c | 81 +++++++++++++ gcm.h | 25 +++- nettle-meta-aeads.c | 1 + nettle-meta-ciphers.c | 1 + nettle-meta.h | 3 + nettle.texinfo | 81 +++++++++++++ sm4-meta.c | 49 ++++++++ sm4.c | 223 +++++++++++++++++++++++++++++++++++ sm4.h | 69 +++++++++++ testsuite/.gitignore | 1 + testsuite/Makefile.in | 2 +- testsuite/gcm-test.c | 18 +++ testsuite/meta-aead-test.c | 1 + testsuite/meta-cipher-test.c | 3 +- testsuite/sm4-test.c | 19 +++ 18 files changed, 638 insertions(+), 3 deletions(-) create mode 100644 gcm-sm4-meta.c create mode 100644 gcm-sm4.c create mode 100644 sm4-meta.c create mode 100644 sm4.c create mode 100644 sm4.h create mode 100644 testsuite/sm4-test.c
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- nettle.texinfo | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/nettle.texinfo b/nettle.texinfo index 76934637..45b06720 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -293,6 +293,10 @@ Written by @value{AUTHOR}, using Peter Gutmann's SHA1 code as a model. @item SHA3 Written by @value{AUTHOR}.
+@item SM3 +The C implementation of the SM3 message digest is written by Tianjia +Zhang, and the code is based on the implementation by Jia Zhang. + @item TWOFISH The implementation of the TWOFISH cipher is written by Ruud de Rooij.
Introduce the SM4 cipher algorithms (OSCCA GB/T 32907-2016).
SM4 (GBT.32907-2016) is a cryptographic standard issued by the Organization of State Commercial Administration of China (OSCCA) as an authorized cryptographic algorithms for the use within China.
SMS4 was originally created for use in protecting wireless networks, and is mandated in the Chinese National Standard for Wireless LAN WAPI (Wired Authentication and Privacy Infrastructure) (GB.15629.11-2003).
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- Makefile.in | 1 + nettle-meta-ciphers.c | 1 + nettle-meta.h | 2 + sm4-meta.c | 49 ++++++++ sm4.c | 223 +++++++++++++++++++++++++++++++++++ sm4.h | 69 +++++++++++ testsuite/meta-cipher-test.c | 3 +- 7 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 sm4-meta.c create mode 100644 sm4.c create mode 100644 sm4.h
diff --git a/Makefile.in b/Makefile.in index f6bc2155..ba1a2db2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -150,6 +150,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \ serpent-meta.c \ streebog.c streebog-meta.c \ twofish.c twofish-meta.c \ + sm4.c sm4-meta.c \ umac-nh.c umac-nh-n.c umac-l2.c umac-l3.c \ umac-poly64.c umac-poly128.c umac-set-key.c \ umac32.c umac64.c umac96.c umac128.c \ diff --git a/nettle-meta-ciphers.c b/nettle-meta-ciphers.c index 49cb47a7..f8d691cf 100644 --- a/nettle-meta-ciphers.c +++ b/nettle-meta-ciphers.c @@ -54,6 +54,7 @@ const struct nettle_cipher * const _nettle_ciphers[] = { &nettle_arctwo64, &nettle_arctwo128, &nettle_arctwo_gutmann128, + &nettle_sm4, NULL };
diff --git a/nettle-meta.h b/nettle-meta.h index d684947e..3d0440e8 100644 --- a/nettle-meta.h +++ b/nettle-meta.h @@ -89,6 +89,8 @@ extern const struct nettle_cipher nettle_arctwo64; extern const struct nettle_cipher nettle_arctwo128; extern const struct nettle_cipher nettle_arctwo_gutmann128;
+extern const struct nettle_cipher nettle_sm4; + struct nettle_hash { const char *name; diff --git a/sm4-meta.c b/sm4-meta.c new file mode 100644 index 00000000..d7234984 --- /dev/null +++ b/sm4-meta.c @@ -0,0 +1,49 @@ +/* sm4-meta.c + + Copyright (C) 2022 Tianjia Zhang tianjia.zhang@linux.alibaba.com + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "nettle-meta.h" + +#include "sm4.h" + +const struct nettle_cipher nettle_sm4 = { + "sm4", + sizeof(struct sm4_ctx), + SM4_BLOCK_SIZE, + SM4_KEY_SIZE, + (nettle_set_key_func *) sm4_set_encrypt_key, + (nettle_set_key_func *) sm4_set_decrypt_key, + (nettle_cipher_func *) sm4_crypt, + (nettle_cipher_func *) sm4_crypt +}; diff --git a/sm4.c b/sm4.c new file mode 100644 index 00000000..7b3c049a --- /dev/null +++ b/sm4.c @@ -0,0 +1,223 @@ +/* sm4.c + + Copyright (C) 2022 Tianjia Zhang tianjia.zhang@linux.alibaba.com + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <string.h> + +#include "sm4.h" + +#include "macros.h" + + +static const uint32_t fk[4] = +{ + 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc +}; + +static const uint32_t ck[32] = +{ + 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, + 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, + 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, + 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, + 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, + 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, + 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, + 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 +}; + +static const uint8_t sbox[256] = +{ + 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, + 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, + 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, + 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, + 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, + 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, + 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, + 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, + 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, + 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, + 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, + 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, + 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, + 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, + 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, + 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, + 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, + 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, + 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, + 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, + 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, + 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, + 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, + 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, + 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, + 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, + 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, + 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, + 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, + 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 +}; + +static uint32_t +sm4_t_non_lin_sub(uint32_t x) +{ + uint32_t out; + + out = (uint32_t)sbox[x & 0xff]; + out |= (uint32_t)sbox[(x >> 8) & 0xff] << 8; + out |= (uint32_t)sbox[(x >> 16) & 0xff] << 16; + out |= (uint32_t)sbox[(x >> 24) & 0xff] << 24; + + return out; +} + +static uint32_t +sm4_key_lin_sub(uint32_t x) +{ + return x ^ ROTL32(13, x) ^ ROTL32(23, x); +} + +static uint32_t +sm4_enc_lin_sub(uint32_t x) +{ + return x ^ ROTL32(2, x) ^ ROTL32(10, x) ^ ROTL32(18, x) ^ ROTL32(24, x); +} + +static uint32_t +sm4_key_sub(uint32_t x) +{ + return sm4_key_lin_sub(sm4_t_non_lin_sub(x)); +} + +static uint32_t +sm4_enc_sub(uint32_t x) +{ + return sm4_enc_lin_sub(sm4_t_non_lin_sub(x)); +} + +static uint32_t +sm4_round(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t rk) +{ + return x0 ^ sm4_enc_sub(x1 ^ x2 ^ x3 ^ rk); +} + +static void +sm4_set_key(struct sm4_ctx *ctx, const uint8_t *key, int encrypt) +{ + uint32_t rk0, rk1, rk2, rk3; + unsigned i; + + rk0 = READ_UINT32(key + 0) ^ fk[0]; + rk1 = READ_UINT32(key + 4) ^ fk[1]; + rk2 = READ_UINT32(key + 8) ^ fk[2]; + rk3 = READ_UINT32(key + 12) ^ fk[3]; + + for (i = 0; i < 32; i += 4) + { + rk0 ^= sm4_key_sub(rk1 ^ rk2 ^ rk3 ^ ck[i + 0]); + rk1 ^= sm4_key_sub(rk2 ^ rk3 ^ rk0 ^ ck[i + 1]); + rk2 ^= sm4_key_sub(rk3 ^ rk0 ^ rk1 ^ ck[i + 2]); + rk3 ^= sm4_key_sub(rk0 ^ rk1 ^ rk2 ^ ck[i + 3]); + + if (encrypt) + { + ctx->rkey[i + 0] = rk0; + ctx->rkey[i + 1] = rk1; + ctx->rkey[i + 2] = rk2; + ctx->rkey[i + 3] = rk3; + } + else + { + ctx->rkey[31 - 0 - i] = rk0; + ctx->rkey[31 - 1 - i] = rk1; + ctx->rkey[31 - 2 - i] = rk2; + ctx->rkey[31 - 3 - i] = rk3; + } + } +} + +void +sm4_set_encrypt_key(struct sm4_ctx *ctx, const uint8_t *key) +{ + sm4_set_key(ctx, key, 1); +} + +void +sm4_set_decrypt_key(struct sm4_ctx *ctx, const uint8_t *key) +{ + sm4_set_key(ctx, key, 0); +} + +void +sm4_crypt(const struct sm4_ctx *context, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const uint32_t *rk = context->rkey; + + assert( !(length % SM4_BLOCK_SIZE) ); + + for ( ; length; length -= SM4_BLOCK_SIZE) + { + uint32_t x0, x1, x2, x3; + unsigned i; + + x0 = READ_UINT32(src + 0 * 4); + x1 = READ_UINT32(src + 1 * 4); + x2 = READ_UINT32(src + 2 * 4); + x3 = READ_UINT32(src + 3 * 4); + + for (i = 0; i < 32; i += 4) + { + x0 = sm4_round(x0, x1, x2, x3, rk[i + 0]); + x1 = sm4_round(x1, x2, x3, x0, rk[i + 1]); + x2 = sm4_round(x2, x3, x0, x1, rk[i + 2]); + x3 = sm4_round(x3, x0, x1, x2, rk[i + 3]); + } + + WRITE_UINT32(dst + 0 * 4, x3); + WRITE_UINT32(dst + 1 * 4, x2); + WRITE_UINT32(dst + 2 * 4, x1); + WRITE_UINT32(dst + 3 * 4, x0); + + src += SM4_BLOCK_SIZE; + dst += SM4_BLOCK_SIZE; + } +} diff --git a/sm4.h b/sm4.h new file mode 100644 index 00000000..608eb3f3 --- /dev/null +++ b/sm4.h @@ -0,0 +1,69 @@ +/* sm4.h + + Copyright (C) 2022 Tianjia Zhang tianjia.zhang@linux.alibaba.com + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#ifndef NETTLE_SM4_H_INCLUDED +#define NETTLE_SM4_H_INCLUDED + +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define sm4_set_encrypt_key nettle_sm4_set_encrypt_key +#define sm4_set_decrypt_key nettle_sm4_set_decrypt_key +#define sm4_crypt nettle_sm4_crypt + +#define SM4_BLOCK_SIZE 16 +#define SM4_KEY_SIZE 16 + +struct sm4_ctx +{ + uint32_t rkey[32]; +}; + +void +sm4_set_encrypt_key(struct sm4_ctx *ctx, const uint8_t *key); + +void +sm4_set_decrypt_key(struct sm4_ctx *ctx, const uint8_t *key); + +void +sm4_crypt(const struct sm4_ctx *context, + size_t length, uint8_t *dst, + const uint8_t *src); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_SM4_H_INCLUDED */ diff --git a/testsuite/meta-cipher-test.c b/testsuite/meta-cipher-test.c index f949fd76..62488b7f 100644 --- a/testsuite/meta-cipher-test.c +++ b/testsuite/meta-cipher-test.c @@ -18,7 +18,8 @@ const char* ciphers[] = { "serpent256", "twofish128", "twofish192", - "twofish256" + "twofish256", + "sm4" };
void
Add a testuite for SM4 symmetric algorithm. Test vectors are based on: https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- testsuite/.gitignore | 1 + testsuite/Makefile.in | 2 +- testsuite/sm4-test.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 testsuite/sm4-test.c
diff --git a/testsuite/.gitignore b/testsuite/.gitignore index ca41472e..07127d2b 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -98,6 +98,7 @@ /sha512-256-test /sha512-test /sm3-test +/sm4-test /streebog-test /twofish-test /umac-test diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 6734d3e6..c2662826 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -24,7 +24,7 @@ TS_NETTLE_SOURCES = aes-test.c aes-keywrap-test.c arcfour-test.c arctwo-test.c \ sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \ sha3-permute-test.c sha3-224-test.c sha3-256-test.c \ sha3-384-test.c sha3-512-test.c \ - shake256-test.c streebog-test.c sm3-test.c \ + shake256-test.c streebog-test.c sm3-test.c sm4-test.c \ serpent-test.c twofish-test.c version-test.c \ knuth-lfib-test.c \ cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ diff --git a/testsuite/sm4-test.c b/testsuite/sm4-test.c new file mode 100644 index 00000000..97d9d58a --- /dev/null +++ b/testsuite/sm4-test.c @@ -0,0 +1,19 @@ +#include "testutils.h" +#include "sm4.h" + +void +test_main(void) +{ + /* test vectors from: + * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html + */ + test_cipher(&nettle_sm4, + SHEX("0123456789ABCDEF FEDCBA9876543210"), + SHEX("0123456789ABCDEF FEDCBA9876543210"), + SHEX("681EDF34D206965E 86B3E94F536E4246")); + + test_cipher(&nettle_sm4, + SHEX("FEDCBA9876543210 0123456789ABCDEF"), + SHEX("0001020304050607 08090A0B0C0D0E0F"), + SHEX("F766678F13F01ADE AC1B3EA955ADB594")); +}
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- examples/nettle-benchmark.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/examples/nettle-benchmark.c b/examples/nettle-benchmark.c index ba5dd284..802a7234 100644 --- a/examples/nettle-benchmark.c +++ b/examples/nettle-benchmark.c @@ -63,6 +63,7 @@ #include "sha1.h" #include "sha2.h" #include "sha3.h" +#include "sm4.h" #include "twofish.h" #include "umac.h" #include "cmac.h" @@ -926,6 +927,7 @@ main(int argc, char **argv) &nettle_des3, &nettle_serpent256, &nettle_twofish128, &nettle_twofish192, &nettle_twofish256, + &nettle_sm4, NULL };
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- nettle.texinfo | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
diff --git a/nettle.texinfo b/nettle.texinfo index 45b06720..a6cc9379 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -297,6 +297,9 @@ Written by @value{AUTHOR}. The C implementation of the SM3 message digest is written by Tianjia Zhang, and the code is based on the implementation by Jia Zhang.
+@item SM4 +The implementation of the SM4 cipher is written by Tianjia Zhang. + @item TWOFISH The implementation of the TWOFISH cipher is written by Ruud de Rooij.
@@ -2277,6 +2280,42 @@ in any other way. Analogous to @code{twofish_encrypt} @end deftypefun
+@node SM4 +@subsection SM4 +@cindex SM4 + +SM4 is a block cipher standard adopted by the government of the People's +Republic of China, and it was issued by the State Cryptography Administration +on March 21, 2012. The standard is GM/T 0002-2012 "SM4 block cipher algorithm". +Nettle defines it in @file{<nettle/sm4.h>}. + +@deftp {Context struct} {struct sm4_ctx} +@end deftp + +@defvr Constant SM4_BLOCK_SIZE +The SM4 block-size, 16. +@end defvr + +@defvr Constant SM4_KEY_SIZE +Default SM4 key size, 16. +@end defvr + +@deftypefun void sm4_set_encrypt_key (struct sm4_ctx *@var{ctx}, const uint8_t *@var{key}) +Initialize the cipher. The function is used for encryption. +@end deftypefun + +@deftypefun void sm4_set_decrypt_key (struct sm4_ctx *@var{ctx}, const uint8_t *@var{key}) +Initialize the cipher. The function is used for decryption. +@end deftypefun + +@deftypefun void sm4_crypt (const struct sm4_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Cryption function. @var{length} must be an integral multiple of the +block size. If it is more than one block, the data is processed in ECB +mode. @code{src} and @code{dst} may be equal, but they must not overlap +in any other way. The same function is used for both encryption and +decryption. +@end deftypefun + @node nettle_cipher abstraction @subsection The @code{struct nettle_cipher} abstraction @cindex nettle_cipher
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- Makefile.in | 1 + gcm-sm4-meta.c | 60 ++++++++++++++++++++++++++++ gcm-sm4.c | 81 ++++++++++++++++++++++++++++++++++++++ gcm.h | 25 +++++++++++- nettle-meta-aeads.c | 1 + nettle-meta.h | 1 + testsuite/gcm-test.c | 18 +++++++++ testsuite/meta-aead-test.c | 1 + 8 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 gcm-sm4-meta.c create mode 100644 gcm-sm4.c
diff --git a/Makefile.in b/Makefile.in index ba1a2db2..e96bac31 100644 --- a/Makefile.in +++ b/Makefile.in @@ -112,6 +112,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \ gcm-aes256.c gcm-aes256-meta.c \ gcm-camellia128.c gcm-camellia128-meta.c \ gcm-camellia256.c gcm-camellia256-meta.c \ + gcm-sm4.c gcm-sm4-meta.c \ cmac.c cmac64.c cmac-aes128.c cmac-aes256.c cmac-des3.c \ cmac-aes128-meta.c cmac-aes256-meta.c cmac-des3-meta.c \ gost28147.c gosthash94.c gosthash94-meta.c \ diff --git a/gcm-sm4-meta.c b/gcm-sm4-meta.c new file mode 100644 index 00000000..090460d3 --- /dev/null +++ b/gcm-sm4-meta.c @@ -0,0 +1,60 @@ +/* gcm-sm4-meta.c + + Copyright (C) 2022 Tianjia Zhang tianjia.zhang@linux.alibaba.com + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "nettle-meta.h" + +#include "gcm.h" + +static nettle_set_key_func gcm_sm4_set_nonce_wrapper; +static void +gcm_sm4_set_nonce_wrapper (void *ctx, const uint8_t *nonce) +{ + gcm_sm4_set_iv (ctx, GCM_IV_SIZE, nonce); +} + +const struct nettle_aead nettle_gcm_sm4 = + { "gcm_sm4", sizeof(struct gcm_sm4_ctx), + GCM_BLOCK_SIZE, SM4_KEY_SIZE, + GCM_IV_SIZE, GCM_DIGEST_SIZE, + (nettle_set_key_func *) gcm_sm4_set_key, + (nettle_set_key_func *) gcm_sm4_set_key, + gcm_sm4_set_nonce_wrapper, + (nettle_hash_update_func *) gcm_sm4_update, + (nettle_crypt_func *) gcm_sm4_encrypt, + (nettle_crypt_func *) gcm_sm4_decrypt, + (nettle_hash_digest_func *) gcm_sm4_digest, + }; diff --git a/gcm-sm4.c b/gcm-sm4.c new file mode 100644 index 00000000..19d91ae9 --- /dev/null +++ b/gcm-sm4.c @@ -0,0 +1,81 @@ +/* gcm-sm4.c + + Galois counter mode using SM4 as the underlying cipher. + + Copyright (C) 2022 Tianjia Zhang tianjia.zhang@linux.alibaba.com + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "gcm.h" + +void +gcm_sm4_set_key(struct gcm_sm4_ctx *ctx, const uint8_t *key) +{ + GCM_SET_KEY(ctx, sm4_set_encrypt_key, sm4_crypt, key); +} + +void +gcm_sm4_set_iv(struct gcm_sm4_ctx *ctx, + size_t length, const uint8_t *iv) +{ + GCM_SET_IV (ctx, length, iv); +} + +void +gcm_sm4_update(struct gcm_sm4_ctx *ctx, + size_t length, const uint8_t *data) +{ + GCM_UPDATE (ctx, length, data); +} + +void +gcm_sm4_encrypt(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + GCM_ENCRYPT(ctx, sm4_crypt, length, dst, src); +} + +void +gcm_sm4_decrypt(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + GCM_DECRYPT(ctx, sm4_crypt, length, dst, src); +} + +void +gcm_sm4_digest(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *digest) +{ + GCM_DIGEST(ctx, sm4_crypt, length, digest); +} diff --git a/gcm.h b/gcm.h index 96578530..39af5ab0 100644 --- a/gcm.h +++ b/gcm.h @@ -40,6 +40,7 @@
#include "aes.h" #include "camellia.h" +#include "sm4.h"
#ifdef __cplusplus extern "C" { @@ -95,6 +96,13 @@ extern "C" { #define gcm_camellia256_decrypt nettle_gcm_camellia256_decrypt #define gcm_camellia256_digest nettle_gcm_camellia256_digest
+#define gcm_sm4_set_key nettle_gcm_sm4_set_key +#define gcm_sm4_set_iv nettle_gcm_sm4_set_iv +#define gcm_sm4_update nettle_gcm_sm4_update +#define gcm_sm4_encrypt nettle_gcm_sm4_encrypt +#define gcm_sm4_decrypt nettle_gcm_sm4_decrypt +#define gcm_sm4_digest nettle_gcm_sm4_digest + #define GCM_BLOCK_SIZE 16 #define GCM_IV_SIZE (GCM_BLOCK_SIZE - 4) #define GCM_DIGEST_SIZE 16 @@ -322,7 +330,22 @@ void gcm_camellia256_decrypt(struct gcm_camellia256_ctx *ctx, void gcm_camellia256_digest(struct gcm_camellia256_ctx *ctx, size_t length, uint8_t *digest);
- + +struct gcm_sm4_ctx GCM_CTX(struct sm4_ctx); + +void gcm_sm4_set_key(struct gcm_sm4_ctx *ctx, const uint8_t *key); +void gcm_sm4_set_iv(struct gcm_sm4_ctx *ctx, + size_t length, const uint8_t *iv); +void gcm_sm4_update(struct gcm_sm4_ctx *ctx, + size_t length, const uint8_t *data); +void gcm_sm4_encrypt(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); +void gcm_sm4_decrypt(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); +void gcm_sm4_digest(struct gcm_sm4_ctx *ctx, + size_t length, uint8_t *digest); + + #ifdef __cplusplus } #endif diff --git a/nettle-meta-aeads.c b/nettle-meta-aeads.c index c99cc465..78f38a3c 100644 --- a/nettle-meta-aeads.c +++ b/nettle-meta-aeads.c @@ -43,6 +43,7 @@ const struct nettle_aead * const _nettle_aeads[] = { &nettle_gcm_aes256, &nettle_gcm_camellia128, &nettle_gcm_camellia256, + &nettle_gcm_sm4, &nettle_eax_aes128, &nettle_chacha_poly1305, NULL diff --git a/nettle-meta.h b/nettle-meta.h index 3d0440e8..19dc96c5 100644 --- a/nettle-meta.h +++ b/nettle-meta.h @@ -200,6 +200,7 @@ extern const struct nettle_aead nettle_gcm_aes192; extern const struct nettle_aead nettle_gcm_aes256; extern const struct nettle_aead nettle_gcm_camellia128; extern const struct nettle_aead nettle_gcm_camellia256; +extern const struct nettle_aead nettle_gcm_sm4; extern const struct nettle_aead nettle_eax_aes128; extern const struct nettle_aead nettle_chacha_poly1305;
diff --git a/testsuite/gcm-test.c b/testsuite/gcm-test.c index d68af4e0..1897c41a 100644 --- a/testsuite/gcm-test.c +++ b/testsuite/gcm-test.c @@ -574,6 +574,24 @@ test_main(void) "16aedbf5a0de6a57 a637b39b"), /* iv */ SHEX("5791883f822013f8bd136fc36fb9946b")); /* tag */
+ /* + * GCM-SM4 Test Vectors from + * https://datatracker.ietf.org/doc/html/rfc8998 + */ + test_aead(&nettle_gcm_sm4, NULL, + SHEX("0123456789ABCDEFFEDCBA9876543210"), + SHEX("FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2"), + SHEX("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB" + "CCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDD" + "EEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF" + "EEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAA"), + SHEX("17F399F08C67D5EE19D0DC9969C4BB7D" + "5FD46FD3756489069157B282BB200735" + "D82710CA5C22F0CCFA7CBF93D496AC15" + "A56834CBCF98C397B4024A2691233B8D"), + SHEX("00001234567800000000ABCD"), + SHEX("83DE3541E4C2B58177E065A9BF7B62EC")); + /* Test gcm_hash, with varying message size, keys and iv all zero. Not compared to any other implementation. */ test_gcm_hash (SDATA("a"), diff --git a/testsuite/meta-aead-test.c b/testsuite/meta-aead-test.c index 1fcede40..ceeca227 100644 --- a/testsuite/meta-aead-test.c +++ b/testsuite/meta-aead-test.c @@ -8,6 +8,7 @@ const char* aeads[] = { "gcm_aes256", "gcm_camellia128", "gcm_camellia256", + "gcm_sm4", "eax_aes128", "chacha_poly1305", };
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com --- nettle.texinfo | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/nettle.texinfo b/nettle.texinfo index a6cc9379..7a256eda 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -3360,6 +3360,44 @@ that @var{length} is @code{GCM_DIGEST_SIZE}, but if you provide a smaller value, only the first @var{length} octets of the digest are written. @end deftypefun
+@subsubsection @acronym{GCM}-SM4 interface + +The following functions implement the case of @acronym{GCM} using +SM4 as the underlying cipher. + +@deftp {Context struct} {struct gcm_sm4_ctx} +Context structs, defined using @code{GCM_CTX}. +@end deftp + +@deftypefun void gcm_sm4_set_key (struct gcm_sm4_ctx *@var{ctx}, const uint8_t *@var{key}) +Initializes @var{ctx} using the given key. +@end deftypefun + +@deftypefun void gcm_sm4_set_iv (struct gcm_sm4_ctx *@var{ctx}, size_t @var{length}, const uint8_t *@var{iv}) +Initializes the per-message state, using the given @acronym{IV}. +@end deftypefun + +@deftypefun void gcm_sm4_update (struct gcm_sm4_ctx *@var{ctx}, size_t @var{length}, const uint8_t *@var{data}) +Provides associated data to be authenticated. If used, must be called +before @code{gcm_sm4_encrypt} or @code{gcm_sm4_decrypt}. All but the +last call for each message @emph{must} use a length that is a multiple +of the block size. +@end deftypefun + +@deftypefun void gcm_sm4_encrypt (struct gcm_sm4_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) +@deftypefunx void gcm_sm4_decrypt (struct gcm_sm4_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Encrypts or decrypts the data of a message. All but the last call for +each message @emph{must} use a length that is a multiple of the block +size. +@end deftypefun + +@deftypefun void gcm_sm4_digest (struct gcm_sm4_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{digest}) +Extracts the message digest (also known ``authentication tag''). This is +the final operation when processing a message. It's strongly recommended +that @var{length} is @code{GCM_DIGEST_SIZE}, but if you provide a smaller +value, only the first @var{length} octets of the digest are written. +@end deftypefun + @node CCM @subsection Counter with CBC-MAC mode
nettle-bugs@lists.lysator.liu.se