Skip to content

Commit

Permalink
Add sm3-yescrypt backend and tests.
Browse files Browse the repository at this point in the history
sm3-yescrypt uses the output from the yescrypt hashing method in
place of a hmac message.  Thus, the yescrypt crypto properties
are superseeded by the ShangMi 3 hash function with a 256 bit
digest.

This hashing method is useful in applications that need modern
password hashing methods, but require to rely on cryptographic
properties that have been approved by the Chinese Office of State
Commercial Cryptography Administration (OSCCA).

ShangMi 3 is a cryptographic hash function used in the Chinese
National Standard.  It was published by the National Cryptography
Administration (Chinese: 国家密码管理局) on 2010-12-17 as
"GM/T 0004-2012: SM3 cryptographic hash algorithm".

SM3 is used for implementing digital signatures, message
authentication codes, and pseudorandom number generators.  The
algorithm is public and is considered similar to SHA-256 in
security and efficiency.
SM3 is also used with Transport Layer Security.

SM3 is defined in each of:

  * GM/T 0004-2012:   SM3 cryptographic hash algorithm
  * GB/T 32905-2016:  Information security techniques
                      SM3 cryptographic hash algorithm
  * ISO/IEC 10118-3:2018:
                      IT Security techniques—Hash-functions
                      Part 3: Dedicated hash-functions
  * IETF RFC draft-sca-cfrg-sm3-02

See:  https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3
  • Loading branch information
besser82 committed Nov 27, 2024
1 parent f002d3f commit 0bbc21b
Show file tree
Hide file tree
Showing 22 changed files with 1,178 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ test/alg-sha1
test/alg-sha256
test/alg-sha512
test/alg-sm3
test/alg-sm3-hmac
test/alg-yescrypt
test/badsalt
test/badsetting
Expand All @@ -77,6 +78,7 @@ test/crypt-pbkdf1-sha1
test/crypt-scrypt
test/crypt-sha256
test/crypt-sha512
test/crypt-sm3-yescrypt
test/crypt-sunmd5
test/crypt-yescrypt
test/des-obsolete
Expand All @@ -103,6 +105,7 @@ test/ka-sha1crypt
test/ka-sha256crypt
test/ka-sha512crypt
test/ka-sm3crypt
test/ka-sm3-yescrypt
test/ka-sunmd5
test/ka-yescrypt
test/preferred-method
Expand Down
5 changes: 3 additions & 2 deletions LICENSING
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ source tree. For specific licensing terms consult the files themselves.
crypt-scrypt.c

* Copyright Björn Esser; 0-clause BSD:
crypt-common.c, test-checksalt.c, test-compile-strong-alias.c,
test-gensalt-nthash.c, test-short-outbuf.c, test-special-char-salt.c
alg-sm3-hmac.h, alg-sm3-hmac.c, crypt-sm3-yescrypt.c, crypt-common.c,
test-checksalt.c, test-compile-strong-alias.c, test-gensalt-nthash.c,
test-short-outbuf.c, test-special-char-salt.c

* Copyright Michael Bretterklieber, Björn Esser et al.; 2-clause BSD:
crypt-nthash.c
Expand Down
25 changes: 25 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ noinst_HEADERS = \
lib/alg-sha256.h \
lib/alg-sha512.h \
lib/alg-sm3.h \
lib/alg-sm3-hmac.h \
lib/alg-yescrypt.h \
lib/byteorder.h \
lib/crypt-obsolete.h \
Expand Down Expand Up @@ -110,12 +111,14 @@ libcrypt_la_SOURCES = \
lib/alg-sha256.c \
lib/alg-sha512.c \
lib/alg-sm3.c \
lib/alg-sm3-hmac.c \
lib/alg-yescrypt-common.c \
lib/alg-yescrypt-opt.c \
lib/crypt-bcrypt.c \
lib/crypt-des.c \
lib/crypt-gensalt-static.c \
lib/crypt-gost-yescrypt.c \
lib/crypt-sm3-yescrypt.c \
lib/crypt-md5.c \
lib/crypt-nthash.c \
lib/crypt-pbkdf1-sha1.c \
Expand Down Expand Up @@ -360,6 +363,7 @@ check_PROGRAMS = \
test/ka-sha256crypt \
test/ka-sha512crypt \
test/ka-sm3crypt \
test/ka-sm3-yescrypt \
test/ka-sunmd5 \
test/ka-yescrypt \
test/alg-des \
Expand All @@ -373,6 +377,7 @@ check_PROGRAMS = \
test/alg-sha256 \
test/alg-sha512 \
test/alg-sm3 \
test/alg-sm3-hmac \
test/alg-yescrypt \
test/badsalt \
test/badsetting \
Expand All @@ -381,6 +386,7 @@ check_PROGRAMS = \
test/compile-strong-alias \
test/crypt-badargs \
test/crypt-gost-yescrypt \
test/crypt-sm3-yescrypt \
test/crypt-multithread \
test/explicit-bzero \
test/gensalt \
Expand Down Expand Up @@ -409,6 +415,7 @@ test_ka_sha1crypt_SOURCES = test/ka-tester.c
test_ka_sha256crypt_SOURCES = test/ka-tester.c
test_ka_sha512crypt_SOURCES = test/ka-tester.c
test_ka_sm3crypt_SOURCES = test/ka-tester.c
test_ka_sm3_yescrypt_SOURCES = test/ka-tester.c
test_ka_sunmd5_SOURCES = test/ka-tester.c
test_ka_yescrypt_SOURCES = test/ka-tester.c

Expand All @@ -427,6 +434,7 @@ test_ka_sha1crypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sha1crypt
test_ka_sha256crypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sha256crypt
test_ka_sha512crypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sha512crypt
test_ka_sm3crypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sm3crypt
test_ka_sm3_yescrypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sm3_yescrypt
test_ka_sunmd5_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_sunmd5
test_ka_yescrypt_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_yescrypt

Expand Down Expand Up @@ -521,6 +529,7 @@ test_ka_sha1crypt_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_sha256crypt_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_sha512crypt_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_sm3crypt_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_sm3_yescrypt_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_sunmd5_LDADD = $(COMMON_TEST_OBJECTS)
test_ka_yescrypt_LDADD = $(COMMON_TEST_OBJECTS)

Expand Down Expand Up @@ -579,6 +588,11 @@ test_alg_sm3_LDADD = \
lib/libcrypt_la-alg-sm3.lo \
lib/libcrypt_la-util-xbzero.lo \
$(COMMON_TEST_OBJECTS)
test_alg_sm3_hmac_LDADD = \
lib/libcrypt_la-alg-sm3.lo \
lib/libcrypt_la-alg-sm3-hmac.lo \
lib/libcrypt_la-util-xbzero.lo \
$(COMMON_TEST_OBJECTS)
test_alg_yescrypt_LDADD = \
lib/libcrypt_la-alg-sha256.lo \
lib/libcrypt_la-alg-yescrypt-common.lo \
Expand All @@ -597,6 +611,17 @@ test_crypt_gost_yescrypt_LDADD = \
lib/libcrypt_la-util-xbzero.lo \
lib/libcrypt_la-util-xstrcpy.lo \
$(COMMON_TEST_OBJECTS)
test_crypt_sm3_yescrypt_LDADD = \
lib/libcrypt_la-alg-sm3.lo \
lib/libcrypt_la-alg-sm3-hmac.lo \
lib/libcrypt_la-alg-sha256.lo \
lib/libcrypt_la-alg-yescrypt-common.lo \
lib/libcrypt_la-alg-yescrypt-opt.lo \
lib/libcrypt_la-crypt-yescrypt.lo \
lib/libcrypt_la-util-base64.lo \
lib/libcrypt_la-util-xbzero.lo \
lib/libcrypt_la-util-xstrcpy.lo \
$(COMMON_TEST_OBJECTS)

test_explicit_bzero_LDADD = \
lib/libcrypt_la-util-xbzero.lo
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ README for libxcrypt

libxcrypt is a modern library for one-way hashing of passwords. It
supports a wide variety of both modern and historical hashing methods:
yescrypt, gost-yescrypt, scrypt, bcrypt, sha512crypt, sha256crypt,
sm3crypt, md5crypt, SunMD5, sha1crypt, NT, bsdicrypt, bigcrypt,
and descrypt.
yescrypt, gost-yescrypt, sm3-yescrypt, scrypt, bcrypt, sha512crypt,
sha256crypt, sm3crypt, md5crypt, SunMD5, sha1crypt, NT, bsdicrypt,
bigcrypt, and descrypt.
It provides the traditional Unix `crypt` and `crypt_r` interfaces, as
well as a set of extended interfaces pioneered by Openwall Linux,
`crypt_rn`, `crypt_ra`, `crypt_gensalt`, `crypt_gensalt_rn`, and
Expand Down
12 changes: 12 additions & 0 deletions doc/crypt.5
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ The GOST R 34.11-2012 (Streebog) hash function has been published by the IETF
as RFC 6986.
Acceptable for new hashes where required.
.hash "$gy$" "\e$gy\e$[./A-Za-z0-9]+\e$[./A-Za-z0-9]{,86}\e$[./A-Za-z0-9]{43}" unlimited 8 256 256 "up to 512 (128+ recommended)" "1 to 11 (logarithmic, also affects memory usage)"
.Ss sm3-yescrypt
sm3-yescrypt uses the output from yescrypt as an input message to HMAC with
the ShangMi 3 hash function with a 256-bit digest.
Thus, yescrypt's cryptographic properties are superseded by those of the
ShangMi 3 hash function.
This hashing method is useful in applications that need modern passphrase
hashing, but have to rely on algorithms approved by the Chinese Office of
State Commercial Cryptography Administration (OSCCA).
The ShangMi 3 hash function has been published in Part 3: "Dedicated
hash-functions" of the ISO/IEC 10118-3:2018.
Acceptable for new hashes where required.
.hash "$sm3y$" "\e$sm3y\e$[./A-Za-z0-9]+\e$[./A-Za-z0-9]{,86}\e$[./A-Za-z0-9]{43}" unlimited 8 256 256 "up to 512 (128+ recommended)" "1 to 11 (logarithmic, also affects memory usage)"
.Ss scrypt
scrypt is a password-based key derivation function created by Colin Percival,
originally for the Tarsnap online backup service.
Expand Down
119 changes: 119 additions & 0 deletions lib/alg-sm3-hmac.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/* Copyright (C) 2024 Björn Esser <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include "crypt-port.h"

#if INCLUDE_sm3crypt

#include <string.h>
#include "alg-sm3-hmac.h"

/**
* HMAC_k(m) = H((k ^ opad), H((k ^ ipad), m))
* pseudo-code:
* function hmac(key, message)
* opad = [0x5c * blocksize]
* ipad = [0x36 * blocksize]
* if (length(key) > blocksize) then
* key = hash(key)
* end if
* for i from 0 to length(key) - 1 step 1
* ipad[i] = ipad[i] XOR key[i]
* opad[i] = opad[i] XOR key[i]
* end for
* return hash(opad || hash(ipad || message))
* end function
*/

#define IPAD 0x36
#define OPAD 0x5C

void
sm3_hmac_init (sm3_hmac_ctx_t *ctx, const uint8_t *key, size_t key_len)
{
int i;

if (key_len <= SM3_BLOCK_SIZE)
{
memcpy (ctx->key, key, key_len);
explicit_bzero (ctx->key + key_len, SM3_BLOCK_SIZE - key_len);
}
else
{
sm3_init (&ctx->sm3_ctx);
sm3_update (&ctx->sm3_ctx, key, key_len);
sm3_final (ctx->key, &ctx->sm3_ctx);
explicit_bzero (ctx->key + SM3_DIGEST_SIZE,
SM3_BLOCK_SIZE - SM3_DIGEST_SIZE);
}
for (i = 0; i < SM3_BLOCK_SIZE; i++)
{
ctx->key[i] ^= IPAD;
}

sm3_init (&ctx->sm3_ctx);
sm3_update (&ctx->sm3_ctx, ctx->key, SM3_BLOCK_SIZE);
}

void
sm3_hmac_update (sm3_hmac_ctx_t *ctx, const uint8_t *data, size_t data_len)
{
sm3_update (&ctx->sm3_ctx, data, data_len);
}

void
sm3_hmac_final (sm3_hmac_ctx_t *ctx, uint8_t mac[SM3_HMAC_MAC_SIZE])
{
int i;
for (i = 0; i < SM3_BLOCK_SIZE; i++)
{
ctx->key[i] ^= (IPAD ^ OPAD);
}
sm3_final (mac, &ctx->sm3_ctx);
sm3_init (&ctx->sm3_ctx);
sm3_update (&ctx->sm3_ctx, ctx->key, SM3_BLOCK_SIZE);
sm3_update (&ctx->sm3_ctx, mac, SM3_DIGEST_SIZE);
sm3_final (mac, &ctx->sm3_ctx);

/* Zeroize sensitive information. */
explicit_bzero (&ctx, sizeof (ctx));
}

void
sm3_hmac (const unsigned char *data, size_t data_len,
const uint8_t *key, size_t key_len,
uint8_t mac[SM3_HMAC_MAC_SIZE], sm3_hmac_ctx_t *ctx)
{
sm3_hmac_init (ctx, key, key_len);
sm3_hmac_update (ctx, data, data_len);
sm3_hmac_final (ctx, mac);

/* Zeroize sensitive information. */
explicit_bzero (ctx, sizeof (sm3_hmac_ctx_t));
}

void
sm3_hmac_buf (const unsigned char *data, size_t data_len,
const uint8_t *key, size_t key_len,
uint8_t mac[SM3_HMAC_MAC_SIZE])
{
sm3_hmac_ctx_t ctx;
sm3_hmac (data, data_len, key, key_len, mac, &ctx);
}

#endif /* INCLUDE_sm3_yescrypt */
44 changes: 44 additions & 0 deletions lib/alg-sm3-hmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* Copyright (C) 2024 Björn Esser <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#ifndef _CRYPT_ALG_SM3_HMAC_H
#define _CRYPT_ALG_SM3_HMAC_H

#include "alg-sm3.h"

#define SM3_HMAC_MAC_SIZE SM3_DIGEST_SIZE

typedef struct
{
sm3_ctx sm3_ctx;
uint8_t key[SM3_BLOCK_SIZE];
} sm3_hmac_ctx_t;

void sm3_hmac_init (sm3_hmac_ctx_t * ctx, const uint8_t * key,
size_t key_len);
void sm3_hmac_update (sm3_hmac_ctx_t * ctx, const uint8_t * data,
size_t data_len);
void sm3_hmac_final (sm3_hmac_ctx_t * ctx, uint8_t mac[SM3_HMAC_MAC_SIZE]);
void sm3_hmac (const uint8_t * data, size_t data_len,
const uint8_t * key, size_t key_len,
uint8_t mac[SM3_HMAC_MAC_SIZE], sm3_hmac_ctx_t * ctx);
void sm3_hmac_buf (const uint8_t * data, size_t data_len,
const uint8_t * key, size_t key_len,
uint8_t mac[SM3_HMAC_MAC_SIZE]);

#endif /* _CRYPT_ALG_SM3_HMAC_H */
17 changes: 13 additions & 4 deletions lib/crypt-port.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ extern size_t strcpy_or_abort (void *dst, size_t d_size, const void *src);
#define sm3_init _crypt_sm3_init
#define sm3_update _crypt_sm3_update
#define sm3_final _crypt_sm3_final
#define sm3_hash _crypt_sm3_hash
#define sm3_buf _crypt_sm3_buf
#endif

Expand All @@ -434,15 +435,23 @@ extern size_t strcpy_or_abort (void *dst, size_t d_size, const void *src);
#define GOST34112012Cleanup _crypt_GOST34112012_Cleanup
#define gost_hash256 _crypt_gost_hash256
#define gost_hmac256 _crypt_gost_hmac256
#endif

#if INCLUDE_sm3_yescrypt
#define sm3_hmac_buf _crypt_sm3_hmac_buf
#define sm3_hmac_final _crypt_sm3_hmac_final
#define sm3_hmac_init _crypt_sm3_hmac_init
#define sm3_hmac_update _crypt_sm3_hmac_update
#define sm3_hmac _crypt_sm3_hmac
#endif

/* Those are not present, if gost-yescrypt is selected,
but yescrypt is not. */
#if !INCLUDE_yescrypt
/* Those are not present, if gost-yescrypt or sm3-yescrypt
is selected, but yescrypt is not. */
#if !INCLUDE_yescrypt && (INCLUDE_gost_yescrypt || INCLUDE_sm3_yescrypt)
#define gensalt_yescrypt_rn _crypt_gensalt_yescrypt_rn
extern void gensalt_yescrypt_rn
(unsigned long, const uint8_t *, size_t, uint8_t *, size_t);
#endif
#endif

/* Those are not present, if des-big is selected, but des is not. */
#if INCLUDE_bigcrypt && !INCLUDE_descrypt
Expand Down
Loading

0 comments on commit 0bbc21b

Please sign in to comment.