1 2 /* 3 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. 4 * 5 * Licensed under the Apache License 2.0 (the "License"). You may not use 6 * this file except in compliance with the License. You can obtain a copy 7 * in the file LICENSE in the source distribution or at 8 * https://www.openssl.org/source/license.html 9 */ 10 11 /* Dispatch functions for SM4 XTS mode */ 12 13 #include <openssl/proverr.h> 14 #include "cipher_sm4_xts.h" 15 #include "prov/implementations.h" 16 #include "prov/providercommon.h" 17 18 #define SM4_XTS_FLAGS PROV_CIPHER_FLAG_CUSTOM_IV 19 #define SM4_XTS_IV_BITS 128 20 #define SM4_XTS_BLOCK_BITS 8 21 22 /* forward declarations */ 23 static OSSL_FUNC_cipher_encrypt_init_fn sm4_xts_einit; 24 static OSSL_FUNC_cipher_decrypt_init_fn sm4_xts_dinit; 25 static OSSL_FUNC_cipher_update_fn sm4_xts_stream_update; 26 static OSSL_FUNC_cipher_final_fn sm4_xts_stream_final; 27 static OSSL_FUNC_cipher_cipher_fn sm4_xts_cipher; 28 static OSSL_FUNC_cipher_freectx_fn sm4_xts_freectx; 29 static OSSL_FUNC_cipher_dupctx_fn sm4_xts_dupctx; 30 static OSSL_FUNC_cipher_set_ctx_params_fn sm4_xts_set_ctx_params; 31 static OSSL_FUNC_cipher_settable_ctx_params_fn sm4_xts_settable_ctx_params; 32 33 /*- 34 * Provider dispatch functions 35 */ 36 static int sm4_xts_init(void *vctx, const unsigned char *key, size_t keylen, 37 const unsigned char *iv, size_t ivlen, 38 const OSSL_PARAM params[], int enc) 39 { 40 PROV_SM4_XTS_CTX *xctx = (PROV_SM4_XTS_CTX *)vctx; 41 PROV_CIPHER_CTX *ctx = &xctx->base; 42 43 if (!ossl_prov_is_running()) 44 return 0; 45 46 ctx->enc = enc; 47 48 if (iv != NULL) { 49 if (!ossl_cipher_generic_initiv(vctx, iv, ivlen)) 50 return 0; 51 } 52 if (key != NULL) { 53 if (keylen != ctx->keylen) { 54 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 55 return 0; 56 } 57 if (!ctx->hw->init(ctx, key, keylen)) 58 return 0; 59 } 60 return sm4_xts_set_ctx_params(xctx, params); 61 } 62 63 static int sm4_xts_einit(void *vctx, const unsigned char *key, size_t keylen, 64 const unsigned char *iv, size_t ivlen, 65 const OSSL_PARAM params[]) 66 { 67 return sm4_xts_init(vctx, key, keylen, iv, ivlen, params, 1); 68 } 69 70 static int sm4_xts_dinit(void *vctx, const unsigned char *key, size_t keylen, 71 const unsigned char *iv, size_t ivlen, 72 const OSSL_PARAM params[]) 73 { 74 return sm4_xts_init(vctx, key, keylen, iv, ivlen, params, 0); 75 } 76 77 static void *sm4_xts_newctx(void *provctx, unsigned int mode, uint64_t flags, 78 size_t kbits, size_t blkbits, size_t ivbits) 79 { 80 PROV_SM4_XTS_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 81 82 if (ctx != NULL) { 83 ossl_cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, mode, 84 flags, ossl_prov_cipher_hw_sm4_xts(kbits), 85 NULL); 86 } 87 return ctx; 88 } 89 90 static void sm4_xts_freectx(void *vctx) 91 { 92 PROV_SM4_XTS_CTX *ctx = (PROV_SM4_XTS_CTX *)vctx; 93 94 ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); 95 OPENSSL_clear_free(ctx, sizeof(*ctx)); 96 } 97 98 static void *sm4_xts_dupctx(void *vctx) 99 { 100 PROV_SM4_XTS_CTX *in = (PROV_SM4_XTS_CTX *)vctx; 101 PROV_SM4_XTS_CTX *ret = NULL; 102 103 if (!ossl_prov_is_running()) 104 return NULL; 105 106 if (in->xts.key1 != NULL) { 107 if (in->xts.key1 != &in->ks1) 108 return NULL; 109 } 110 if (in->xts.key2 != NULL) { 111 if (in->xts.key2 != &in->ks2) 112 return NULL; 113 } 114 ret = OPENSSL_malloc(sizeof(*ret)); 115 if (ret == NULL) 116 return NULL; 117 in->base.hw->copyctx(&ret->base, &in->base); 118 return ret; 119 } 120 121 static int sm4_xts_cipher(void *vctx, unsigned char *out, size_t *outl, 122 size_t outsize, const unsigned char *in, size_t inl) 123 { 124 PROV_SM4_XTS_CTX *ctx = (PROV_SM4_XTS_CTX *)vctx; 125 126 if (!ossl_prov_is_running() 127 || ctx->xts.key1 == NULL 128 || ctx->xts.key2 == NULL 129 || !ctx->base.iv_set 130 || out == NULL 131 || in == NULL 132 || inl < SM4_BLOCK_SIZE) 133 return 0; 134 135 /* 136 * Impose a limit of 2^20 blocks per data unit as specified by 137 * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007 138 * indicated that this was a SHOULD NOT rather than a MUST NOT. 139 * NIST SP 800-38E mandates the same limit. 140 */ 141 if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * SM4_BLOCK_SIZE) { 142 ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE); 143 return 0; 144 } 145 if (ctx->xts_standard) { 146 if (ctx->stream != NULL) 147 (*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, 148 ctx->base.iv, ctx->base.enc); 149 else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl, 150 ctx->base.enc)) 151 return 0; 152 } else { 153 if (ctx->stream_gb != NULL) 154 (*ctx->stream_gb)(in, out, inl, ctx->xts.key1, ctx->xts.key2, 155 ctx->base.iv, ctx->base.enc); 156 else if (ossl_crypto_xts128gb_encrypt(&ctx->xts, ctx->base.iv, in, out, 157 inl, ctx->base.enc)) 158 return 0; 159 } 160 *outl = inl; 161 return 1; 162 } 163 164 static int sm4_xts_stream_update(void *vctx, unsigned char *out, size_t *outl, 165 size_t outsize, const unsigned char *in, 166 size_t inl) 167 { 168 PROV_SM4_XTS_CTX *ctx = (PROV_SM4_XTS_CTX *)vctx; 169 170 if (outsize < inl) { 171 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 172 return 0; 173 } 174 175 if (!sm4_xts_cipher(ctx, out, outl, outsize, in, inl)) { 176 ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); 177 return 0; 178 } 179 180 return 1; 181 } 182 183 static int sm4_xts_stream_final(void *vctx, unsigned char *out, size_t *outl, 184 size_t outsize) 185 { 186 if (!ossl_prov_is_running()) 187 return 0; 188 *outl = 0; 189 return 1; 190 } 191 192 static const OSSL_PARAM sm4_xts_known_settable_ctx_params[] = { 193 OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_XTS_STANDARD, NULL, 0), 194 OSSL_PARAM_END 195 }; 196 197 static const OSSL_PARAM *sm4_xts_settable_ctx_params(ossl_unused void *cctx, 198 ossl_unused void *provctx) 199 { 200 return sm4_xts_known_settable_ctx_params; 201 } 202 203 static int sm4_xts_set_ctx_params(void *vxctx, const OSSL_PARAM params[]) 204 { 205 PROV_SM4_XTS_CTX *xctx = (PROV_SM4_XTS_CTX *)vxctx; 206 const OSSL_PARAM *p; 207 208 if (ossl_param_is_empty(params)) 209 return 1; 210 211 /*- 212 * Sets the XTS standard to use with SM4-XTS algorithm. 213 * 214 * Must be utf8 string "GB" or "IEEE", 215 * "GB" means the GB/T 17964-2021 standard 216 * "IEEE" means the IEEE Std 1619-2007 standard 217 */ 218 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_XTS_STANDARD); 219 220 if (p != NULL) { 221 const char *xts_standard = NULL; 222 223 if (p->data_type != OSSL_PARAM_UTF8_STRING) 224 return 0; 225 226 if (!OSSL_PARAM_get_utf8_string_ptr(p, &xts_standard)) { 227 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 228 return 0; 229 } 230 if (OPENSSL_strcasecmp(xts_standard, "GB") == 0) { 231 xctx->xts_standard = 0; 232 } else if (OPENSSL_strcasecmp(xts_standard, "IEEE") == 0) { 233 xctx->xts_standard = 1; 234 } else { 235 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 236 return 0; 237 } 238 } 239 240 return 1; 241 } 242 243 #define IMPLEMENT_cipher(lcmode, UCMODE, kbits, flags) \ 244 static OSSL_FUNC_cipher_get_params_fn sm4_##kbits##_##lcmode##_get_params; \ 245 static int sm4_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ 246 { \ 247 return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ 248 flags, 2 * kbits, SM4_XTS_BLOCK_BITS,\ 249 SM4_XTS_IV_BITS); \ 250 } \ 251 static OSSL_FUNC_cipher_newctx_fn sm4_##kbits##_xts_newctx; \ 252 static void *sm4_##kbits##_xts_newctx(void *provctx) \ 253 { \ 254 return sm4_xts_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, flags, 2 * kbits, \ 255 SM4_XTS_BLOCK_BITS, SM4_XTS_IV_BITS); \ 256 } \ 257 const OSSL_DISPATCH ossl_sm4##kbits##xts_functions[] = { \ 258 { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))sm4_##kbits##_xts_newctx }, \ 259 { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))sm4_xts_einit }, \ 260 { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))sm4_xts_dinit }, \ 261 { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))sm4_xts_stream_update }, \ 262 { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))sm4_xts_stream_final }, \ 263 { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))sm4_xts_cipher }, \ 264 { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))sm4_xts_freectx }, \ 265 { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))sm4_xts_dupctx }, \ 266 { OSSL_FUNC_CIPHER_GET_PARAMS, \ 267 (void (*)(void))sm4_##kbits##_##lcmode##_get_params }, \ 268 { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ 269 (void (*)(void))ossl_cipher_generic_gettable_params }, \ 270 { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ 271 (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ 272 { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ 273 (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ 274 { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ 275 (void (*)(void))sm4_xts_set_ctx_params }, \ 276 { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ 277 (void (*)(void))sm4_xts_settable_ctx_params }, \ 278 OSSL_DISPATCH_END \ 279 } 280 /* ossl_sm4128xts_functions */ 281 IMPLEMENT_cipher(xts, XTS, 128, SM4_XTS_FLAGS); 282