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