OpenSSL-SM2

Posted 西宁西

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenSSL-SM2相关的知识,希望对你有一定的参考价值。

任务详情

在openEuler(推荐)或Ubuntu或Windows(不推荐)中完成下面任务
编译运行https://github.com/greendow/SM2-signature-creation-and-verification 中的代码,提交运行结果与截图,(7‘)
编译运行https://github.com/greendow/SM2-encrypt-and-decrypt 中的代码提交运行结果与截图(8’)
用OpenSSL EVP函数完成上述签名验签和加密解密两个功能,提交代码和运行结果截图。(15‘)
一、SM2-signature-creation-and-verification
编译

gcc -o sm2_sign *.c -I. -lcrypto

运行

二、SM2-encrypt-and-decrypt
编译

gcc -o mysm2 *.c -I. -lcrypto

运行

三、OpenSSL EVP函数

sm2_enc_dec.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
 
int main(void) 
	int ret = -1, i;
	EVP_PKEY_CTX *pctx = NULL, *ectx = NULL;
	EVP_PKEY *pkey = NULL;
	unsigned char message[16] = "2020133120201331";// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF ;
	size_t message_len = sizeof(message);
	unsigned char *ciphertext = NULL, *plaintext = NULL;
	size_t ciphertext_len, plaintext_len;
	EC_KEY *key_pair = NULL;
	const BIGNUM *priv_key = NULL;
	char *priv_key_str = NULL;
 
	const EC_GROUP *group = NULL;
	const EC_POINT *pub_key = NULL;
	BN_CTX *ctx = NULL;
	BIGNUM *x_coordinate = NULL, *y_coordinate = NULL;
	char *x_coordinate_str = NULL, *y_coordinate_str = NULL;
 
	/* create SM2 Ellipse Curve parameters and key pair */
	if ( !(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_paramgen_init(pctx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2)) <= 0 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_keygen_init(pctx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_keygen(pctx, &pkey)) != 1 ) 
		goto clean_up;
	
 
	/* print SM2 key pair */
	if ( !(key_pair = EVP_PKEY_get0_EC_KEY(pkey)) ) 
		goto clean_up;
	
 
	if ( !(priv_key = EC_KEY_get0_private_key(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(priv_key_str = BN_bn2hex(priv_key)) ) 
		goto clean_up;
	
	printf("SM2 private key (in hex form):\\n");
	printf("%s\\n\\n", priv_key_str);
 
	if ( !(pub_key = EC_KEY_get0_public_key(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(group = EC_KEY_get0_group(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(ctx = BN_CTX_new()) ) 
		goto clean_up;
	
	BN_CTX_start(ctx);
	x_coordinate = BN_CTX_get(ctx);
	y_coordinate = BN_CTX_get(ctx);
	if ( !(y_coordinate) ) 
		goto clean_up;
	
	if ( !(EC_POINT_get_affine_coordinates(group, pub_key, x_coordinate, y_coordinate, ctx)) ) 
		goto clean_up;
	
	if ( !(x_coordinate_str = BN_bn2hex(x_coordinate)) ) 
		goto clean_up;
	
	printf("x coordinate in SM2 public key (in hex form):\\n");
	printf("%s\\n\\n", x_coordinate_str);
 
	if ( !(y_coordinate_str = BN_bn2hex(y_coordinate)) ) 
		goto clean_up;
	
	printf("y coordinate in SM2 public key (in hex form):\\n");
	printf("%s\\n\\n", y_coordinate_str);
 
	/* compute SM2 encryption */
	if ( (EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) != 1 ) 
		goto clean_up;
	
 
	if ( !(ectx = EVP_PKEY_CTX_new(pkey, NULL)) ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_encrypt_init(ectx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_encrypt(ectx, NULL, &ciphertext_len, message, message_len)) != 1 ) 
		goto clean_up;
	
 
	if ( !(ciphertext = (unsigned char *)malloc(ciphertext_len)) ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_encrypt(ectx, ciphertext, &ciphertext_len, message, message_len)) != 1 ) 
		goto clean_up;
	
 
	printf("Message length: %ld bytes.\\n", message_len);
	printf("Message:\\n");
	for (i = 0; i < (int)message_len; i++) 
		printf("0x%x  ", message[i]);
	
	printf("\\n\\n");
 
	printf("Ciphertext length: %ld bytes.\\n", ciphertext_len);
	printf("Ciphertext (ASN.1 encode):\\n");
	for (i = 0; i < (int)ciphertext_len; i++) 
		printf("0x%x  ", ciphertext[i]);
	
	printf("\\n\\n");
 
	/* compute SM2 decryption */
	if ( (EVP_PKEY_decrypt_init(ectx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_decrypt(ectx, NULL, &plaintext_len, ciphertext, ciphertext_len)) != 1 ) 
		goto clean_up;
	
 
	if ( !(plaintext = (unsigned char *)malloc(plaintext_len)) ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_decrypt(ectx, plaintext, &plaintext_len, ciphertext, ciphertext_len)) != 1 ) 
		goto clean_up;
	
 
	printf("Decrypted plaintext length: %ld bytes.\\n", plaintext_len);
	printf("Decrypted plaintext:\\n");
	for (i = 0; i < (int)plaintext_len; i++) 
		printf("0x%x  ", plaintext[i]);
	
	printf("\\n\\n");
 
	if ( plaintext_len != message_len ) 
		printf("Decrypted data length error!\\n");
		goto clean_up;
	
 
	if ( memcmp(plaintext, message, message_len) ) 
		printf("Decrypt data failed!\\n");
		goto clean_up;
	 else 
		printf("Encrypt and decrypt data succeeded!\\n");
	
 
	ret = 0;
clean_up:
	if (pctx) 
		EVP_PKEY_CTX_free(pctx);
	
 
	if (pkey) 
		EVP_PKEY_free(pkey);
	
 
	if (priv_key_str) 
		OPENSSL_free(priv_key_str);
	
 
	if (ctx) 
		BN_CTX_end(ctx);
		BN_CTX_free(ctx);
	
 
	if (x_coordinate_str) 
		OPENSSL_free(x_coordinate_str);
	
 
	if (y_coordinate_str) 
		OPENSSL_free(y_coordinate_str);
	
 
	if (ectx) 
		EVP_PKEY_CTX_free(ectx);
	
 
	if (ciphertext) 
		free(ciphertext);
	
 
	if (plaintext) 
		free(plaintext);
	
 
	return 0;

运行结果

sm2_sign.c

#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
 
int main(void) 
	int ret = -1, i;
	EVP_PKEY_CTX* pctx = NULL, * sctx = NULL;
	EVP_PKEY* pkey = NULL;
	EVP_MD_CTX* md_ctx = NULL, * md_ctx_verify = NULL;
	unsigned char message[16] = "2020133120201331"; // 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF ;
	size_t message_len = sizeof(message);
	unsigned char* sig = NULL;
	size_t sig_len;
	unsigned char sm2_id[] =  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
	                           0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38
	                         ;
	unsigned int sm2_id_len = sizeof(sm2_id);
	EC_KEY* key_pair = NULL;
	const BIGNUM* priv_key = NULL;
	char* priv_key_str = NULL;
 
	const EC_GROUP* group = NULL;
	const EC_POINT* pub_key = NULL;
	BN_CTX* ctx = NULL;
	BIGNUM* x_coordinate = NULL, * y_coordinate = NULL;
	char* x_coordinate_str = NULL, * y_coordinate_str = NULL;
 
	/* create SM2 Ellipse Curve parameters and key pair */
	if ( !(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_paramgen_init(pctx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2)) <= 0 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_keygen_init(pctx)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_PKEY_keygen(pctx, &pkey)) != 1 ) 
		goto clean_up;
	
 
	/* print SM2 key pair */
	if ( !(key_pair = EVP_PKEY_get0_EC_KEY(pkey)) ) 
		goto clean_up;
	
 
	if ( !(priv_key = EC_KEY_get0_private_key(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(priv_key_str = BN_bn2hex(priv_key)) ) 
		goto clean_up;
	
	printf("SM2 private key (in hex form):\\n");
	printf("%s\\n\\n", priv_key_str);
 
	if ( !(pub_key = EC_KEY_get0_public_key(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(group = EC_KEY_get0_group(key_pair)) ) 
		goto clean_up;
	
 
	if ( !(ctx = BN_CTX_new()) ) 
		goto clean_up;
	
	BN_CTX_start(ctx);
	x_coordinate = BN_CTX_get(ctx);
	y_coordinate = BN_CTX_get(ctx);
	if ( !(y_coordinate) ) 
		goto clean_up;
	
	if ( !(EC_POINT_get_affine_coordinates(group, pub_key, x_coordinate, y_coordinate, ctx)) ) 
		goto clean_up;
	
	if ( !(x_coordinate_str = BN_bn2hex(x_coordinate)) ) 
		goto clean_up;
	
	printf("x coordinate in SM2 public key (in hex form):\\n");
	printf("%s\\n\\n", x_coordinate_str);
 
	if ( !(y_coordinate_str = BN_bn2hex(y_coordinate)) ) 
		goto clean_up;
	
	printf("y coordinate in SM2 public key (in hex form):\\n");
	printf("%s\\n\\n", y_coordinate_str);
 
	/* compute SM2 signature */
	if ( (EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) != 1 ) 
		goto clean_up;
	
 
	if ( !(md_ctx = EVP_MD_CTX_new()) ) 
		goto clean_up;
	
 
	if ( !(sctx = EVP_PKEY_CTX_new(pkey, NULL)) ) 
		goto clean_up;
	
 
	if ( EVP_PKEY_CTX_set1_id(sctx, sm2_id, sm2_id_len) <= 0 ) 
		goto clean_up;
	
 
	EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx);
 
	if ( (EVP_DigestSignInit(md_ctx, NULL, EVP_sm3(), NULL, pkey)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_DigestSignUpdate(md_ctx, message, message_len)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_DigestSignFinal(md_ctx, NULL, &sig_len)) != 1 ) 
		goto clean_up;
	
 
	if ( !(sig = (unsigned char*)malloc(sig_len)) ) 
		goto clean_up;
	
 
	if ( (EVP_DigestSignFinal(md_ctx, sig, &sig_len)) != 1 ) 
		goto clean_up;
	
 
	printf("Message length: %ld bytes.\\n", message_len);
	printf("Message:\\n");
	for (i = 0; i < (int)message_len; i++) 
		printf("0x%x  ", message[i]);
	
	printf("\\n\\n");
 
	printf("SM2 signature length: %ld bytes.\\n", sig_len);
	printf("SM2 signature (ASN.1 encode):\\n");
	for (i = 0; i < (int)sig_len; i++) 
		printf("0x%x  ", sig[i]);
	
	printf("\\n\\n");
 
	/* verify SM2 signature */
	if ( !(md_ctx_verify = EVP_MD_CTX_new()) ) 
		goto clean_up;
	
 
	EVP_MD_CTX_set_pkey_ctx(md_ctx_verify, sctx);
 
	if ( (EVP_DigestVerifyInit(md_ctx_verify, NULL, EVP_sm3(), NULL, pkey)) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_DigestVerifyUpdate(md_ctx_verify, message, sizeof(message))) != 1 ) 
		goto clean_up;
	
 
	if ( (EVP_DigestVerifyFinal(md_ctx_verify, sig, sig_len)) != 1 ) 
		printf("Verify SM2 signature failed!\\n");
		goto clean_up;
	 else 
		printf("Verify SM2 signature succeeded!\\n");
	
 
	ret = 0;
clean_up:
	if (pctx) 
		EVP_PKEY_CTX_free(pctx);
	
 
	if (pkey) 
		EVP_PKEY_free(pkey);
	
 
	if (priv_key_str) 
		OPENSSL_free(priv_key_str);
	
 
	if (ctx) 
		BN_CTX_end(ctx);
		BN_CTX_free(ctx);
	
 
	if (x_coordinate_str) 
		OPENSSL_free(x_coordinate_str);
	
 
	if (y_coordinate_str) 
		OPENSSL_free(y_coordinate_str);
	
 
	if (md_ctx) 
		EVP_MD_CTX_free(md_ctx);
	
 
	if (sctx) 
		EVP_PKEY_CTX_free(sctx);
	
 
	if (sig) 
		free(sig);
	
 
	if (md_ctx_verify) 
		EVP_MD_CTX_free(md_ctx_verify);
	
	return 0;

运行结果


NLP-Word Embedding-Attention机制

参考技术A

attention机制是个坑。
要明白attention机制,首先要明白seq2seq
要明白seq2sql,首先要明白RNN
要明白RNN,首先要明白MLP和BP算法
这是attention机制的前坑

明白attention机制后,要明白self-attention,以及attention在诸多领域的应用
明白self-attention后,要明白Transformer
明白transformer后,要明白Bert
这是attention机制的后坑

即一个序列生成另一个序列。最直观的就是机器翻译,一句英文翻译成一句中文。或者应答,问一句答一句。
模型结构:输入数据连接一个 encoder(编码器) 得到编码输出又称中间状态 C 然后连接到一个 decoder(解码器) 最后解码器的输出作为模型输出

也可以发现,RNN星球的外星人,执着于吃自己的隐层状态h(x),同时,其隐层状态可以继续计算得到输出y。当然,他们也会去吃y,当手头没有输入时他们会把前一个y当输入吃掉,就像小D。当手头有输入时,他们可以不吃y而吃输入。就像小E。至于为什么这样,可能是他们当地人的习惯吧,总得有点下shit菜不是。

小E和小D是RNN星球的外星小伙伴,这个大家都知道了
小E吃了一筐水果小D来了发现没了很不开心,这个大家都知道了
当小D骄傲的说出小E具体吃了什么时,他们发现,小D说的没有那么准。
两人对视一会,发现问题:小D只吃了小E最后的h(an),那最后的h(an)携带的前面的信息就很少了。要改变!要把小E所有的h(ai)都用上!而且,要尽量找到对应关系,例如预测第一个时,要尽量用到第一个h(a)的信息。

具体是怎么做的呢?
小D是这么想的,首先,让小E把他拉的所有h(a)都给他。即[h(a1),h(a2),h(a3)...h(an)],每个h(ai)都是一个向量,所以这些组成了一个矩阵K
然后,小D每拉出一个h(b)就去这个矩阵分别计算该h(b)和每个h(a)的相关度,得到一系列分数,按照分数大小来组合这些h(a)从而得到一个专属于该h(b)的C。下图中的a即是表示对应的分数

还有一个问题,怎么计算相关度?cos相关度,点乘,皮尔森相关等都可以
最后一个问题,初始的隐藏状态是什么,因为没有用到非attention机制的h(h(an))。老规矩,随机初始化。

所以,attention机制,像是一种配方,根据当前不同位置来调配encoder一系列隐藏状态h(ai)的组合比重,这显然是很有道理的,因为就拿翻译来说,词的顺序往往是对应的。

简言之,encoder获取状态矩阵K,decoder根据每一轮隐藏状态h计算注意力分数获得注意力向量C,拼接h和C获得输出y,y和h进入下一轮decode获得新的h。。。

上一步有个矩阵K,来自encoder。而来自decoder的h类似于一个查询(query)。这个查询分别与K中的不同向量h(a)(key)计算相关度得到分数(score),然后利用分数做权重与对应的h(a)(value)加权求和得到自己想要的结果C。
这里我为什么要写query,key,value呢?是为了讲解self-attention。注意这里key和value都是指h(a)即encoder的状态矩阵。
那如果这个query不来自decoder而来自encoder本身呢?即自己查自己?
有了query,key,value概念之后,就比较好理解self-attention了。
首先,输入的词汇(小E吃的水果也好,翻译中一句话分成的一组词也好)都是要embedding成一个固定长度的向量x才输入模型的。即对于一句话的所有词,组成了一个输入矩阵X。
然后,我们随机生成3个矩阵Q,K,V对应query,key,value
对于一个输入x,
用x点乘Q得到query
用x点乘K得到key
用x点乘V得到value
这样,对于一句话中的所有x,都可以得到对应的query,key,value

有了这些就好办了
每个x,都可以用自己的query去和其他key计算score,然后用该score和对应的其他value来计算自己的注意力向量C。经过这样的计算,x变成了C。

上图中的z即为C。而score到softmax之间的步骤是一些tricks,不用管。

同样,可以多叠加几层self-attention,用同样的操作不同的QKV矩阵由c变成cc,变成ccc
这就是self-attention。

self-attention像是一种向量转换。x变为c,维度没变,值变了。而同时,这种转变又蕴含了x与上下文x之间的关系。rnn也可以实现由x变为另一个向量,同时也考虑了上下文关系,但是,他存在循环神经网络的弊端,无法并行。而self-attention组成的transformer则可以实现并行运算。即,他不需要等待下一个状态h计算出来再计算C,而是直接通过QKV矩阵和当前x计算所得。
那QKV怎么得到?随机初始,训练所得。

https://caicai.science/2018/10/06/attention%E6%80%BB%E8%A7%88/
https://jalammar.github.io/visualizing-neural-machine-translation-mechanics-of-seq2seq-models-with-attention/
https://zhuanlan.zhihu.com/p/37601161
https://jalammar.github.io/illustrated-transformer/

以上是关于OpenSSL-SM2的主要内容,如果未能解决你的问题,请参考以下文章

2维码测试

老鼠走迷宫

TCP / IP 协议

VueAxios详解

2.3 os 模块

常见应用发布方式剖析