问题: 使用书面演示代码(如下所示),我可以毫无问题地创建和验证。 但是,使用openssl命令行工具验证签名(由演示代码创建) 似乎总是失败。
我做了什么: 演示代码创建一个已定义的公钥/私钥对,然后签署一个已定义的哈希并验证它。
这是程序输出:
Public key: 04DFEC134530603832A31F8885EF01888884483D611F87A698213F168534EC06D85D21F7C85795435BC9A7F78190126CC6E52E050CBDFD43E27175FB1DF3E3DEF6
Hash: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Verified EC Signature
R: 383EB65E4A284CBCBA41A9777CE7C0816C5C23161EA9BC4EF8B1E668C7641A2A
S: 608F4BAB9DFE6DC8F976C32D72508CD5BD68F9E325ADED69A9883CE487E6698B
它也输出以下文件:
privkey.pem
(PEM格式的私钥)pubkey.pem
(PEM格式的公钥)data.bin
(哈希,没什么特别的)data_sig.der
(DER编码签名:R& S值)似乎正确创建了所有文件。
接下来,我尝试使用openssl命令行工具验证data_sig.der
。
$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin
Verification Failure
为什么这会失败?
我只能假设,4个文件中有一个写得不正确, 但我仔细检查了一切,无法发现我的错误。
此外,使用演示程序创建的PEM文件, 标志&验证从命令行正常工作:
$openssl dgst -sign privkey.pem data.bin > data_sig2.der
$openssl dgst -verify pubkey.pem -signature data_sig2.der data.bin
Verified OK
以下是演示代码(使用gcc demo_code.c -lcrypto -lssl -o demo_code
编译):
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/ecdsa.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
void createSignature()
{
EC_KEY* eckey = EC_KEY_new();
EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_group(eckey,ecgroup);
EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
/* the private key value */
const char *p_str = "7D22AB6A1FD3FC1F5EBEDCA222151375683B733E9DDC9CA5B2485E202C55D25C";
BIGNUM* prv = BN_new();
BN_hex2bn(&prv, p_str);
EC_POINT* pub = EC_POINT_new(ecgroup);
/* calculate the public key */
EC_POINT_mul(ecgroup, pub, prv, NULL, NULL, NULL);
/* add the private & public key to the EC_KEY structure */
EC_KEY_set_private_key(eckey, prv);
EC_KEY_set_public_key(eckey, pub);
/* output public key in hex format */
char* hexPKey = EC_POINT_point2hex( ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, NULL );
printf("Public key: %s \n", hexPKey);
/* create hash */
printf("Hash: ");
uint8_t hash[32];
for(int i=0; i < 32; i++) {
hash[i] = i;
printf("%02x",hash[i]);
}
printf("\n");
/* create and verify signature */
ECDSA_SIG* signature = ECDSA_do_sign(hash, 32, eckey);
//hash[0] = 0xff; // Uncomment to test if verification fails with a wrong hash
if (1 != ECDSA_do_verify(hash, 32, signature, eckey)) {
printf("Failed to verify EC Signature\n");
} else {
printf("Verified EC Signature\n");
}
/*print R & S value in hex format */
char* hexR = BN_bn2hex(signature->r);
char* hexS = BN_bn2hex(signature->s);
printf("R: %s \nS: %s\n", hexR, hexS);
/* export raw signature to DER-encoded format */
int sigSize = i2d_ECDSA_SIG(signature, NULL);
uint8_t* derSig = (uint8_t*)malloc(sigSize);
uint8_t* p = derSig; //memset(sig_bytes, 6, sig_size);
sigSize= i2d_ECDSA_SIG(signature, &p);
EVP_PKEY* pkey = EVP_PKEY_new();
EVP_PKEY_set1_EC_KEY(pkey, eckey);
/* write files */
FILE* fp = fopen("pubkey.pem", "w");
PEM_write_PUBKEY(fp, pkey);
fclose(fp);
fp = fopen("privkey.pem", "w");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, 0, NULL);
fclose(fp);
fp = fopen("data.bin", "w");
fwrite(hash, 1, sizeof(hash), fp);
fclose(fp);
fp = fopen("data_sig.der", "w");
fwrite(derSig, 1, sigSize, fp);
fclose(fp);
/* free runtime allocated res */
free(derSig);
OPENSSL_free(hexPKey); OPENSSL_free(hexR); OPENSSL_free(hexS);
BN_free(prv);
EC_POINT_free(pub);
EC_GROUP_free(ecgroup);
EC_KEY_free(eckey);
}
int main(int argc, char** argv) {
createSignature();
return (EXIT_SUCCESS);
}
答案 0 :(得分:2)
您似乎在签署数据而不是哈希数据的结果。但是当你跑步时:
$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin
openssl实用程序从data.bin
计算sha256哈希并尝试验证此哈希上的签名。
所以你需要从000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
计算sha256并签名结果:
void createSignature()
{
EC_KEY* eckey = EC_KEY_new();
EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_group(eckey,ecgroup);
EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
/* the private key value */
const char *p_str = "7D22AB6A1FD3FC1F5EBEDCA222151375683B733E9DDC9CA5B2485E202C55D25C";
BIGNUM* prv = BN_new();
BN_hex2bn(&prv, p_str);
EC_POINT* pub = EC_POINT_new(ecgroup);
/* calculate the public key */
EC_POINT_mul(ecgroup, pub, prv, NULL, NULL, NULL);
/* add the private & public key to the EC_KEY structure */
EC_KEY_set_private_key(eckey, prv);
EC_KEY_set_public_key(eckey, pub);
/* output public key in hex format */
char* hexPKey = EC_POINT_point2hex( ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, NULL );
printf("Public key: %s \n", hexPKey);
/* create hash */
printf("Data: ");
uint8_t data[32];
for(int i=0; i < 32; i++) {
data[i] = i;
printf("%02x",data[i]);
}
printf("\n");
uint8_t hash[32];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, sizeof(data));
SHA256_Final(hash, &sha256);
printf("Hash: ");
for(int i=0; i < 32; i++) {
data[i] = i;
printf("%02x",hash[i]);
}
printf("\n");
/* create and verify signature */
ECDSA_SIG* signature = ECDSA_do_sign(hash, 32, eckey);
/* hash[0] = 0xff; // Uncomment to test if verification fails with a wrong hash */
if (1 != ECDSA_do_verify(hash, 32, signature, eckey)) {
printf("Failed to verify EC Signature\n");
} else {
printf("Verified EC Signature\n");
}
/*print R & S value in hex format */
char* hexR = BN_bn2hex(signature->r);
char* hexS = BN_bn2hex(signature->s);
printf("R: %s \nS: %s\n", hexR, hexS);
/* export raw signature to DER-encoded format */
int sigSize = i2d_ECDSA_SIG(signature, NULL);
uint8_t* derSig = (uint8_t*)malloc(sigSize);
uint8_t* p = derSig; //memset(sig_bytes, 6, sig_size);
sigSize= i2d_ECDSA_SIG(signature, &p);
EVP_PKEY* pkey = EVP_PKEY_new();
EVP_PKEY_set1_EC_KEY(pkey, eckey);
/* write files */
FILE* fp = fopen("pubkey.pem", "w");
PEM_write_PUBKEY(fp, pkey);
fclose(fp);
fp = fopen("privkey.pem", "w");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, 0, NULL);
fclose(fp);
fp = fopen("data.bin", "w");
fwrite(data, 1, sizeof(data), fp);
fclose(fp);
fp = fopen("data_sig.der", "w");
fwrite(derSig, 1, sigSize, fp);
fclose(fp);
/* free runtime allocated res */
free(derSig);
OPENSSL_free(hexPKey);
OPENSSL_free(hexR); OPENSSL_free(hexS);
BN_free(prv);
EC_POINT_free(pub);
EC_GROUP_free(ecgroup);
EC_KEY_free(eckey);
}
现在openssl检查有效:
$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin
Verified OK