openssl DSA 算法学习

1,DSA简介

struct dsa_st
	{
	/* This first variable is used to pick up errors where
	 * a DSA is passed instead of of a EVP_PKEY */
	int pad;
	long version;
	int write_params;
	BIGNUM *p;
	BIGNUM *q;	/* == 20 */
	BIGNUM *g;

	BIGNUM *pub_key;  /* y public key */
	BIGNUM *priv_key; /* x private key */

	BIGNUM *kinv;	/* Signing pre-calc */
	BIGNUM *r;	/* Signing pre-calc */

	int flags;
	/* Normally used to cache montgomery values */
	BN_MONT_CTX *method_mont_p;
	int references;
	CRYPTO_EX_DATA ex_data;
	const DSA_METHOD *meth;
	/* functional reference if 'meth' is ENGINE-provided */
	ENGINE *engine;
	};

Digital Signature Algorithm (DSA)算法是一种公钥算法。其密钥由如下部分组成:

1p一个大素数,长度为L(64的整数倍)比特。

2q一个160比特素数。

3=h(p-1)/q mod p,其中h小于p-1

4x小于q

5) y=gx mod p

其中x为私钥,y为公钥。pqg是公开信息(openssl中称为密钥参数)

DSA签名包括两部分,如下:

r = (gk mod p) mod q 

s = (k-1 (H(m) + xr)) mod q 

其中,H(m)为摘要算法;

DSA验签如下:

w = s-1 mod q 

u1 = (H(m) * w) mod q 

u2 = (rw) mod q 

v = ((gu1 * yu2) mod p) mod q

如果v=r,则验证通过。

2,DSA 算法调用过程

1)初始化DSA结构体

DSA* DSA_new();
在该函数中会设置meth首先看一下,meth的结构体原型,有代码中我们可以清晰的看到meth结构是函数指针,后面签名等函数的调用就是调用结构体函数指针。首先我们来看一下DSA_new()中对meth的设置。


struct dsa_method
	{
	const char *name;
	DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa);
	int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
								BIGNUM **rp);
	int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len,
			     DSA_SIG *sig, DSA *dsa);
	int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1,
			BIGNUM *a2, BIGNUM *p2, BIGNUM *m, BN_CTX *ctx,
			BN_MONT_CTX *in_mont);
	int (*bn_mod_exp)(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
				const BIGNUM *m, BN_CTX *ctx,
				BN_MONT_CTX *m_ctx); /* Can be null */
	int (*init)(DSA *dsa);
	int (*finish)(DSA *dsa);
	int flags;
	char *app_data;
	/* If this is non-NULL, it is used to generate DSA parameters */
	int (*dsa_paramgen)(DSA *dsa, int bits,
			const unsigned char *seed, int seed_len,
			int *counter_ret, unsigned long *h_ret,
			BN_GENCB *cb);
	/* If this is non-NULL, it is used to generate DSA keys */
	int (*dsa_keygen)(DSA *dsa);
	};

2)在生成密钥之前需要先生成密钥参数。调用

int DSA_generate_parameters_ex(DSA *ret,int bits,const unsigned char *seed_in, int seed_len,int *counter_ret, unsigned long *h_ret, BN_GENCB *cb)

其中bits设置是为了选择哪一种hash算法。该函数功能是生成前面所讲的P、Q、G 三个参数。

在我们们跟踪到具体的代码发现,所有的都用基本上都是通过调用DSA结构体中的meth,而该结构成员基本上都是结构体指针。

3)生成密钥,即生成DSA中的pub_key和priv_key

int DSA_generate_key(DSA *dsa)
4)最后进行sign和verify

int DSA_sign(int type, const unsigned char *dgst, int dlen, unsigned char *sig,
	     unsigned int *siglen, DSA *dsa);
int DSA_verify(int type, const unsigned char *dgst, int dgst_len,
	     const unsigned char *sigbuf, int siglen, DSA *dsa);





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用 OpenSSL 中的 DSA 算法进行数字签名和验证的完整代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/dsa.h> #include <openssl/err.h> #define MESSAGE "Hello, world!" int main() { // 生成 DSA 密钥对 DSA *dsa = DSA_generate_parameters(1024, NULL, 0, NULL, NULL, NULL, NULL); if (!dsa) { fprintf(stderr, "Failed to generate DSA parameters\n"); ERR_print_errors_fp(stderr); exit(1); } if (!DSA_generate_key(dsa)) { fprintf(stderr, "Failed to generate DSA key pair\n"); ERR_print_errors_fp(stderr); exit(1); } // 计算消息的哈希值 unsigned char digest[SHA256_DIGEST_LENGTH]; SHA256((const unsigned char *) MESSAGE, strlen(MESSAGE), digest); // 签名消息 unsigned char signature[DSA_size(dsa)]; unsigned int signature_len; EVP_MD_CTX *ctx = EVP_MD_CTX_new(); if (!ctx) { fprintf(stderr, "Failed to create EVP_MD_CTX object\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, dsa)) { fprintf(stderr, "Failed to initialize signing context\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestSignUpdate(ctx, digest, SHA256_DIGEST_LENGTH)) { fprintf(stderr, "Failed to update signing context\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestSignFinal(ctx, signature, &signature_len)) { fprintf(stderr, "Failed to finalize signing context\n"); ERR_print_errors_fp(stderr); exit(1); } printf("Signature:\n"); for (int i = 0; i < signature_len; i++) { printf("%02x", signature[i]); } printf("\n"); // 验证消息 ctx = EVP_MD_CTX_new(); if (!ctx) { fprintf(stderr, "Failed to create EVP_MD_CTX object\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, dsa)) { fprintf(stderr, "Failed to initialize verification context\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestVerifyUpdate(ctx, digest, SHA256_DIGEST_LENGTH)) { fprintf(stderr, "Failed to update verification context\n"); ERR_print_errors_fp(stderr); exit(1); } if (!EVP_DigestVerifyFinal(ctx, signature, signature_len, dsa)) { fprintf(stderr, "Verification failed\n"); ERR_print_errors_fp(stderr); exit(1); } printf("Verification succeeded\n"); // 释放资源 DSA_free(dsa); EVP_MD_CTX_free(ctx); return 0; } ``` 需要注意的是,此示例中使用的哈希算法为 SHA-256,如果需要使用其他哈希算法,需要相应地更改 EVP_DigestSignInit 和 EVP_DigestVerifyInit 中的参数。此外,代码中没有包括错误处理和内存管理,实际使用时应该加上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值