Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SM4 XTS implementation to providers #19619

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion crypto/modes/build.info
Expand Up @@ -52,7 +52,7 @@ IF[{- !$disabled{asm} -}]
ENDIF

$COMMON=cbc128.c ctr128.c cfb128.c ofb128.c gcm128.c ccm128.c xts128.c \
wrap128.c $MODESASM
wrap128.c xts128gb.c $MODESASM
SOURCE[../../libcrypto]=$COMMON \
cts128.c ocb128.c siv128.c
SOURCE[../../providers/libfips.a]=$COMMON
Expand Down
199 changes: 199 additions & 0 deletions crypto/modes/xts128gb.c
@@ -0,0 +1,199 @@
/*
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
*
* 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 <string.h>
#include <openssl/crypto.h>
#include "internal/endian.h"
#include "crypto/modes.h"

#ifndef STRICT_ALIGNMENT
# ifdef __GNUC__
typedef u64 u64_a1 __attribute((__aligned__(1)));
# else
typedef u64 u64_a1;
# endif
#endif

int ossl_crypto_xts128gb_encrypt(const XTS128_CONTEXT *ctx,
const unsigned char iv[16],
const unsigned char *inp, unsigned char *out,
size_t len, int enc)
{
DECLARE_IS_ENDIAN;
union {
u64 u[2];
u32 d[4];
u8 c[16];
} tweak, scratch;
unsigned int i;

if (len < 16)
return -1;

memcpy(tweak.c, iv, 16);

(*ctx->block2) (tweak.c, tweak.c, ctx->key2);

if (!enc && (len % 16))
len -= 16;

while (len >= 16) {
#if defined(STRICT_ALIGNMENT)
memcpy(scratch.c, inp, 16);
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
#else
scratch.u[0] = ((u64_a1 *)inp)[0] ^ tweak.u[0];
scratch.u[1] = ((u64_a1 *)inp)[1] ^ tweak.u[1];
#endif
(*ctx->block1) (scratch.c, scratch.c, ctx->key1);
#if defined(STRICT_ALIGNMENT)
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
memcpy(out, scratch.c, 16);
#else
((u64_a1 *)out)[0] = scratch.u[0] ^= tweak.u[0];
((u64_a1 *)out)[1] = scratch.u[1] ^= tweak.u[1];
#endif
inp += 16;
out += 16;
len -= 16;

if (len == 0)
return 0;

if (IS_LITTLE_ENDIAN) {
u8 res;
u64 hi, lo;
#ifdef BSWAP8
hi = BSWAP8(tweak.u[0]);
lo = BSWAP8(tweak.u[1]);
#else
u8 *p = tweak.c;

hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
#endif
res = (u8)lo & 1;
tweak.u[0] = (lo >> 1) | (hi << 63);
tweak.u[1] = hi >> 1;
if (res)
tweak.c[15] ^= 0xe1;
#ifdef BSWAP8
hi = BSWAP8(tweak.u[0]);
lo = BSWAP8(tweak.u[1]);
#else
p = tweak.c;

hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
#endif
tweak.u[0] = lo;
tweak.u[1] = hi;
} else {
u8 carry, res;
carry = 0;
for (i = 0; i < 16; ++i) {
res = (tweak.c[i] << 7) & 0x80;
tweak.c[i] = ((tweak.c[i] >> 1) + carry) & 0xff;
carry = res;
}
if (res)
tweak.c[0] ^= 0xe1;
}
}
if (enc) {
for (i = 0; i < len; ++i) {
u8 c = inp[i];
out[i] = scratch.c[i];
scratch.c[i] = c;
}
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
(*ctx->block1) (scratch.c, scratch.c, ctx->key1);
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
memcpy(out - 16, scratch.c, 16);
} else {
union {
u64 u[2];
u8 c[16];
} tweak1;

if (IS_LITTLE_ENDIAN) {
u8 res;
u64 hi, lo;
#ifdef BSWAP8
hi = BSWAP8(tweak.u[0]);
lo = BSWAP8(tweak.u[1]);
#else
u8 *p = tweak.c;

hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
#endif
res = (u8)lo & 1;
tweak1.u[0] = (lo >> 1) | (hi << 63);
tweak1.u[1] = hi >> 1;
if (res)
tweak1.c[15] ^= 0xe1;
#ifdef BSWAP8
hi = BSWAP8(tweak1.u[0]);
lo = BSWAP8(tweak1.u[1]);
#else
p = tweak1.c;

hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
#endif
tweak1.u[0] = lo;
tweak1.u[1] = hi;
} else {
u8 carry, res;
carry = 0;
for (i = 0; i < 16; ++i) {
res = (tweak.c[i] << 7) & 0x80;
tweak1.c[i] = ((tweak.c[i] >> 1) + carry) & 0xff;
carry = res;
}
if (res)
tweak1.c[0] ^= 0xe1;
}
#if defined(STRICT_ALIGNMENT)
memcpy(scratch.c, inp, 16);
scratch.u[0] ^= tweak1.u[0];
scratch.u[1] ^= tweak1.u[1];
#else
scratch.u[0] = ((u64_a1 *)inp)[0] ^ tweak1.u[0];
scratch.u[1] = ((u64_a1 *)inp)[1] ^ tweak1.u[1];
#endif
(*ctx->block1) (scratch.c, scratch.c, ctx->key1);
scratch.u[0] ^= tweak1.u[0];
scratch.u[1] ^= tweak1.u[1];

for (i = 0; i < len; ++i) {
u8 c = inp[16 + i];
out[16 + i] = scratch.c[i];
scratch.c[i] = c;
}
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
(*ctx->block1) (scratch.c, scratch.c, ctx->key1);
#if defined(STRICT_ALIGNMENT)
scratch.u[0] ^= tweak.u[0];
scratch.u[1] ^= tweak.u[1];
memcpy(out, scratch.c, 16);
#else
((u64_a1 *)out)[0] = scratch.u[0] ^ tweak.u[0];
((u64_a1 *)out)[1] = scratch.u[1] ^ tweak.u[1];
#endif
}

return 0;
}
15 changes: 10 additions & 5 deletions crypto/objects/obj_dat.h
Expand Up @@ -10,7 +10,7 @@
*/

/* Serialized OID's */
static const unsigned char so[8356] = {
static const unsigned char so[8364] = {
0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 0] OBJ_rsadsi */
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 6] OBJ_pkcs */
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02, /* [ 13] OBJ_md2 */
Expand Down Expand Up @@ -1152,9 +1152,10 @@ static const unsigned char so[8356] = {
0x60,0x86,0x48,0x01,0x86,0xF9,0x66, /* [ 8325] OBJ_oracle */
0x60,0x86,0x48,0x01,0x86,0xF9,0x66,0xAD,0xCA,0x7B,0x01,0x01, /* [ 8332] OBJ_oracle_jdk_trustedkeyusage */
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x32, /* [ 8344] OBJ_id_ct_signedTAL */
0x2A,0x81,0x1C,0xCF,0x55,0x01,0x68,0x0A, /* [ 8355] OBJ_sm4_xts */
};

#define NUM_NID 1290
#define NUM_NID 1291
static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"UNDEF", "undefined", NID_undef},
{"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
Expand Down Expand Up @@ -2446,9 +2447,10 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"brainpoolP512r1tls13", "brainpoolP512r1tls13", NID_brainpoolP512r1tls13},
{"brotli", "Brotli compression", NID_brotli},
{"zstd", "Zstandard compression", NID_zstd},
{"SM4-XTS", "sm4-xts", NID_sm4_xts, 8, &so[8355]},
};

#define NUM_SN 1281
#define NUM_SN 1282
static const unsigned int sn_objs[NUM_SN] = {
364, /* "AD_DVCS" */
419, /* "AES-128-CBC" */
Expand Down Expand Up @@ -2735,6 +2737,7 @@ static const unsigned int sn_objs[NUM_SN] = {
1133, /* "SM4-ECB" */
1248, /* "SM4-GCM" */
1135, /* "SM4-OFB" */
1290, /* "SM4-XTS" */
188, /* "SMIME" */
167, /* "SMIME-CAPS" */
100, /* "SN" */
Expand Down Expand Up @@ -3733,7 +3736,7 @@ static const unsigned int sn_objs[NUM_SN] = {
1289, /* "zstd" */
};

#define NUM_LN 1281
#define NUM_LN 1282
static const unsigned int ln_objs[NUM_LN] = {
363, /* "AD Time Stamping" */
405, /* "ANSI X9.62" */
Expand Down Expand Up @@ -4966,6 +4969,7 @@ static const unsigned int ln_objs[NUM_LN] = {
1133, /* "sm4-ecb" */
1248, /* "sm4-gcm" */
1135, /* "sm4-ofb" */
1290, /* "sm4-xts" */
1203, /* "sshkdf" */
1205, /* "sskdf" */
16, /* "stateOrProvinceName" */
Expand Down Expand Up @@ -5018,7 +5022,7 @@ static const unsigned int ln_objs[NUM_LN] = {
125, /* "zlib compression" */
};

#define NUM_OBJ 1147
#define NUM_OBJ 1148
static const unsigned int obj_objs[NUM_OBJ] = {
0, /* OBJ_undef 0 */
181, /* OBJ_iso 1 */
Expand Down Expand Up @@ -5514,6 +5518,7 @@ static const unsigned int obj_objs[NUM_OBJ] = {
1139, /* OBJ_sm4_ctr 1 2 156 10197 1 104 7 */
1248, /* OBJ_sm4_gcm 1 2 156 10197 1 104 8 */
1249, /* OBJ_sm4_ccm 1 2 156 10197 1 104 9 */
1290, /* OBJ_sm4_xts 1 2 156 10197 1 104 10 */
1172, /* OBJ_sm2 1 2 156 10197 1 301 */
1143, /* OBJ_sm3 1 2 156 10197 1 401 */
1204, /* OBJ_SM2_with_SM3 1 2 156 10197 1 501 */
Expand Down
1 change: 1 addition & 0 deletions crypto/objects/obj_mac.num
Expand Up @@ -1287,3 +1287,4 @@ brainpoolP384r1tls13 1286
brainpoolP512r1tls13 1287
brotli 1288
zstd 1289
sm4_xts 1290
1 change: 1 addition & 0 deletions crypto/objects/objects.txt
Expand Up @@ -1611,6 +1611,7 @@ sm-scheme 104 6 : SM4-CFB8 : sm4-cfb8
sm-scheme 104 7 : SM4-CTR : sm4-ctr
sm-scheme 104 8 : SM4-GCM : sm4-gcm
sm-scheme 104 9 : SM4-CCM : sm4-ccm
sm-scheme 104 10 : SM4-XTS : sm4-xts

# There is no OID that just denotes "HMAC" oddly enough...

Expand Down
34 changes: 34 additions & 0 deletions doc/man3/EVP_EncryptInit.pod
Expand Up @@ -993,6 +993,40 @@ Byte 11-12: Input length (Always 0)

"tls1multi_interleave" must also be set for this operation.

=item "xts_standard" (B<OSSL_CIPHER_PARAM_XTS_STANDARD>) <UTF8 string>

Sets the XTS standard to use with SM4-XTS algorithm. XTS mode has two
implementations, one is standardized in IEEE Std. 1619-2007 and has
been widely used (e.g., XTS AES), the other is proposed recently
(GB/T 17964-2021 implemented in May 2022) and is currently only used
in SM4.

The main difference between them is the multiplication by the
primitive element E<alpha> to calculate the tweak values. The IEEE
Std 1619-2007 noted that the multiplication "is a left shift of each
byte by one bit with carry propagating from one byte to the next
one", which means that in each byte, the leftmost bit is the most
significant bit. But in GB/T 17964-2021, the rightmost bit is the
most significant bit, thus the multiplication becomes a right shift
of each byte by one bit with carry propagating from one byte to the
next one.

Valid values for the mode are:

=over 4

=item "GB"

The GB/T 17964-2021 variant of SM4-XTS algorithm.

=item "IEEE"

The IEEE Std. 1619-2007 variant of SM4-XTS algorithm.

=back

The default value is "GB".

=back

=head1 CONTROLS
Expand Down
6 changes: 6 additions & 0 deletions doc/man7/EVP_CIPHER-SM4.pod
Expand Up @@ -24,6 +24,12 @@ The following algorithms are available in the default provider:

=item "SM4-CFB" or "SM4-CFB128"

=item "SM4-GCM"

=item "SM4-CCM"

=item "SM4-XTS"

=back

=head2 Parameters
Expand Down
1 change: 1 addition & 0 deletions fuzz/oids.txt
Expand Up @@ -1148,3 +1148,4 @@ OBJ_hmacWithSM3="\x2A\x81\x1C\xCF\x55\x01\x83\x11\x03\x01"
OBJ_oracle="\x60\x86\x48\x01\x86\xF9\x66"
OBJ_oracle_jdk_trustedkeyusage="\x60\x86\x48\x01\x86\xF9\x66\xAD\xCA\x7B\x01\x01"
OBJ_id_ct_signedTAL="\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x01\x32"
OBJ_sm4_xts="\x2A\x81\x1C\xCF\x55\x01\x68\x0A"
6 changes: 6 additions & 0 deletions include/crypto/modes.h
Expand Up @@ -155,6 +155,12 @@ struct xts128_context {
block128_f block1, block2;
};

/* XTS mode for SM4 algorithm specified by GB/T 17964-2021 */
int ossl_crypto_xts128gb_encrypt(const XTS128_CONTEXT *ctx,
const unsigned char iv[16],
const unsigned char *inp, unsigned char *out,
size_t len, int enc);

struct ccm128_context {
union {
u64 u[2];
Expand Down
1 change: 1 addition & 0 deletions include/openssl/core_names.h
Expand Up @@ -97,6 +97,7 @@ extern "C" {
#define OSSL_CIPHER_PARAM_CTS_MODE "cts_mode" /* utf8_string */
/* For passing the AlgorithmIdentifier parameter in DER form */
#define OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS "alg_id_param" /* octet_string */
#define OSSL_CIPHER_PARAM_XTS_STANDARD "xts_standard" /* utf8_string */

#define OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT \
"tls1multi_maxsndfrag" /* uint */
Expand Down
5 changes: 5 additions & 0 deletions include/openssl/obj_mac.h
Expand Up @@ -5094,6 +5094,11 @@
#define NID_sm4_ccm 1249
#define OBJ_sm4_ccm OBJ_sm_scheme,104L,9L

#define SN_sm4_xts "SM4-XTS"
#define LN_sm4_xts "sm4-xts"
#define NID_sm4_xts 1290
#define OBJ_sm4_xts OBJ_sm_scheme,104L,10L

#define SN_hmac "HMAC"
#define LN_hmac "hmac"
#define NID_hmac 855
Expand Down
1 change: 1 addition & 0 deletions providers/defltprov.c
Expand Up @@ -304,6 +304,7 @@ static const OSSL_ALGORITHM_CAPABLE deflt_ciphers[] = {
ALG(PROV_NAMES_SM4_CTR, ossl_sm4128ctr_functions),
ALG(PROV_NAMES_SM4_OFB, ossl_sm4128ofb128_functions),
ALG(PROV_NAMES_SM4_CFB, ossl_sm4128cfb128_functions),
ALG(PROV_NAMES_SM4_XTS, ossl_sm4128xts_functions),
#endif /* OPENSSL_NO_SM4 */
#ifndef OPENSSL_NO_CHACHA
ALG(PROV_NAMES_ChaCha20, ossl_chacha20_functions),
Expand Down