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.
Signed-off-by: Hyman Huang <yong.hu...@smartx.com> --- crypto/block-luks.c | 7 ++++++ crypto/cipher-gcrypt.c.inc | 4 ++++ crypto/cipher-nettle.c.inc | 42 +++++++++++++++++++++++++++++++++ crypto/cipher.c | 2 ++ qapi/crypto.json | 5 +++- tests/unit/test-crypto-cipher.c | 11 +++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index fb01ec38bb..1cb7f21a05 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -95,12 +95,19 @@ qcrypto_block_luks_cipher_size_map_twofish[] = { { 0, 0 }, }; +static const QCryptoBlockLUKSCipherSizeMap +qcrypto_block_luks_cipher_size_map_sm4[] = { + { 16, QCRYPTO_CIPHER_ALG_SM4}, + { 0, 0 }, +}; + static const QCryptoBlockLUKSCipherNameMap qcrypto_block_luks_cipher_name_map[] = { { "aes", qcrypto_block_luks_cipher_size_map_aes }, { "cast5", qcrypto_block_luks_cipher_size_map_cast5 }, { "serpent", qcrypto_block_luks_cipher_size_map_serpent }, { "twofish", qcrypto_block_luks_cipher_size_map_twofish }, + { "sm4", qcrypto_block_luks_cipher_size_map_sm4}, }; QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48); diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc index a6a0117717..03af50b0c3 100644 --- a/crypto/cipher-gcrypt.c.inc +++ b/crypto/cipher-gcrypt.c.inc @@ -35,6 +35,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_ALG_SERPENT_256: case QCRYPTO_CIPHER_ALG_TWOFISH_128: case QCRYPTO_CIPHER_ALG_TWOFISH_256: + case QCRYPTO_CIPHER_ALG_SM4: break; default: return false; @@ -219,6 +220,9 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_ALG_TWOFISH_256: gcryalg = GCRY_CIPHER_TWOFISH; break; + case QCRYPTO_CIPHER_ALG_SM4: + gcryalg = GCRY_CIPHER_SM4; + break; default: error_setg(errp, "Unsupported cipher algorithm %s", QCryptoCipherAlgorithm_str(alg)); diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc index 24cc61f87b..cd2ca0c7b5 100644 --- a/crypto/cipher-nettle.c.inc +++ b/crypto/cipher-nettle.c.inc @@ -30,6 +30,7 @@ #include <nettle/serpent.h> #include <nettle/twofish.h> #include <nettle/ctr.h> +#include <nettle/sm4.h> #ifndef CONFIG_QEMU_PRIVATE_XTS #include <nettle/xts.h> #endif @@ -426,6 +427,28 @@ DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_twofish, QCryptoNettleTwofish, TWOFISH_BLOCK_SIZE, twofish_encrypt_native, twofish_decrypt_native) +typedef struct QCryptoNettleSm4 { + QCryptoCipher base; + struct sm4_ctx key[2]; +} QCryptoNettleSm4; + +static void sm4_encrypt_native(void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + struct sm4_ctx *keys = ctx; + sm4_crypt(&keys[0], length, dst, src); +} + +static void sm4_decrypt_native(void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + struct sm4_ctx *keys = ctx; + sm4_crypt(&keys[1], length, dst, src); +} + +DEFINE_ECB(qcrypto_nettle_sm4, + QCryptoNettleSm4, SM4_BLOCK_SIZE, + sm4_encrypt_native, sm4_decrypt_native) bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, QCryptoCipherMode mode) @@ -443,6 +466,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_ALG_TWOFISH_128: case QCRYPTO_CIPHER_ALG_TWOFISH_192: case QCRYPTO_CIPHER_ALG_TWOFISH_256: + case QCRYPTO_CIPHER_ALG_SM4: break; default: return false; @@ -702,6 +726,24 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, return &ctx->base; } + case QCRYPTO_CIPHER_ALG_SM4: + { + QCryptoNettleSm4 *ctx = g_new0(QCryptoNettleSm4, 1); + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + ctx->base.driver = &qcrypto_nettle_sm4_driver_ecb; + break; + default: + goto bad_cipher_mode; + } + + sm4_set_encrypt_key(&ctx->key[0], key); + sm4_set_decrypt_key(&ctx->key[1], key); + + return &ctx->base; + } + default: error_setg(errp, "Unsupported cipher algorithm %s", QCryptoCipherAlgorithm_str(alg)); diff --git a/crypto/cipher.c b/crypto/cipher.c index 74b09a5b26..048ceaa6a3 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -38,6 +38,7 @@ static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24, [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32, + [QCRYPTO_CIPHER_ALG_SM4] = 16, }; static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { @@ -53,6 +54,7 @@ static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16, [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16, + [QCRYPTO_CIPHER_ALG_SM4] = 16, }; static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = { diff --git a/qapi/crypto.json b/qapi/crypto.json index fd3d46ebd1..95fa10bb6d 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -94,6 +94,8 @@ # # @twofish-256: Twofish with 256 bit / 32 byte keys # +# @sm4: SM4 with 128 bit / 16 byte keys (since 8.2) +# # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm', @@ -102,7 +104,8 @@ 'des', '3des', 'cast5-128', 'serpent-128', 'serpent-192', 'serpent-256', - 'twofish-128', 'twofish-192', 'twofish-256']} + 'twofish-128', 'twofish-192', 'twofish-256', + 'sm4']} ## # @QCryptoCipherMode: diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index d9d9d078ff..80a4984e43 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -382,6 +382,17 @@ static QCryptoCipherTestData test_data[] = { .plaintext = "90afe91bb288544f2c32dc239b2635e6", .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa", }, + { + /* SM4, GB/T 32907-2016, Appendix A.1 */ + .path = "/crypto/cipher/sm4", + .alg = QCRYPTO_CIPHER_ALG_SM4, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "0123456789abcdeffedcba9876543210", + .plaintext = + "0123456789abcdeffedcba9876543210", + .ciphertext = + "681edf34d206965e86b3e94f536e4246", + }, { /* #1 32 byte key, 32 byte PTX */ .path = "/crypto/cipher/aes-xts-128-1", -- 2.39.1