/* * Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2017 Ribose Inc. All Rights Reserved. * Ported from Ribose contributions from Botan. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include "internal/deprecated.h" #include "internal/cryptlib.h" #ifndef OPENSSL_NO_SM4 # include # include # include "crypto/sm4.h" # include "crypto/evp.h" # include "crypto/sm4_platform.h" # include "evp_local.h" typedef struct { union { OSSL_UNION_ALIGN; SM4_KEY ks; } ks; block128_f block; union { ecb128_f ecb; cbc128_f cbc; ctr128_f ctr; } stream; } EVP_SM4_KEY; # define BLOCK_CIPHER_generic(nid,blocksize,ivlen,nmode,mode,MODE,flags) \ static const EVP_CIPHER sm4_##mode = { \ nid##_##nmode,blocksize,128/8,ivlen, \ flags|EVP_CIPH_##MODE##_MODE, \ EVP_ORIG_GLOBAL, \ sm4_init_key, \ sm4_##mode##_cipher, \ NULL, \ sizeof(EVP_SM4_KEY), \ NULL,NULL,NULL,NULL }; \ const EVP_CIPHER *EVP_sm4_##mode(void) \ { return &sm4_##mode; } #define DEFINE_BLOCK_CIPHERS(nid,flags) \ BLOCK_CIPHER_generic(nid,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \ BLOCK_CIPHER_generic(nid,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \ BLOCK_CIPHER_generic(nid,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \ BLOCK_CIPHER_generic(nid,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \ BLOCK_CIPHER_generic(nid,1,16,ctr,ctr,CTR,flags) static int sm4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { int mode; EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); mode = EVP_CIPHER_CTX_get_mode(ctx); if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { #ifdef HWSM4_CAPABLE if (HWSM4_CAPABLE) { HWSM4_set_decrypt_key(key, &dat->ks.ks); dat->block = (block128_f) HWSM4_decrypt; dat->stream.cbc = NULL; # ifdef HWSM4_cbc_encrypt if (mode == EVP_CIPH_CBC_MODE) dat->stream.cbc = (cbc128_f) HWSM4_cbc_encrypt; # endif # ifdef HWSM4_ecb_encrypt if (mode == EVP_CIPH_ECB_MODE) dat->stream.ecb = (ecb128_f) HWSM4_ecb_encrypt; # endif } else #endif #ifdef VPSM4_CAPABLE if (VPSM4_CAPABLE) { vpsm4_set_decrypt_key(key, &dat->ks.ks); dat->block = (block128_f) vpsm4_decrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) dat->stream.cbc = (cbc128_f) vpsm4_cbc_encrypt; else if (mode == EVP_CIPH_ECB_MODE) dat->stream.ecb = (ecb128_f) vpsm4_ecb_encrypt; } else #endif { dat->block = (block128_f) ossl_sm4_decrypt; ossl_sm4_set_key(key, EVP_CIPHER_CTX_get_cipher_data(ctx)); } } else #ifdef HWSM4_CAPABLE if (HWSM4_CAPABLE) { HWSM4_set_encrypt_key(key, &dat->ks.ks); dat->block = (block128_f) HWSM4_encrypt; dat->stream.cbc = NULL; # ifdef HWSM4_cbc_encrypt if (mode == EVP_CIPH_CBC_MODE) dat->stream.cbc = (cbc128_f) HWSM4_cbc_encrypt; else # endif # ifdef HWSM4_ecb_encrypt if (mode == EVP_CIPH_ECB_MODE) dat->stream.ecb = (ecb128_f) HWSM4_ecb_encrypt; else # endif # ifdef HWSM4_ctr32_encrypt_blocks if (mode == EVP_CIPH_CTR_MODE) dat->stream.ctr = (ctr128_f) HWSM4_ctr32_encrypt_blocks; else # endif (void)0; /* terminate potentially open 'else' */ } else #endif #ifdef VPSM4_CAPABLE if (VPSM4_CAPABLE) { vpsm4_set_encrypt_key(key, &dat->ks.ks); dat->block = (block128_f) vpsm4_encrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) dat->stream.cbc = (cbc128_f) vpsm4_cbc_encrypt; else if (mode == EVP_CIPH_ECB_MODE) dat->stream.ecb = (ecb128_f) vpsm4_ecb_encrypt; else if (mode == EVP_CIPH_CTR_MODE) dat->stream.ctr = (ctr128_f) vpsm4_ctr32_encrypt_blocks; } else #endif { dat->block = (block128_f) ossl_sm4_encrypt; ossl_sm4_set_key(key, EVP_CIPHER_CTX_get_cipher_data(ctx)); } return 1; } static int sm4_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) { EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); if (dat->stream.cbc) (*dat->stream.cbc) (in, out, len, &dat->ks.ks, ctx->iv, EVP_CIPHER_CTX_is_encrypting(ctx)); else if (EVP_CIPHER_CTX_is_encrypting(ctx)) CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block); else CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block); return 1; } static int sm4_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) { EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); int num = EVP_CIPHER_CTX_get_num(ctx); CRYPTO_cfb128_encrypt(in, out, len, &dat->ks, ctx->iv, &num, EVP_CIPHER_CTX_is_encrypting(ctx), dat->block); EVP_CIPHER_CTX_set_num(ctx, num); return 1; } static int sm4_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) { size_t bl = EVP_CIPHER_CTX_get_block_size(ctx); size_t i; EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); if (len < bl) return 1; if (dat->stream.ecb != NULL) (*dat->stream.ecb) (in, out, len, &dat->ks.ks, EVP_CIPHER_CTX_is_encrypting(ctx)); else for (i = 0, len -= bl; i <= len; i += bl) (*dat->block) (in + i, out + i, &dat->ks); return 1; } static int sm4_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) { EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); int num = EVP_CIPHER_CTX_get_num(ctx); CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, ctx->iv, &num, dat->block); EVP_CIPHER_CTX_set_num(ctx, num); return 1; } static int sm4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) { int n = EVP_CIPHER_CTX_get_num(ctx); unsigned int num; EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx); if (n < 0) return 0; num = (unsigned int)n; if (dat->stream.ctr) CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, EVP_CIPHER_CTX_buf_noconst(ctx), &num, dat->stream.ctr); else CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, EVP_CIPHER_CTX_buf_noconst(ctx), &num, dat->block); EVP_CIPHER_CTX_set_num(ctx, num); return 1; } DEFINE_BLOCK_CIPHERS(NID_sm4, 0) #endif