Análise do processo de verificação e assinatura do segredo nacional

A assinatura é essencialmente: AAA = base64_encode (criptografia de chave privada (SHA1 (mensagem do corpo da mensagem)))

A essência da verificação é: BBB = a descriptografia da chave pública da outra parte (base64_decode (AAA)) e CCC = SHA1 (corpo da mensagem MSG)

                            if (BBB == CCC) {

                                        A verificação do sinal foi bem-sucedida

                            }outro{

                                      A verificação do sinal falhou

                            }

O algoritmo SHA1 pode ser substituído por MD5, SHA256 ou SHA512 conforme necessário, e base64 não é necessária. O objetivo principal aqui é converter o binário em uma string, o que é conveniente para o protocolo HTTP ser transmitido ao servidor para verificação . Os dados podem ser descriptografados com a chave pública da outra parte, o que prova que os dados estão realmente criptografados pela chave privada da criança, e pode ser confirmado se a pessoa que está enviando os dados é Ah Mao ou Ah Gou. Se for transmissão de dados de rede para evitar espionagem, é para criptografar os dados com a chave pública da outra parte, e a pessoa que recebe os dados usa sua própria chave privada para descriptografá-los, o que é diferente da verificação de assinatura.

As funções de assinatura e verificação secretas nacionais são as seguintes:

1 、 ECDSA_sign 和 ECDSA_verify

2 、 ECDSA_do_sign 和 ECDSA_do_verify

3 、 sm2_do_sign 和 sm2_do_verify


/** Computes ECDSA signature of a given hash value using the supplied private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
 *  \param  type     此参数可以被忽略         this parameter is ignored
 *  \param  dgst     指向要签名的HASH值       pointer to the hash value to sign
 *  \param  dgstlen  HASH值的长度             length of the hash value
 *  \param  sig      创建签名的DER加密内存块  memory for the DER encoded created signature
 *  \param  siglen   指向签名的长度           pointer to the length of the returned signature
 *  \param  eckey    包含私钥的EC_KEY对象     EC_KEY object containing a private EC key
 *  \                返回1代表成功            return 1 on success and 0 otherwise
 */
int ECDSA_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig, unsigned int *siglen, EC_KEY *eckey);


/** Verifies that the given signature is valid ECDSA signature of the supplied hash value using the specified public key.
 *  \param  type     此参数可以被忽略         this parameter is ignored
 *  \param  dgst     指向HASH值的指针         pointer to the hash value
 *  \param  dgstlen  HASH值的长度             length of the hash value
 *  \param  sig      指向DER编码后的签名                 pointer to the DER encoded signature
 *  \param  siglen   编码的签名长度           length of the DER encoded signature
 *  \param  eckey    包含公钥的EC_KEY对象     EC_KEY object containing a public EC key
 *  \                返回1代表签名有效        return 1 if the signature is valid, 0 if the signature is invalid and -1 on error
 */
int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, const unsigned char *sig, int siglen, EC_KEY *eckey);

 

/** 使用私钥计算给定的HASH值的ECDSA签名结构体    Computes the ECDSA signature of the given hash value using the supplied private key and returns the created signature.
 *  \param  dgst      指向HASH值的指针       pointer to the hash value
 *  \param  dgst_len  HASH值的长度           length of the hash value
 *  \param  eckey     包含私钥的EC_KEY对象   EC_KEY object containing a private EC key
 *  \                 返回ECDSA_SIG结构体的指针,返回NULL代表出错  return pointer to a ECDSA_SIG structure or NULL if an error occurred
 */
ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst, int dgst_len,  EC_KEY *eckey);


/** Verifies that the supplied signature is a valid ECDSA  signature of the supplied hash value using the supplied public key.
 *  \param  dgst      指向HASH值的指针         pointer to the hash value
 *  \param  dgst_len  HASH值的长度             length of the hash value
 *  \param  sig       ECDSA_SIG 结构体指针     structure
 *  \param  eckey     包含公钥的EC_KEY结构体   EC_KEY object containing a public EC key
 *  \                 签名成功返回1,失败返回-1   return 1 if the signature is valid, 0 if the signature is invalid and -1 on error
 */
int ECDSA_do_verify(const unsigned char *dgst, int dgst_len,  const ECDSA_SIG *sig, EC_KEY *eckey);
/*
 * SM2 签名操作.  计算Z值和签名H(Z)    Computes Z and then signs H(Z || msg) using SM2
 */
                             私钥         摘要算法          ID值                   ID的长度       签名的消息        消息长度
ECDSA_SIG *sm2_do_sign(const EC_KEY *key, const EVP_MD *digest, const uint8_t *id, const size_t id_len, const uint8_t *msg, size_t msg_len);

	
                                            摘要算法             签名函数返回的结构体       ID值              ID的长度             签名的消息         消息长度
int sm2_do_verify(const EC_KEY *key, const EVP_MD *digest, const ECDSA_SIG *signature, const uint8_t *id, const size_t id_len, const uint8_t *msg, size_t msg_len);

A seguir está um exemplo de demonstração do teste. Compilei a biblioteca estática do segredo do país. Você precisa conectar libssl_static.lib libcrypto_static.lib ws2_32.lib e o certificado pode ser gerado por gmssl.exe


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/asn1t.h>
#include <openssl/x509.h>

#include <openssl/rsa.h>
#include <openssl/dsa.h>

#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/ui.h>
#include <openssl/safestack.h>

#include <openssl/bn.h>
#include <openssl/ssl.h>
#include "main.h"


//#pragma comment(lib,"legacy_stdio_definitions.lib")


 
//#define stdin  (__acrt_iob_func(0))
//#define stdout (__acrt_iob_func(1))
//#define stderr (__acrt_iob_func(2))

//#define stdin  (&__iob_func()[0])
//#define stdout (&__iob_func()[1])
//#define stderr (&__iob_func()[2])



//参数为私钥文件名,返回私钥
EVP_PKEY* load_privateKey(const char* file) {
    BIO* in;
    EVP_PKEY* key;

    in = BIO_new_file(file, "r");
    if (!in)    return NULL;
    key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL);
    BIO_free(in);
    return key;
}

//参数为公钥文件名,返回公钥
EVP_PKEY* load_publicKey(const char* file) {
    BIO* in;
    EVP_PKEY* key;

    in = BIO_new_file(file, "r");
    if (!in)    return NULL;
    key = PEM_read_bio_PUBKEY(in, NULL, 0, NULL);
    BIO_free(in);
    return key;
}

//参数为证书文件名,返回证书中的公钥
EVP_PKEY* load_cert(const char* file)
{
	STACK_OF(X509_INFO)* allcerts = NULL;
	BIO*  certs = NULL;
	EVP_PKEY* pkey = NULL;
	int i;

	certs = BIO_new_file(file, "r");//bio_open_default(file, 'r', FORMAT_PEM);
	if (certs == NULL)  return NULL;

	allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
	for (i=0; i<sk_X509_INFO_num(allcerts); i++) {
		X509_INFO* xinfo = sk_X509_INFO_value(allcerts, i);
		if (xinfo->x509 != NULL) {
			X509* xx = xinfo->x509;
			pkey = X509_get_pubkey(xx);
			break;
		}
	}


	sk_X509_INFO_pop_free(allcerts, X509_INFO_free);

	BIO_free(certs);
	return pkey;
}


#define  HASHED_DATA(p)   (((unsigned char*)p)+15)

//计算 SHA-1 的签名HASH值
unsigned char* HashForSign(unsigned char *dst, unsigned int dst_size, unsigned char *src, unsigned int src_size)
{
	unsigned char *buf = (unsigned char *)dst;
	unsigned char sign_data[] =
	{
		0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E,
		0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,
	};
	//校验参数
	if (dst == NULL || src == NULL || src_size == 0 || dst_size < 35)
	{
		return NULL;
	}

	// 
	memcpy(buf, sign_data, sizeof(sign_data));

	// Hash
	SHA1(src, src_size, HASHED_DATA(buf));

	return buf;
}

int main(int argc, char** argv)
{
	//msg为原始消息, 这里随便写
    unsigned char* msg = (unsigned char*)"aaaaaaaaaaaaaaaaaaaaaaa";
	unsigned char sha[64] = {0};

	//用sha1算法计算msg的HASH值,
    unsigned char* sha1 = HashForSign(sha, sizeof(sha), msg, strlen((const char*)msg));
    int res1, res2;
	unsigned char sig[512] = {0};
    unsigned int siglen = sizeof(sig);

	///加载签名证书的私钥文件
    EVP_PKEY* evpPrvKey = load_privateKey("./ClientSign.key");
    EC_KEY* ecPrvKey = EVP_PKEY_get1_EC_KEY(evpPrvKey);

	//加载签名证书,从证书中获取公钥,也可以直接加载公钥文件
    EVP_PKEY* evpPubKey = load_cert("./ClientSign.crt");
    EC_KEY* ecPubKey = EVP_PKEY_get1_EC_KEY(evpPubKey);

	//进行签名,返回1代表成功
    res1 = ECDSA_sign(0, sha1, sizeof(sha), sig, &siglen, ecPrvKey);

    //如果要让服务器验签则把sig用base64加密后传给服务器即可。

	//进行验签,返回1代表成功
    res2 = ECDSA_verify(0, sha1, sizeof(sha), sig, siglen, ecPubKey);

    printf("-------res1=%d, res2=%d--------\n", res1, res2);

    return 0;
}

Endereço de download do código-fonte: https://download.csdn.net/download/langeldep/14803127

 

Acho que você gosta

Origin blog.csdn.net/langeldep/article/details/112833031
Recomendado
Clasificación