From 129129e34f9d9cc28def8f1296f64b5966ef5d31 Mon Sep 17 00:00:00 2001 From: modric Date: Mon, 27 Dec 2021 16:18:44 +0800 Subject: [PATCH] add sm3 crypt support --- add-sm3-crypt-support.patch | 964 ++++++++++++++++++++++++++++++++++++ libxcrypt.spec | 9 +- 2 files changed, 972 insertions(+), 1 deletion(-) create mode 100644 add-sm3-crypt-support.patch diff --git a/add-sm3-crypt-support.patch b/add-sm3-crypt-support.patch new file mode 100644 index 0000000..622b9b4 --- /dev/null +++ b/add-sm3-crypt-support.patch @@ -0,0 +1,964 @@ +From 68260fe06c12445874cabc9e378288b49765ca71 Mon Sep 17 00:00:00 2001 +From: root +Date: Mon, 27 Dec 2021 16:01:26 +0800 +Subject: [PATCH] add sm3 crypt support + +--- + Makefile.am | 7 + + lib/alg-sm3.c | 408 ++++++++++++++++++++++++++++++++++++++++++++ + lib/alg-sm3.h | 62 +++++++ + lib/crypt-port.h | 9 +- + lib/crypt-sm3.c | 357 ++++++++++++++++++++++++++++++++++++++ + lib/hashes.conf | 1 + + libxcrypt.spec.rpkg | 2 +- + 7 files changed, 844 insertions(+), 2 deletions(-) + create mode 100644 lib/alg-sm3.c + create mode 100644 lib/alg-sm3.h + create mode 100644 lib/crypt-sm3.c + +diff --git a/Makefile.am b/Makefile.am +index 430115a..936e0c1 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -74,6 +74,7 @@ noinst_HEADERS = \ + lib/alg-md5.h \ + lib/alg-sha1.h \ + lib/alg-sha256.h \ ++ lib/alg-sm3.h \ + lib/alg-sha512.h \ + lib/alg-yescrypt-sysendian.h \ + lib/alg-yescrypt.h \ +@@ -106,6 +107,7 @@ libcrypt_la_SOURCES = \ + lib/alg-md5.c \ + lib/alg-sha1.c \ + lib/alg-sha256.c \ ++ lib/alg-sm3.c \ + lib/alg-sha512.c \ + lib/alg-yescrypt-common.c \ + lib/alg-yescrypt-opt.c \ +@@ -120,6 +122,7 @@ libcrypt_la_SOURCES = \ + lib/crypt-pbkdf1-sha1.c \ + lib/crypt-scrypt.c \ + lib/crypt-sha256.c \ ++ lib/crypt-sm3.c \ + lib/crypt-sha512.c \ + lib/crypt-static.c \ + lib/crypt-sunmd5.c \ +@@ -329,6 +332,7 @@ check_PROGRAMS = \ + test/alg-pbkdf-hmac-sha256 \ + test/alg-sha1 \ + test/alg-sha256 \ ++ test/alg-sm3 \ + test/alg-sha512 \ + test/alg-yescrypt \ + test/badsalt \ +@@ -520,6 +524,9 @@ test_crypt_gost_yescrypt_LDADD = \ + lib/libcrypt_la-alg-yescrypt-opt.lo \ + lib/libcrypt_la-crypt-yescrypt.lo \ + $(COMMON_TEST_OBJECTS) ++test_alg_sm3_LDADD = \ ++ lib/libcrypt_la-alg-sm3.lo \ ++ $(COMMON_TEST_OBJECTS) + + test_getrandom_interface_LDADD = \ + lib/libcrypt_la-randombytes.lo \ +diff --git a/lib/alg-sm3.c b/lib/alg-sm3.c +new file mode 100644 +index 0000000..68d9f7c +--- /dev/null ++++ b/lib/alg-sm3.c +@@ -0,0 +1,408 @@ ++/*- ++ * Copyright(C) 2017-2021. Huawei Technologies Co.,Ltd. All Rights Reserved. ++ * Copyright 2017-2021 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 "crypt-port.h" ++#include "alg-yescrypt-sysendian.h" ++ ++#if INCLUDE_sm3crypt ++ ++#define insecure_memzero XCRYPT_SECURE_MEMSET ++ ++#include "alg-sm3.h" ++ ++#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) ++ ++#define P0(X) (X ^ ROTATE(X, 9) ^ ROTATE(X, 17)) ++#define P1(X) (X ^ ROTATE(X, 15) ^ ROTATE(X, 23)) ++ ++#define FF0(X,Y,Z) (X ^ Y ^ Z) ++#define GG0(X,Y,Z) (X ^ Y ^ Z) ++ ++#define FF1(X,Y,Z) ((X & Y) | ((X | Y) & Z)) ++#define GG1(X,Y,Z) ((Z ^ (X & (Y ^ Z)))) ++ ++#define EXPAND(W0,W7,W13,W3,W10) \ ++ (P1(W0 ^ W7 ^ ROTATE(W13, 15)) ^ ROTATE(W3, 7) ^ W10) ++ ++#define RND(A, B, C, D, E, F, G, H, TJ, Wi, Wj, FF, GG) \ ++ do { \ ++ const uint32_t A12 = ROTATE(A, 12); \ ++ const uint32_t A12_SM = A12 + E + TJ; \ ++ const uint32_t SS1 = ROTATE(A12_SM, 7); \ ++ const uint32_t TT1 = FF(A, B, C) + D + (SS1 ^ A12) + (Wj); \ ++ const uint32_t TT2 = GG(E, F, G) + H + SS1 + Wi; \ ++ B = ROTATE(B, 9); \ ++ D = TT1; \ ++ F = ROTATE(F, 19); \ ++ H = P0(TT2); \ ++ } while(0) ++ ++#define R1(A,B,C,D,E,F,G,H,TJ,Wi,Wj) \ ++ RND(A,B,C,D,E,F,G,H,TJ,Wi,Wj,FF0,GG0) ++ ++#define R2(A,B,C,D,E,F,G,H,TJ,Wi,Wj) \ ++ RND(A,B,C,D,E,F,G,H,TJ,Wi,Wj,FF1,GG1) ++/* ++ * Encode a length len*2 vector of (uint32_t) into a length len*8 vector of ++ * (uint8_t) in big-endian form. ++ */ ++static void ++be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len) ++{ ++ do { ++ be32enc(&dst[0], src[0]); ++ be32enc(&dst[4], src[1]); ++ src += 2; ++ dst += 8; ++ } while (--len); ++} ++ ++/* ++ * Decode a big-endian length len*8 vector of (uint8_t) into a length ++ * len*2 vector of (uint32_t). ++ */ ++static void ++be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len) ++{ ++ do { ++ dst[0] = be32dec(&src[0]); ++ dst[1] = be32dec(&src[4]); ++ src += 8; ++ dst += 2; ++ } while (--len); ++} ++ ++static void ++SM3_Transform(uint32_t state[static restrict 8], ++ const uint8_t block[static restrict 64], ++ uint32_t W[static restrict 64]) ++{ ++ register uint32_t A, B, C, D, E, F, G, H; ++ uint32_t W00, W01, W02, W03, W04, W05, W06, W07, ++ W08, W09, W10, W11, W12, W13, W14, W15; ++ ++ /* 1. Prepare the first part of the message schedule W. */ ++ be32dec_vect(W, block, 8); ++ ++ A = state[0]; ++ B = state[1]; ++ C = state[2]; ++ D = state[3]; ++ E = state[4]; ++ F = state[5]; ++ G = state[6]; ++ H = state[7]; ++ ++ W00 = W[0]; ++ W01 = W[1]; ++ W02 = W[2]; ++ W03 = W[3]; ++ W04 = W[4]; ++ W05 = W[5]; ++ W06 = W[6]; ++ W07 = W[7]; ++ W08 = W[8]; ++ W09 = W[9]; ++ W10 = W[10]; ++ W11 = W[11]; ++ W12 = W[12]; ++ W13 = W[13]; ++ W14 = W[14]; ++ W15 = W[15]; ++ ++ R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04); ++ W00 = EXPAND(W00, W07, W13, W03, W10); ++ R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05); ++ W01 = EXPAND(W01, W08, W14, W04, W11); ++ R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06); ++ W02 = EXPAND(W02, W09, W15, W05, W12); ++ R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07); ++ W03 = EXPAND(W03, W10, W00, W06, W13); ++ R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08); ++ W04 = EXPAND(W04, W11, W01, W07, W14); ++ R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09); ++ W05 = EXPAND(W05, W12, W02, W08, W15); ++ R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10); ++ W06 = EXPAND(W06, W13, W03, W09, W00); ++ R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11); ++ W07 = EXPAND(W07, W14, W04, W10, W01); ++ R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12); ++ W08 = EXPAND(W08, W15, W05, W11, W02); ++ R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13); ++ W09 = EXPAND(W09, W00, W06, W12, W03); ++ R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14); ++ W10 = EXPAND(W10, W01, W07, W13, W04); ++ R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15); ++ W11 = EXPAND(W11, W02, W08, W14, W05); ++ R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00); ++ W12 = EXPAND(W12, W03, W09, W15, W06); ++ R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01); ++ W13 = EXPAND(W13, W04, W10, W00, W07); ++ R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02); ++ W14 = EXPAND(W14, W05, W11, W01, W08); ++ R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03); ++ W15 = EXPAND(W15, W06, W12, W02, W09); ++ R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); ++ W00 = EXPAND(W00, W07, W13, W03, W10); ++ R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); ++ W01 = EXPAND(W01, W08, W14, W04, W11); ++ R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); ++ W02 = EXPAND(W02, W09, W15, W05, W12); ++ R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); ++ W03 = EXPAND(W03, W10, W00, W06, W13); ++ R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); ++ W04 = EXPAND(W04, W11, W01, W07, W14); ++ R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); ++ W05 = EXPAND(W05, W12, W02, W08, W15); ++ R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); ++ W06 = EXPAND(W06, W13, W03, W09, W00); ++ R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); ++ W07 = EXPAND(W07, W14, W04, W10, W01); ++ R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); ++ W08 = EXPAND(W08, W15, W05, W11, W02); ++ R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); ++ W09 = EXPAND(W09, W00, W06, W12, W03); ++ R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); ++ W10 = EXPAND(W10, W01, W07, W13, W04); ++ R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); ++ W11 = EXPAND(W11, W02, W08, W14, W05); ++ R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); ++ W12 = EXPAND(W12, W03, W09, W15, W06); ++ R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); ++ W13 = EXPAND(W13, W04, W10, W00, W07); ++ R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); ++ W14 = EXPAND(W14, W05, W11, W01, W08); ++ R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); ++ W15 = EXPAND(W15, W06, W12, W02, W09); ++ R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04); ++ W00 = EXPAND(W00, W07, W13, W03, W10); ++ R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05); ++ W01 = EXPAND(W01, W08, W14, W04, W11); ++ R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06); ++ W02 = EXPAND(W02, W09, W15, W05, W12); ++ R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07); ++ W03 = EXPAND(W03, W10, W00, W06, W13); ++ R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08); ++ W04 = EXPAND(W04, W11, W01, W07, W14); ++ R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09); ++ W05 = EXPAND(W05, W12, W02, W08, W15); ++ R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10); ++ W06 = EXPAND(W06, W13, W03, W09, W00); ++ R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11); ++ W07 = EXPAND(W07, W14, W04, W10, W01); ++ R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12); ++ W08 = EXPAND(W08, W15, W05, W11, W02); ++ R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13); ++ W09 = EXPAND(W09, W00, W06, W12, W03); ++ R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14); ++ W10 = EXPAND(W10, W01, W07, W13, W04); ++ R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15); ++ W11 = EXPAND(W11, W02, W08, W14, W05); ++ R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00); ++ W12 = EXPAND(W12, W03, W09, W15, W06); ++ R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01); ++ W13 = EXPAND(W13, W04, W10, W00, W07); ++ R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02); ++ W14 = EXPAND(W14, W05, W11, W01, W08); ++ R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03); ++ W15 = EXPAND(W15, W06, W12, W02, W09); ++ R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); ++ W00 = EXPAND(W00, W07, W13, W03, W10); ++ R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); ++ W01 = EXPAND(W01, W08, W14, W04, W11); ++ R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); ++ W02 = EXPAND(W02, W09, W15, W05, W12); ++ R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); ++ W03 = EXPAND(W03, W10, W00, W06, W13); ++ R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); ++ R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); ++ R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); ++ R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); ++ R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); ++ R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); ++ R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); ++ R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); ++ R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); ++ R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); ++ R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); ++ R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); ++ ++ state[0] ^= A; ++ state[1] ^= B; ++ state[2] ^= C; ++ state[3] ^= D; ++ state[4] ^= E; ++ state[5] ^= F; ++ state[6] ^= G; ++ state[7] ^= H; ++} ++ ++/* Magic initialization constants. */ ++static const uint32_t initial_state[8] = { ++ 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, ++ 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e ++}; ++ ++/** ++ * SM3_Init(ctx): ++ * Initialize the SM3 context ${ctx}. ++ */ ++void SM3_Init(SM3_CTX * ctx) ++{ ++ /* Zero bits processed so far. */ ++ ctx->count = 0; ++ ++ /* Initialize state. */ ++ memcpy(ctx->state, initial_state, sizeof(initial_state)); ++} ++ ++/** ++ * SM3_Update(ctx, in, len): ++ * Input ${len} bytes from ${in} into the SM3 context ${ctx}. ++ */ ++static void _SM3_Update(SM3_CTX * ctx, const void * in, size_t len, ++ uint32_t tmp32[static restrict 72]) ++{ ++ uint32_t r; ++ const uint8_t * src = in; ++ ++ /* Return immediately if we have nothing to do. */ ++ if (len == 0) ++ return; ++ ++ /* Number of bytes left in the buffer from previous updates. */ ++ r = (ctx->count >> 3) & 0x3f; ++ ++ /* Update number of bits. */ ++ ctx->count += (uint64_t)(len) << 3; ++ ++ /* Handle the case where we don't need to perform any transforms. */ ++ if (len < 64 - r) { ++ memcpy(&ctx->buf[r], src, len); ++ return; ++ } ++ ++ /* Finish the current block. */ ++ memcpy(&ctx->buf[r], src, 64 - r); ++ SM3_Transform(ctx->state, ctx->buf, &tmp32[0]); ++ src += 64 - r; ++ len -= 64 - r; ++ ++ /* Perform complete blocks. */ ++ while (len >= 64) { ++ SM3_Transform(ctx->state, src, &tmp32[0]); ++ src += 64; ++ len -= 64; ++ } ++ ++ /* Copy left over data into buffer. */ ++ memcpy(ctx->buf, src, len); ++} ++ ++/* Wrapper function for intermediate-values sanitization. */ ++void ++SM3_Update(SM3_CTX * ctx, const void * in, size_t len) ++{ ++ uint32_t tmp32[72]; ++ ++ /* Call the real function. */ ++ _SM3_Update(ctx, in, len, tmp32); ++ ++ /* Clean the stack. */ ++ insecure_memzero(tmp32, 288); ++} ++ ++static const uint8_t PAD[64] = { ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* Add padding and terminating bit-count. */ ++static void ++SM3_Pad(SM3_CTX * ctx, uint32_t tmp32[static restrict 72]) ++{ ++ size_t r; ++ ++ /* Figure out how many bytes we have buffered. */ ++ r = (ctx->count >> 3) & 0x3f; ++ ++ /* Pad to 56 mod 64, transforming if we finish a block en route. */ ++ if (r < 56) { ++ /* Pad to 56 mod 64. */ ++ memcpy(&ctx->buf[r], PAD, 56 - r); ++ } else { ++ /* Finish the current block and mix. */ ++ memcpy(&ctx->buf[r], PAD, 64 - r); ++ SM3_Transform(ctx->state, ctx->buf, &tmp32[0]); ++ ++ /* The start of the final block is all zeroes. */ ++ memset(&ctx->buf[0], 0, 56); ++ } ++ ++ /* Add the terminating bit-count. */ ++ be64enc(&ctx->buf[56], ctx->count); ++ ++ /* Mix in the final block. */ ++ SM3_Transform(ctx->state, ctx->buf, &tmp32[0]); ++} ++/** ++ * SM3_Final(digest, ctx): ++ * Output the SM3 hash of the data input to the context ${ctx} into the ++ * buffer ${digest}. ++ */ ++static void ++_SM3_Final(uint8_t digest[32], SM3_CTX * ctx, ++ uint32_t tmp32[static restrict 72]) ++{ ++ /* Add padding. */ ++ SM3_Pad(ctx, tmp32); ++ /* Write the hash. */ ++ be32enc_vect(digest, ctx->state, 4); ++} ++ ++/* Wrapper function for intermediate-values sanitization. */ ++void ++SM3_Final(uint8_t digest[32], SM3_CTX * ctx) ++{ ++ uint32_t tmp32[72]; ++ ++ /* Call the real function. */ ++ _SM3_Final(digest, ctx, tmp32); ++ ++ /* Clear the context state. */ ++ insecure_memzero(ctx, sizeof(SM3_CTX)); ++ ++ /* Clean the stack. */ ++ insecure_memzero(tmp32, 288); ++} ++ ++/** ++ * SM3_Buf(in, len, digest): ++ * Compute the SM3 hash of ${len} bytes from ${in} and write it to ${digest}. ++ */ ++void ++SM3_Buf(const void * in, size_t len, uint8_t digest[32]) ++{ ++ SM3_CTX ctx; ++ uint32_t tmp32[72]; ++ ++ SM3_Init(&ctx); ++ _SM3_Update(&ctx, in, len, tmp32); ++ _SM3_Final(digest, &ctx, tmp32); ++ ++ /* Clean the stack. */ ++ insecure_memzero(&ctx, sizeof(SM3_CTX)); ++ insecure_memzero(tmp32, 288); ++} ++#endif /* INCLUDE_sm3crypt */ +diff --git a/lib/alg-sm3.h b/lib/alg-sm3.h +new file mode 100644 +index 0000000..5c76e6b +--- /dev/null ++++ b/lib/alg-sm3.h +@@ -0,0 +1,62 @@ ++/*- ++ * Copyright(C) 2017-2021. Huawei Technologies Co.,Ltd. All Rights Reserved. ++ * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 2017 Ribose Inc. 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 ++ */ ++ ++#ifndef _SM3_H_ ++#define _SM3_H_ ++ ++#include "crypt-port.h" ++ ++#include ++#include ++ ++/* ++ * Use #defines in order to avoid namespace collisions with anyone else's ++ * SM3 code (e.g., the code in OpenSSL). ++ */ ++#define SM3_Init libcperciva_SM3_Init ++#define SM3_Update libcperciva_SM3_Update ++#define SM3_Final libcperciva_SM3_Final ++#define SM3_Buf libcperciva_SM3_Buf ++#define SM3_CTX libcperciva_SM3_CTX ++ ++/* Context structure for SM3 operations. */ ++typedef struct { ++ uint32_t state[8]; ++ uint64_t count; ++ uint8_t buf[64]; ++} SM3_CTX; ++ ++/** ++ * SM3_Init(ctx): ++ * Initialize the SM3 context ${ctx}. ++ */ ++void SM3_Init(SM3_CTX *); ++ ++/** ++ * SM3_Update(ctx, in, len): ++ * Input ${len} bytes from ${in} into the SM3 context ${ctx}. ++ */ ++void SM3_Update(SM3_CTX *, const void *, size_t); ++ ++/** ++ * SM3_Final(digest, ctx): ++ * Output the SM3 hash of the data input to the context ${ctx} into the ++ * buffer ${digest}. ++ */ ++void SM3_Final(uint8_t[32], SM3_CTX *); ++ ++/** ++ * SM3_Buf(in, len, digest): ++ * Compute the SM3 hash of ${len} bytes from ${in} and write it to ${digest}. ++ */ ++void SM3_Buf(const void *, size_t, uint8_t[32]); ++ ++#endif /* !_SM3_H_ */ +diff --git a/lib/crypt-port.h b/lib/crypt-port.h +index bec36ac..33534fa 100644 +--- a/lib/crypt-port.h ++++ b/lib/crypt-port.h +@@ -306,7 +306,7 @@ _crypt_strcpy_or_abort (void *, const size_t, const void *); + #define libcperciva_SHA512_Buf _crypt_SHA512_Buf + #endif + +-#if INCLUDE_md5crypt || INCLUDE_sha256crypt || INCLUDE_sha512crypt ++#if INCLUDE_md5crypt || INCLUDE_sha256crypt || INCLUDE_sha512crypt || INCLUDE_sm3crypt + #define gensalt_sha_rn _crypt_gensalt_sha_rn + #endif + +@@ -341,6 +341,13 @@ _crypt_strcpy_or_abort (void *, const size_t, const void *); + #define libcperciva_SHA256_Buf _crypt_SHA256_Buf + #endif + ++#if INCLUDE_sm3crypt ++#define libcperciva_SM3_Init _crypt_SM3_Init ++#define libcperciva_SM3_Update _crypt_SM3_Update ++#define libcperciva_SM3_Final _crypt_SM3_Final ++#define libcperciva_SM3_Buf _crypt_SM3_Buf ++#endif ++ + #if INCLUDE_gost_yescrypt + #define GOST34112012Init _crypt_GOST34112012_Init + #define GOST34112012Update _crypt_GOST34112012_Update +diff --git a/lib/crypt-sm3.c b/lib/crypt-sm3.c +new file mode 100644 +index 0000000..b79d670 +--- /dev/null ++++ b/lib/crypt-sm3.c +@@ -0,0 +1,357 @@ ++/* One way encryption based on the SM3-based Unix crypt implementation. ++ * ++ * Written by Ulrich Drepper in 2007 [1]. ++ * Modified by Zack Weinberg in 2017, 2018. ++ * Composed by Björn Esser in 2018. ++ * To the extent possible under law, the named authors have waived all ++ * copyright and related or neighboring rights to this work. ++ * ++ * See https://creativecommons.org/publicdomain/zero/1.0/ for further ++ * details. ++ * ++ * This file is a modified except from [2], lines 648 up to 909. ++ * ++ * [1] https://www.akkadia.org/drepper/sha-crypt.html ++ * [2] https://www.akkadia.org/drepper/SHA-crypt.txt ++ */ ++ ++#include "crypt-port.h" ++#include "alg-sm3.h" ++ ++#include ++#include ++#include ++ ++#if INCLUDE_sm3crypt ++ ++/* Define our magic string to mark salt for SM3 "encryption" ++ replacement. */ ++static const char sm3_salt_prefix[] = "$sm3$"; ++ ++/* Prefix for optional rounds specification. */ ++static const char sm3_rounds_prefix[] = "rounds="; ++ ++/* Maximum salt string length. */ ++#define SALT_LEN_MAX 16 ++/* Default number of rounds if not explicitly specified. */ ++#define ROUNDS_DEFAULT 5000 ++/* Minimum number of rounds. */ ++#define ROUNDS_MIN 1000 ++/* Maximum number of rounds. */ ++#define ROUNDS_MAX 999999999 ++ ++/* The maximum possible length of a SM3-hashed password string, ++ including the terminating NUL character. Prefix (including its NUL) ++ + rounds tag ("rounds=$" = "rounds=\0") + strlen(ROUNDS_MAX) ++ + salt (up to SALT_LEN_MAX chars) + '$' + hash (43 chars). */ ++ ++#define LENGTH_OF_NUMBER(n) (sizeof #n - 1) ++ ++#define SM3_HASH_LENGTH \ ++ (sizeof (sm3_salt_prefix) + sizeof (sm3_rounds_prefix) + \ ++ LENGTH_OF_NUMBER (ROUNDS_MAX) + SALT_LEN_MAX + 1 + 43) ++ ++static_assert (SM3_HASH_LENGTH <= CRYPT_OUTPUT_SIZE, ++ "CRYPT_OUTPUT_SIZE is too small for SM3"); ++ ++/* A SM3_buffer holds all of the sensitive intermediate data. */ ++struct SM3_buffer ++{ ++ SM3_CTX ctx; ++ uint8_t result[32]; ++ uint8_t p_bytes[32]; ++ uint8_t s_bytes[32]; ++}; ++ ++static_assert (sizeof (struct SM3_buffer) <= ALG_SPECIFIC_SIZE, ++ "ALG_SPECIFIC_SIZE is too small for SM3"); ++ ++ ++/* Feed CTX with LEN bytes of a virtual byte sequence consisting of ++ BLOCK repeated over and over indefinitely. */ ++static void ++SM3_Update_recycled (SM3_CTX *ctx, ++ unsigned char block[32], size_t len) ++{ ++ size_t cnt; ++ for (cnt = len; cnt >= 32; cnt -= 32) ++ SM3_Update (ctx, block, 32); ++ SM3_Update (ctx, block, cnt); ++} ++ ++void ++crypt_sm3crypt_rn (const char *phrase, size_t phr_size, ++ const char *setting, size_t ARG_UNUSED (set_size), ++ uint8_t *output, size_t out_size, ++ void *scratch, size_t scr_size) ++{ ++ /* This shouldn't ever happen, but... */ ++ if (out_size < SM3_HASH_LENGTH ++ || scr_size < sizeof (struct SM3_buffer)) ++ { ++ errno = ERANGE; ++ return; ++ } ++ ++ struct SM3_buffer *buf = scratch; ++ SM3_CTX *ctx = &buf->ctx; ++ uint8_t *result = buf->result; ++ uint8_t *p_bytes = buf->p_bytes; ++ uint8_t *s_bytes = buf->s_bytes; ++ char *cp = (char *)output; ++ const char *salt = setting; ++ ++ size_t salt_size; ++ size_t cnt; ++ /* Default number of rounds. */ ++ size_t rounds = ROUNDS_DEFAULT; ++ bool rounds_custom = false; ++ ++ /* Find beginning of salt string. The prefix should normally always ++ be present. Just in case it is not. */ ++ if (strncmp (sm3_salt_prefix, salt, sizeof (sm3_salt_prefix) - 1) == 0) ++ /* Skip salt prefix. */ ++ salt += sizeof (sm3_salt_prefix) - 1; ++ ++ if (strncmp (salt, sm3_rounds_prefix, sizeof (sm3_rounds_prefix) - 1) == 0) ++ { ++ const char *num = salt + sizeof (sm3_rounds_prefix) - 1; ++ /* Do not allow an explicit setting of zero rounds, nor of the ++ default number of rounds, nor leading zeroes on the rounds. */ ++ if (!(*num >= '1' && *num <= '9')) ++ { ++ errno = EINVAL; ++ return; ++ } ++ ++ errno = 0; ++ char *endp; ++ rounds = strtoul (num, &endp, 10); ++ if (endp == num || *endp != '$' ++ || rounds < ROUNDS_MIN ++ || rounds > ROUNDS_MAX ++ || errno) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt = endp + 1; ++ rounds_custom = true; ++ } ++ ++ salt_size = strspn (salt, b64t); ++ if (salt[salt_size] && salt[salt_size] != '$') ++ { ++ errno = EINVAL; ++ return; ++ } ++ if (salt_size > SALT_LEN_MAX) ++ salt_size = SALT_LEN_MAX; ++ ++ /* Compute alternate SM3 sum with input PHRASE, SALT, and PHRASE. The ++ final result will be added to the first context. */ ++ SM3_Init (ctx); ++ ++ /* Add phrase. */ ++ SM3_Update (ctx, phrase, phr_size); ++ ++ /* Add salt. */ ++ SM3_Update (ctx, salt, salt_size); ++ ++ /* Add phrase again. */ ++ SM3_Update (ctx, phrase, phr_size); ++ ++ /* Now get result of this (32 bytes). */ ++ SM3_Final (result, ctx); ++ ++ /* Prepare for the real work. */ ++ SM3_Init (ctx); ++ ++ /* Add the phrase string. */ ++ SM3_Update (ctx, phrase, phr_size); ++ ++ /* The last part is the salt string. This must be at most 8 ++ characters and it ends at the first `$' character (for ++ compatibility with existing implementations). */ ++ SM3_Update (ctx, salt, salt_size); ++ ++ /* Add for any character in the phrase one byte of the alternate sum. */ ++ for (cnt = phr_size; cnt > 32; cnt -= 32) ++ SM3_Update (ctx, result, 32); ++ SM3_Update (ctx, result, cnt); ++ ++ /* Take the binary representation of the length of the phrase and for every ++ 1 add the alternate sum, for every 0 the phrase. */ ++ for (cnt = phr_size; cnt > 0; cnt >>= 1) ++ if ((cnt & 1) != 0) ++ SM3_Update (ctx, result, 32); ++ else ++ SM3_Update (ctx, phrase, phr_size); ++ ++ /* Create intermediate result. */ ++ SM3_Final (result, ctx); ++ ++ /* Start computation of P byte sequence. */ ++ SM3_Init (ctx); ++ ++ /* For every character in the password add the entire password. */ ++ for (cnt = 0; cnt < phr_size; ++cnt) ++ SM3_Update (ctx, phrase, phr_size); ++ ++ /* Finish the digest. */ ++ SM3_Final (p_bytes, ctx); ++ ++ /* Start computation of S byte sequence. */ ++ SM3_Init (ctx); ++ ++ /* For every character in the password add the entire password. */ ++ for (cnt = 0; cnt < (size_t) 16 + (size_t) result[0]; ++cnt) ++ SM3_Update (ctx, salt, salt_size); ++ ++ /* Finish the digest. */ ++ SM3_Final (s_bytes, ctx); ++ ++ /* Repeatedly run the collected hash value through SM3 to burn ++ CPU cycles. */ ++ for (cnt = 0; cnt < rounds; ++cnt) ++ { ++ /* New context. */ ++ SM3_Init (ctx); ++ ++ /* Add phrase or last result. */ ++ if ((cnt & 1) != 0) ++ SM3_Update_recycled (ctx, p_bytes, phr_size); ++ else ++ SM3_Update (ctx, result, 32); ++ ++ /* Add salt for numbers not divisible by 3. */ ++ if (cnt % 3 != 0) ++ SM3_Update_recycled (ctx, s_bytes, salt_size); ++ ++ /* Add phrase for numbers not divisible by 7. */ ++ if (cnt % 7 != 0) ++ SM3_Update_recycled (ctx, p_bytes, phr_size); ++ ++ /* Add phrase or last result. */ ++ if ((cnt & 1) != 0) ++ SM3_Update (ctx, result, 32); ++ else ++ SM3_Update_recycled (ctx, p_bytes, phr_size); ++ ++ /* Create intermediate result. */ ++ SM3_Final (result, ctx); ++ } ++ ++ /* Now we can construct the result string. It consists of four ++ parts, one of which is optional. We already know that there ++ is sufficient space at CP for the longest possible result string. */ ++ memcpy (cp, sm3_salt_prefix, sizeof (sm3_salt_prefix) - 1); ++ cp += sizeof (sm3_salt_prefix) - 1; ++ ++ if (rounds_custom) ++ { ++ int n = snprintf (cp, ++ SM3_HASH_LENGTH - (sizeof (sm3_salt_prefix) - 1), ++ "%s%zu$", sm3_rounds_prefix, rounds); ++ cp += n; ++ } ++ ++ memcpy (cp, salt, salt_size); ++ cp += salt_size; ++ *cp++ = '$'; ++ ++#define b64_from_24bit(B2, B1, B0, N) \ ++ do { \ ++ unsigned int w = ((((unsigned int)(B2)) << 16) | \ ++ (((unsigned int)(B1)) << 8) | \ ++ ((unsigned int)(B0))); \ ++ int n = (N); \ ++ while (n-- > 0) \ ++ { \ ++ *cp++ = b64t[w & 0x3f]; \ ++ w >>= 6; \ ++ } \ ++ } while (0) ++ ++ b64_from_24bit (result[0], result[10], result[20], 4); ++ b64_from_24bit (result[21], result[1], result[11], 4); ++ b64_from_24bit (result[12], result[22], result[2], 4); ++ b64_from_24bit (result[3], result[13], result[23], 4); ++ b64_from_24bit (result[24], result[4], result[14], 4); ++ b64_from_24bit (result[15], result[25], result[5], 4); ++ b64_from_24bit (result[6], result[16], result[26], 4); ++ b64_from_24bit (result[27], result[7], result[17], 4); ++ b64_from_24bit (result[18], result[28], result[8], 4); ++ b64_from_24bit (result[9], result[19], result[29], 4); ++ b64_from_24bit (0, result[31], result[30], 3); ++ ++ *cp = '\0'; ++} ++ ++void ++gensalt_sm3crypt_rn (unsigned long count, ++ const uint8_t *rbytes, size_t nrbytes, ++ uint8_t *output, size_t output_size) ++{ ++ /* We will use more rbytes if available, but at least this much is ++ required. */ ++ if (nrbytes < 5) ++ { ++ errno = EINVAL; ++ return; ++ } ++ ++ if (count == 0) ++ count = ROUNDS_DEFAULT; ++ if (count < ROUNDS_MIN) ++ count = ROUNDS_MIN; ++ if (count > ROUNDS_MAX) ++ count = ROUNDS_MAX; ++ ++ /* Compute how much space we need. */ ++ size_t output_len = 10; /* $sm3$ssss\0 */ ++ if (count != ROUNDS_DEFAULT) ++ { ++ output_len += 9; /* rounds=1$ */ ++ for (unsigned long ceiling = 10; ceiling < count; ceiling *= 10) ++ output_len += 1; ++ } ++ if (output_size < output_len) ++ { ++ errno = ERANGE; ++ return; ++ } ++ ++ size_t written; ++ if (count == ROUNDS_DEFAULT) ++ written = (size_t) snprintf ((char *)output, output_size, "$%s$", "sm3"); ++ else ++ written = (size_t) snprintf ((char *)output, output_size, ++ "$%s$rounds=%lu$", "sm3", count); ++ ++ /* The length calculation above should ensure that this is always true. */ ++ assert (written + 5 < output_size); ++ ++ size_t used_rbytes = 0; ++ while (written + 5 < output_size && ++ used_rbytes + 3 < nrbytes && ++ (used_rbytes * 4 / 3) < SALT_LEN_MAX) ++ { ++ unsigned long value = ++ ((unsigned long) (unsigned char) rbytes[used_rbytes + 0] << 0) | ++ ((unsigned long) (unsigned char) rbytes[used_rbytes + 1] << 8) | ++ ((unsigned long) (unsigned char) rbytes[used_rbytes + 2] << 16); ++ ++ output[written + 0] = ascii64[value & 0x3f]; ++ output[written + 1] = ascii64[(value >> 6) & 0x3f]; ++ output[written + 2] = ascii64[(value >> 12) & 0x3f]; ++ output[written + 3] = ascii64[(value >> 18) & 0x3f]; ++ ++ written += 4; ++ used_rbytes += 3; ++ } ++ ++ output[written] = '\0'; ++} ++ ++#endif +diff --git a/lib/hashes.conf b/lib/hashes.conf +index 99ed116..d5d05b2 100644 +--- a/lib/hashes.conf ++++ b/lib/hashes.conf +@@ -48,6 +48,7 @@ bcrypt_a $2a$ 16 STRONG,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS, + bcrypt_x $2x$ 16 ALT,OWL,SUSE + sha512crypt $6$ 15 STRONG,DEFAULT,GLIBC,FREEBSD,SOLARIS + sha256crypt $5$ 15 GLIBC,FREEBSD,SOLARIS ++sm3crypt $sm3$ 15 STRONG + sha1crypt $sha1 20 NETBSD + sunmd5 $md5 8 SOLARIS + md5crypt $1$ 9 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS +diff --git a/libxcrypt.spec.rpkg b/libxcrypt.spec.rpkg +index 12216a6..dc3bd8e 100644 +--- a/libxcrypt.spec.rpkg ++++ b/libxcrypt.spec.rpkg +@@ -173,7 +173,7 @@ Recommends: mkpasswd + %description + 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, ++yescrypt, gost-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, +-- +2.27.0 + diff --git a/libxcrypt.spec b/libxcrypt.spec index 64e78b0..68ff421 100644 --- a/libxcrypt.spec +++ b/libxcrypt.spec @@ -1,15 +1,19 @@ %define libdir /lib64 Name: libxcrypt Version: 4.4.17 -Release: 1 +Release: 2 Summary: Extended crypt library for DES, MD5, Blowfish and others License: LGPLv2+ and BSD and Public Domain URL: https://github.com/besser82/%{name} Source0: https://github.com/besser82/%{name}/archive/v%{version}.tar.gz + +Patch9000: add-sm3-crypt-support.patch + BuildRequires: autoconf libtool fipscheck Obsoletes: %{name}-common < %{version}-%{release} Provides: %{name}-common%{?_isa} = %{version}-%{release} %{name}%{?_isa} = %{version}-%{release} Provides: %{name}-common = %{version}-%{release} +Provides: %{name}-sm3 = %{version}-%{release} %description libxcrypt is a modern library for one-way hashing of passwords. @@ -96,6 +100,9 @@ make check %changelog +* Mon Dec 27 2021 wangyu - 4.4.17-2 +- add sm3 crypt support + * Thu Jan 21 2021 wangchen - 4.4.17-1 - update to 4.4.17 -- Gitee