NTL密码算法开源库拓展——SM2算法

2021SC@SDUSC

NTL密码算法开源库拓展——SM2算法

概述

本部分给出了SM2椭圆曲线公钥密码算法涉及的必要数学基础知识与相关密码技术,以帮助实现
其它各部分所规定的密码机制。
本部分适用于基域为素域和二元扩域的椭圆曲线公钥密码算法。

国密算法SM2加密解密代码实现

封装加密、解密接口:
加密接口: Encrpt_SM2()
解密接口:Decrypt_SM2()
加密解密结果可以和nodejs的模块sm-crypto
互相加密解密

#ifdef __cplusplus  //在C++编译环境下
extern "C" 
{
#endif

#ifndef _MICRO_SM2_H_
#define _MICRO_SM2_H_

#include <stdint.h>

/*Define to enable SM2 debug function*/
//#define __SM2_DEBUG__

/* Define as 1 to enable ECDSA functions, 0 to disable.
 */
#define SM2_ECDSA 1

/* Optimization settings. Define as 1 to enable an optimization, 0 to disable it.
ECC_SQUARE_FUNC - If enabled, this will cause a specific function to be used for (scalar) squaring instead of the generic
                  multiplication function. Improves speed by about 8% .
*/
#define ECC_SQUARE_FUNC 1

/* Inline assembly options.
Currently we do not provide any inline assembly options. In the future we plan to offer
inline assembly for AVR and 8051.

Note: You must choose the appropriate option for your target architecture, or compilation will fail
with strange assembler messages.
*/
#define ecc_asm_none   0
#ifndef ECC_ASM
    #define ECC_ASM ecc_asm_none
#endif

/* Currently only support 256-bit SM2 */
#define NUM_ECC_DIGITS 32

typedef struct EccPoint
{
    uint8_t x[NUM_ECC_DIGITS];
    uint8_t y[NUM_ECC_DIGITS];
} EccPoint;

typedef struct EccSig
{
    uint8_t r[NUM_ECC_DIGITS];
    uint8_t s[NUM_ECC_DIGITS];
} EccSig;



	/* ecc_make_key() function.
	Create a public/private key pair.

	You must use a new nonpredictable random number to generate each new key pair.

	Outputs:
		p_publicKey  - Will be filled in with the point representing the public key.
		p_privateKey - Will be filled in with the private key.

	Inputs:
		p_random - The random number to use to generate the key pair.

	Returns 1 if the key pair was generated successfully, 0 if an error occurred. If 0 is returned,
	try again with a different random number.
	*/
	int ecc_make_key(EccPoint *p_publicKey, uint8_t p_privateKey[NUM_ECC_DIGITS], uint8_t p_random[NUM_ECC_DIGITS]);

	/* ecc_valid_public_key() function.
	Determine whether or not a given point is on the chosen elliptic curve (ie, is a valid public key).

	Inputs:
		p_publicKey - The point to check.

	Returns 1 if the given point is valid, 0 if it is invalid.
	*/
	int ecc_valid_public_key(EccPoint *p_publicKey);

	/* ecdh_shared_secret() function.
	Compute a shared secret given your secret key and someone else's public key.

	Optionally, you can provide a random multiplier for resistance to DPA attacks. The random multiplier
	should probably be different for each invocation of ecdh_shared_secret().

	Outputs:
		p_secret - Will be filled in with the shared secret value.

	Inputs:
		p_publicKey  - The public key of the remote party.
		p_privateKey - Your private key.
		p_random     - An optional random number to resist DPA attacks. Pass in NULL if DPA attacks are not a concern.

	Returns 1 if the shared secret was computed successfully, 0 otherwise.

	Note: It is recommended that you hash the result of ecdh_shared_secret before using it for symmetric encryption or HMAC.
	If you do not hash the shared secret, you must call ecc_valid_public_key() to verify that the remote side's public key is valid.
	If this is not done, an attacker could create a public key that would cause your use of the shared secret to leak information
	about your private key. */
	int ecdh_shared_secret(uint8_t p_secret[NUM_ECC_DIGITS], EccPoint *p_publicKey, uint8_t p_privateKey[NUM_ECC_DIGITS], uint8_t p_random[NUM_ECC_DIGITS]);

#if SM2_ECDSA

	//added by lhb
	int sm2_get_e(char *IDa, int IDLen, unsigned char *xa, unsigned char *ya, unsigned char *plaintext, unsigned int plainLen, unsigned char *e);
	/*sm2 签名接口*/
	//int sm2_sign(EccSig *sig, uint8_t *msg, unsigned int msg_len, uint8_t *IDa, uint8_t IDa_len, uint8_t p_privateKey[NUM_ECC_DIGITS], uint8_t p_random[NUM_ECC_DIGITS]);
	/*sm2 验签接口*/
	int sm2_verify(EccSig *sig, uint8_t *msg, unsigned int msg_len, uint8_t *IDa, uint8_t IDa_len, EccPoint *p_pubk);
	/*sm2 加密接口*/
	int sm2_encrypt(uint8_t *cipher_text, unsigned int *cipher_len, EccPoint *p_publicKey, uint8_t p_random[NUM_ECC_DIGITS], uint8_t *plain_text, unsigned int plain_len);
	/*sm2 解密接口*/
	int sm2_decrypt(uint8_t *plain_text, unsigned int *plain_len, uint8_t *cipher_text, unsigned int cipher_len, uint8_t p_privateKey[NUM_ECC_DIGITS]);


	/* ecdsa_sign() function.
	Generate an ECDSA signature for a given hash value.

	Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
	this function along with your private key and a random number.
	You must use a new nonpredictable random number to generate each new signature.

	Outputs:
		r, s - Will be filled in with the signature values.

	Inputs:
		p_privateKey - Your private key.
		p_random     - The random number to use to generate the signature.
		p_hash       - The message hash to sign.

	Returns 1 if the signature generated successfully, 0 if an error occurred. If 0 is returned,
	try again with a different random number.
	*/
	//int ecdsa_sign(uint8_t r[NUM_ECC_DIGITS], uint8_t s[NUM_ECC_DIGITS], uint8_t p_privateKey[NUM_ECC_DIGITS],
	//    uint8_t p_random[NUM_ECC_DIGITS], uint8_t p_hash[NUM_ECC_DIGITS]);

	/* ecdsa_verify() function.
	Verify an ECDSA signature.

	Usage: Compute the hash of the signed data using the same hash as the signer and
	pass it to this function along with the signer's public key and the signature values (r and s).

	Inputs:
		p_publicKey - The signer's public key
		p_hash      - The hash of the signed data.
		r, s        - The signature values.

	Returns 1 if the signature is valid, 0 if it is invalid.
	*/
	int ecdsa_verify(EccPoint *p_publicKey, uint8_t p_hash[NUM_ECC_DIGITS], uint8_t r[NUM_ECC_DIGITS], uint8_t s[NUM_ECC_DIGITS]);

#endif /* ECC_ECDSA */

	/* ecc_bytes2native() function.
	Convert an integer in standard octet representation to the native format.

	Outputs:
		p_native - Will be filled in with the native integer value.

	Inputs:
		p_bytes - The standard octet representation of the integer to convert.
	*/
	void ecc_bytes2native(uint8_t p_native[NUM_ECC_DIGITS], uint8_t p_bytes[NUM_ECC_DIGITS * 4]);

	/* ecc_native2bytes() function.
	Convert an integer in native format to the standard octet representation.

	Outputs:
		p_bytes - Will be filled in with the standard octet representation of the integer.

	Inputs:
		p_native - The native integer value to convert.
	*/
	void ecc_native2bytes(uint8_t p_bytes[NUM_ECC_DIGITS * 4], uint8_t p_native[NUM_ECC_DIGITS]);
	__declspec(dllexport) int Encrpt_SM2(unsigned char*Message_original, int Length_of_Message, unsigned char* Message_encrypted);//定义的加密函数接口
	__declspec(dllexport) int Decrypt_SM2(unsigned char *Message_Encrypted, int Length_of_Message, unsigned char* Message_Decrypted);//定义的解密函数接口
#endif /* _MICRO_SM2_H_ */

#ifdef __cplusplus  //在C++编译环境下
}
#endif

int main()
{
	int ret = 0;
	// added by junxue.zheng SM2加密
	std::string inputStr = "junxue"; //需要加密的字符串,如图所示,字符串中不可以有\0,否则后面的会加密失败
	unsigned char inputChar[65535];            //字符串转换为char类型
	inputStr.copy((char*)inputChar, inputStr.length(), 0); 
	int inputLen = inputStr.length();//未加密前数据的长度
	int a = sizeof(inputStr);

	unsigned char tempbuf[65535] = { 0 };//加密后的数据
	ret = Encrpt_SM2(inputChar, inputLen, tempbuf);//加密,秘钥封装在了Encrpt_SM2(内部)
	int tempLen = strlen((const char*)tempbuf);
	// 输出的就是发送给js解密的字符串,可以把以下打印出的字符发送给js解密验证
	printf("enc result:");
	printf("\n");
	int i = 0;
	for (i = 0; i < tempLen; i++)
	{
		printf("%02X", tempbuf[i]);
		//printf("%x", sendbuf[i]);
		if (1 == (i + 1) % 32 && i!=0)
			printf("\n");
	}
	printf("\n");

	// 解密nodejs发送的数据。若收到数据是string,则需要转换为char数组 ,若收到的数据是char,则直接引用。以下以收到的数据为string为例说明;
	// encData_str是收到js发送的数据;也可以是上面加密后的数据tempbuf
	std::string  encData_str = "04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF089D494BCA98353CF1EB00DF753450763D85E90162610262E97C3E75FA335F75EB0176C8F5AA2";
	int encDataLen = encData_str.length();
	unsigned char encData_char[65535];
	unsigned char decData[65535];
	encData_str.copy((char*)encData_char, encDataLen, 0);
	ret = Decrypt_SM2(encData_char, encDataLen, decData);//解密,秘钥封装在了Decrypt_SM2(内部)

	system("pause");
	return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
椭圆曲线密码算法(Elliptic Curve Cryptography,ECC)是一种公钥加密算法,可以用于数据加密和数字签名等安全应用。以下是C++实现椭圆曲线密码算法的示例代码: ```cpp #include <iostream> #include <string> #include <vector> #include <NTL/ZZ.h> // NTL提供的大数运算 using namespace std; using namespace NTL; // 定义椭圆曲线参数 ZZ p("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); ZZ a("-0x3"); ZZ b("0x5"); ZZ n("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); // 定义椭圆曲线点结构体 struct ECPoint { ZZ x; ZZ y; }; // 判断两个大整数是否相等 bool isEqual(const ZZ& a, const ZZ& b) { return (a == b); } // 判断椭圆曲线点是否为无穷远点 bool isInfinity(const ECPoint& P) { return (P.x == 0 && P.y == 0); } // 判断椭圆曲线点是否在椭圆曲线上 bool isOnCurve(const ECPoint& P) { ZZ y2 = SqrMod(P.y, p); ZZ x3 = SqrMod(P.x, p) * P.x % p; ZZ ax = a * P.x % p; ZZ bmodp = b % p; ZZ x3_ax = (x3 + ax) % p; ZZ x3_ax_b = (x3_ax + bmodp) % p; return isEqual(y2, x3_ax_b); } // 计算两个椭圆曲线点之和 ECPoint add(const ECPoint& P, const ECPoint& Q) { if (isInfinity(P)) return Q; if (isInfinity(Q)) return P; if (isEqual(P.x, Q.x) && isEqual(P.y, Q.y)) { ZZ tmp1 = SqrMod(P.x, p); ZZ tmp2 = (tmp1 << 1) % p; ZZ tmp3 = (tmp2 + tmp1 + a) % p; ZZ tmp4 = (P.y << 1) % p; ZZ tmp5 = InvMod(tmp4, p); ZZ tmp6 = (tmp3 * tmp5) % p; ZZ x = (SqrMod(tmp6, p) - tmp2 - P.x - Q.x) % p; ZZ y = ((tmp6 * (P.x - x) % p) - P.y) % p; ECPoint R = {x, y}; return R; } else { ZZ tmp1 = (Q.y - P.y + p) % p; ZZ tmp2 = (Q.x - P.x + p) % p; ZZ tmp3 = InvMod(tmp2, p); ZZ tmp4 = (tmp1 * tmp3) % p; ZZ x = (SqrMod(tmp4, p) - P.x - Q.x + p + a) % p; ZZ y = ((tmp4 * (P.x - x) % p) - P.y + p) % p; ECPoint R = {x, y}; return R; } } // 计算椭圆曲线点的k倍 ECPoint multiply(const ECPoint& P, const ZZ& k) { ECPoint R = {0, 0}; ECPoint Q = P; for (int i = NumBits(k) - 1; i >= 0; i--) { R = add(R, R); if (bit(k, i) == 1) { R = add(R, Q); } } return R; } int main() { // 定义椭圆曲线点 ECPoint P = {0x4a96b5688ef573284664698968c38bb913cbfc82u, 0x23a628553168947d59dcc912042351377ac5fb32u}; // 定义私钥 ZZ d("0x1234567890abcdef"); // 计算公钥 ECPoint Q = multiply(P, d); // 输出公钥 cout << "Public key: (" << Q.x << ", " << Q.y << ")" << endl; return 0; } ``` 以上代码使用了NTL提供的大数运算功能,可以在计算中使用任意大小的整数。在示例代码中,我们定义了椭圆曲线参数,包括模数p、系数a和b、点P以及阶n。接着,我们定义了椭圆曲线点结构体ECPoint,包含了点的x坐标和y坐标。我们实现了几个常用的椭圆曲线算法函数,包括判断两个大整数是否相等、判断椭圆曲线点是否为无穷远点、判断椭圆曲线点是否在椭圆曲线上、计算两个椭圆曲线点之和和计算椭圆曲线点的k倍。最后,我们使用示例代码计算了椭圆曲线公钥,并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元解~殇怀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值