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的主要内容,如果未能解决你的问题,请参考以下文章