Skip to content

Commit

Permalink
crypto: Introduce SM4 symmetric cipher algorithm
Browse files Browse the repository at this point in the history
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.

Detect the SM4 cipher algorithms and enable the feature silently
if it is available.

Signed-off-by: Hyman Huang <yong.huang@smartx.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
  • Loading branch information
HuangSuiXiao authored and berrange committed Feb 9, 2024
1 parent fdd5140 commit 52ed9f4
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 1 deletion.
11 changes: 11 additions & 0 deletions crypto/block-luks.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,23 @@ qcrypto_block_luks_cipher_size_map_twofish[] = {
{ 0, 0 },
};

#ifdef CONFIG_CRYPTO_SM4
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_sm4[] = {
{ 16, QCRYPTO_CIPHER_ALG_SM4},
{ 0, 0 },
};
#endif

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 },
#ifdef CONFIG_CRYPTO_SM4
{ "sm4", qcrypto_block_luks_cipher_size_map_sm4},
#endif
};

QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48);
Expand Down
8 changes: 8 additions & 0 deletions crypto/cipher-gcrypt.c.inc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_SERPENT_256:
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
#endif
break;
default:
return false;
Expand Down Expand Up @@ -219,6 +222,11 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
gcryalg = GCRY_CIPHER_TWOFISH;
break;
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
gcryalg = GCRY_CIPHER_SM4;
break;
#endif
default:
error_setg(errp, "Unsupported cipher algorithm %s",
QCryptoCipherAlgorithm_str(alg));
Expand Down
49 changes: 49 additions & 0 deletions crypto/cipher-nettle.c.inc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#ifndef CONFIG_QEMU_PRIVATE_XTS
#include <nettle/xts.h>
#endif
#ifdef CONFIG_CRYPTO_SM4
#include <nettle/sm4.h>
#endif

static inline bool qcrypto_length_check(size_t len, size_t blocksize,
Error **errp)
Expand Down Expand Up @@ -426,6 +429,30 @@ DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_twofish,
QCryptoNettleTwofish, TWOFISH_BLOCK_SIZE,
twofish_encrypt_native, twofish_decrypt_native)

#ifdef CONFIG_CRYPTO_SM4
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)
#endif

bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
Expand All @@ -443,6 +470,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
#endif
break;
default:
return false;
Expand Down Expand Up @@ -701,6 +731,25 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,

return &ctx->base;
}
#ifdef CONFIG_CRYPTO_SM4
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;
}
#endif

default:
error_setg(errp, "Unsupported cipher algorithm %s",
Expand Down
6 changes: 6 additions & 0 deletions crypto/cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ 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,
#ifdef CONFIG_CRYPTO_SM4
[QCRYPTO_CIPHER_ALG_SM4] = 16,
#endif
};

static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
Expand All @@ -53,6 +56,9 @@ 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,
#ifdef CONFIG_CRYPTO_SM4
[QCRYPTO_CIPHER_ALG_SM4] = 16,
#endif
};

static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
Expand Down
26 changes: 26 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,7 @@ endif
gcrypt = not_found
nettle = not_found
hogweed = not_found
crypto_sm4 = not_found
xts = 'none'

if get_option('nettle').enabled() and get_option('gcrypt').enabled()
Expand All @@ -1658,6 +1659,17 @@ if not gnutls_crypto.found()
cc.find_library('gpg-error', required: true)],
version: gcrypt.version())
endif
crypto_sm4 = gcrypt
# SM4 ALG is available in libgcrypt >= 1.9
if gcrypt.found() and not cc.links('''
#include <gcrypt.h>
int main(void) {
gcry_cipher_hd_t handler;
gcry_cipher_open(&handler, GCRY_CIPHER_SM4, GCRY_CIPHER_MODE_ECB, 0);
return 0;
}''', dependencies: gcrypt)
crypto_sm4 = not_found
endif
endif
if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
nettle = dependency('nettle', version: '>=3.4',
Expand All @@ -1666,6 +1678,18 @@ if not gnutls_crypto.found()
if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
xts = 'private'
endif
crypto_sm4 = nettle
# SM4 ALG is available in nettle >= 3.9
if nettle.found() and not cc.links('''
#include <nettle/sm4.h>
int main(void) {
struct sm4_ctx ctx;
unsigned char key[16] = {0};
sm4_set_encrypt_key(&ctx, key);
return 0;
}''', dependencies: nettle)
crypto_sm4 = not_found
endif
endif
endif

Expand Down Expand Up @@ -2267,6 +2291,7 @@ config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
config_host_data.set('CONFIG_TASN1', tasn1.found())
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
config_host_data.set('CONFIG_NETTLE', nettle.found())
config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
config_host_data.set('CONFIG_HOGWEED', hogweed.found())
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
Expand Down Expand Up @@ -4306,6 +4331,7 @@ summary_info += {'nettle': nettle}
if nettle.found()
summary_info += {' XTS': xts != 'private'}
endif
summary_info += {'SM4 ALG support': crypto_sm4}
summary_info += {'AF_ALG support': have_afalg}
summary_info += {'rng-none': get_option('rng_none')}
summary_info += {'Linux keyring': have_keyring}
Expand Down
5 changes: 4 additions & 1 deletion qapi/crypto.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
#
# @twofish-256: Twofish with 256 bit / 32 byte keys
#
# @sm4: SM4 with 128 bit / 16 byte keys (since 9.0)
#
# Since: 2.6
##
{ 'enum': 'QCryptoCipherAlgorithm',
Expand All @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test-crypto-cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,19 @@ static QCryptoCipherTestData test_data[] = {
.plaintext = "90afe91bb288544f2c32dc239b2635e6",
.ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
},
#ifdef CONFIG_CRYPTO_SM4
{
/* 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",
},
#endif
{
/* #1 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-1",
Expand Down

0 comments on commit 52ed9f4

Please sign in to comment.