xiuos/framework/security/crypto/sm9/sm9_util.c

383 lines
9.1 KiB
C
Executable File

/*
* Copyright (c) 2020 AIIT Ubiquitous Team
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file sm9_util.c
* @brief the function called by SM9 function, including hash, KDF, produce random number, encrypt and decrypt algorithm, BiLinearPairing
* @version 1.0
* @author AIIT Ubiquitous Team
* @date 2021-04-24
*/
#include <sm9_util.h>
#include <sm4.h>
/**
*
* @brief generate random bytes
*
* @param null
*
* @return uint8_t
*
*/
uint8_t hw_get_random_byte(void)
{
static uint32_t lcg_state;
static uint32_t nb_soft = 9876543;
#define MAX_SOFT_RNG 1024
static const uint32_t a = 1664525;
static const uint32_t c = 1013904223;
nb_soft = (nb_soft + 1) % MAX_SOFT_RNG;
lcg_state = (a * lcg_state + c);
return (uint8_t) (lcg_state >> 24);
}
/**
*
* @brief generate random bytes stream
*
* @param buf buffer to store the random bytes
* @param blen buffer length
*
* @return 1 if produce random bytes stream; 0 if buffer is null
*/
int crypto_rng_read(uint8_t *buf, size_t blen)
{
uint8_t *b = buf;
size_t n;
if (!b)
return -1;
for (n = 0; n < blen; n++)
b[n] = hw_get_random_byte();
return 1;
}
/**
*
* @brief generate random big number based on crypto_rng_read, bad prng version , only for test.
* TODO: replace next version
*
* @param null
*
* @return ret, big number r
*
*/
big8w RandomNumGenerate()
{
char i = 0, j = 0;
unsigned char random_byte[4];
big8w ret;
memset(ret.word, 0x00, BIG8W_BYTESIZE);
for (i = 0; i < BIGNUMBER_SIZE_8WORD; i++){
for (j = 0; j < 4; j++)
random_byte[j] = hw_get_random_byte();
ret.word[i] = GETU32(random_byte);
}
if (Big8wBigThan(&ret, &curve.N))
ret = Big8wMinusMod(ret, curve.N, curve.N);
return ret;
}
/**
*
* @brief HashTwice = Hash(funcflag||g1||(Hash(g2||g3||ID_A||ID_B||RA||RB)))
* t1 = (g2||g3||ID_A||ID_B||RA||RB), t2 = (funcflag||g1||hashvalue)
*
* @param ID_A id of challenger
* @param ID_A_len length of ID_A, byte size
* @param ID_B id of responser
* @param ID_B_len length of ID_B, byte size
* @param RA a pointer of a point in group G1
* @param RB a pointer of a point in group G1
* @param g1 a pointer of a number in Fq12
* @param g2 a pointer of a number in Fq12
* @param g3 a pointer of a number in Fq12
* @param funcflag defined in SM9, funcflag = 0x82 or 0x83
* @param ret unsigned char string, store the result
*
* @result ret
*
*/
void HashTwice(uint8_t* ID_A, uint8_t ID_A_len, uint8_t* ID_B, uint8_t ID_B_len,
G1point* RA, G1point* RB,
q12* g1, q12* g2, q12* g3, uint8_t funcflag, uint8_t* ret)
{
uint8_t* t1, *t2;
uint32_t i, temp, msglen;
t1 = (uint8_t*)(malloc(ID_A_len + ID_B_len + BIG8W_BYTESIZE * 12 * 2 + BIG8W_BYTESIZE * 2 * 2));
t2 = (uint8_t*)(malloc(1 + BIG8W_BYTESIZE * 12 + SM3OUT_32BYTES));
i = 0;
Q12Intou8string(g2, t1, i);
i += BIG8W_BYTESIZE * 12;
Q12Intou8string(g3, t1, i);
i += BIG8W_BYTESIZE * 12;
for (temp = 0; temp < ID_A_len; temp++)
t1[i + temp] = ID_A[temp];
i += temp;
for (temp = 0; temp < ID_B_len; temp++)
t1[i + temp] = ID_B[temp];
i += temp;
Big8wIntou8string(&RA->x, t1, i); // join RA and t1
i += BIG8W_BYTESIZE;
Big8wIntou8string(&RA->y, t1, i);
i += BIG8W_BYTESIZE;
Big8wIntou8string(&RB->x, t1, i); // join RB and t1
i += BIG8W_BYTESIZE;
Big8wIntou8string(&RB->y, t1, i);
i += BIG8W_BYTESIZE;
msglen = i;
t2[0] = funcflag;
i = 1;
Q12Intou8string(g1, t2, i);
i += BIG8W_BYTESIZE * 12;
sm3(t1, msglen, t2 + i);
sm3(t2, 1 + BIG8W_BYTESIZE * 12 + SM3OUT_32BYTES, ret);
free(t1);
free(t2);
}
/**
* @brief judge if elements in string are zero
*
* @param string unsigned char string to be checked
* @param stringlen length of string
*
* @return true if all elements in string is zero; else false
*
*/
bool StringEqualZero(uint8_t* string, uint32_t stringlen)
{
uint32_t length = 0;
while (length < stringlen)
if (string[length++])
return false;
return true;
}
/**
*
* @brief defined in SM9:H(Z, n); n = curve.N, 255 bits, hlen = 2(therefore temp[i] = 0x01, 0x02)
*
* @param Z unsigned char string
* @param Zlen length of Z
* @param funcflag defined in SM9, funcflag = 0x01 or 0x02; H1() or H2()
*
* @return ret big number
*
*/
big8w H(uint8_t* Z, uint32_t Zlen, uint8_t funcflag)
{
uint8_t* temp;
uint8_t Ha[40];
uint8_t Ha2[32];
uint32_t ctr = 0x01, i = 0;
uint32_t datalen;
big8w tmp = curve.N;
big16w ret;
tmp.word[0] -= 1; // tmp = curve.N - 1
datalen = 1 + Zlen + 4;
temp = (uint8_t *)malloc(datalen);
memset(temp, 0x00, datalen);
memset(ret.word, 0x00, BIG8W_BYTESIZE * 2);
temp[0] = funcflag; // temp = funcfalg||Z||ctr
for (i = 0; i < Zlen; i++)
temp[i + 1] = Z[i];
temp[++i] = 0;
temp[++i] = 0;
temp[++i] = 0;
temp[++i] = 0x01;
sm3(temp, datalen, Ha);
temp[i] = 0x02;
sm3(temp, datalen, Ha2);
free(temp);
for (i = 32; i < 40; i++)
Ha[i] = Ha2[i - 32];
for (i = 0; i < 10; i++)
ret.word[9 - i] = GETU32(Ha + i * 4);
while (ret.word[i] == 0)
i--;
ret.length = i;
tmp = Big16wmod8w(ret, tmp); // tmp = Ha mod (N-1)
i = 0; // tmp += 1
while (tmp.word[0] == 0xffffffff) // if overflow after plus one
i++;
tmp.word[i]++;
if (i) while (i) { // if overflow
i--;
tmp.word[i] = 0;
}
return tmp;
}
/**
*
* @brief key derive function defined in SM9, baseed of hash function(SM3).
*
* @param Z unsigned char string
* @param Zlen length of Z
* @param klen length of key to be derived, bitsize!!!
* @param ret unsigned char string to store the key derived.
*
* @result ret
*
*/
void KDF(uint8_t* Z, uint32_t Zlen, uint32_t klen, uint8_t* ret)
{
uint8_t* tmp, Ha[32];
uint32_t i, round;
uint32_t ctr = 0x00000001;
round = klen >> 8;
if (klen & 0xff)
round++;
tmp = (uint8_t*)(malloc(Zlen + sizeof(uint32_t))); // tmp = Z||ctr
for (i = 0; i < Zlen; i++)
tmp[i] = Z[i];
for (ctr = 1; ctr <= round; ctr++) {
tmp[i] = (ctr >> 24) & 0xff;
tmp[i+1] = (ctr >> 16) & 0xff;
tmp[i+2] = (ctr >> 8) & 0xff;
tmp[i+3] = ctr & 0xff;
sm3(tmp, Zlen + sizeof(uint32_t), ret + 32 * (ctr - 1));
}
}
/**
* @brief SM4 Encrypt Function With ecb mode
*
* @param message data to be encrypted
* @param msglen length of message, byte size
* @param key key of SM4 algorithm
* @param ciphertext unsigned char string to store the encrypted message
*
* @result ciphertext
*
*/
void SM4EncryptWithEcbMode(uint8_t* message, uint32_t msglen, uint8_t* key, uint8_t* ciphertext)
{
sms4_key_t renckey;
uint32_t ciphertextlen;
sms4_set_encrypt_key(&renckey, key);
Sms4EcbEncryptPkcs7Padding(message, msglen, ciphertext, &ciphertextlen, &renckey);
}
/**
* @brief SM4 Decrypt Function
*
* @param ciphertext encrypted message to be decrypted
* @param ciphertextlen length of ciphertext, % 128 == 0
* @param message unsigned char string to store decrypted data
* @param msglen length of message
* @param key key of SM4 algorithm
*
* @result message
*
*/
void SM4DecryptWithEcbMode(uint8_t* ciphertext, uint32_t ciphertextlen, uint8_t* message, int msglen, uint8_t* key)
{
uint32_t i;
sms4_key_t rdeckey;
sms4_set_decrypt_key(&rdeckey, key);
Sms4EcbDecryptPkcs7Padding(ciphertext, ciphertextlen, message, &msglen, &rdeckey);
}
/**
* @brief function defined in SM9, e(P, Q)
*
* @param P a point in group G1
* @param Q a point in group G2
*
* @return a number in Fq12
*
*/
q12 BiLinearPairing(G1point P, G2point Q)
{
bool flag;
uint32_t elem = 0x215d93e, i; // a = 6*t+2 = 0x2400000000215d93e, used in Miller round
int bitindex = 25; // index of elem's hightest bit
G2point T = Q, Q1, Q2;
q12 f;
// Miller round
Q12Zero(&f);
f.low.low.low.word[0] = 1;
f = Q12MultMod(f, f); // 0
Line(P, &T, T, 1, &f);
f = Q12MultMod(f, f); // 0
Line(P, &T, T, 1, &f);
f = Q12MultMod(f, f); // 1
Line(P, &T, T, 1, &f);
Line(P, &T, Q, 0, &f);
for (i = 0; i < 36; i++) { // 36 continuous 0
f = Q12MultMod(f, f);
Line(P, &T, T, 1, &f);
}
for (; bitindex >= 0; bitindex--) { // scan 0x215d93e
flag = (elem >> bitindex) & 1;
f = Q12MultMod(f, f);
Line(P, &T, T, 1, &f);
if (flag)
Line(P, &T, Q, 0, &f);
}
// Frobenius of Q
G2pointFrobenius(Q, &Q1, 1);
G2pointFrobenius(Q, &Q2, 2);
Line(P, &T, Q1, 0, &f);
Q2.y.high = Big8wMinusMod(curve.q, Q2.y.high, curve.q);
Q2.y.low = Big8wMinusMod(curve.q, Q2.y.low, curve.q);
Line(P, &T, Q2, 0, &f);
LastPower(&f);
return f;
}