如何使用 libssl 对文件进行签名?
我想使用 OpenSSL 为文件创建签名。 我相信我的结果应该与 openssl 生成的 testfile.sig 相匹配:
$ openssl dgst -sha1 -binary < testfile > testfile.sha1
$ openssl rsautl -sign -in testfile.sha1 -inkey rsa_private.pem -keyform PEM -out testfile.sig
$ openssl rsautl -verify -inkey rsa_public.pem -pubin -in testfile.sig -hexdump
Loading 'screen' into random state - done
0000 - 9f 23 88 15 2b af d6 a6-9f 4f 1f 7e ee b0 90 dd .#..+....O.~....
0010 - 69 99 2b 3d i.+=
因此,我使用了此处发布的 caf 代码: 如何读取密钥文件以与 HMAC_Init_ex 一起使用( ) 只是添加了一小块来将 EVP_SignFinal() 之后的数据保存到文件中,所以我 可以用 openssl 和公钥验证它:
FILE * fp = fopen("out.sig", "wb");
if (fp) {
printf("Writing the signature in a file. # of bytes: %u.\n", sig_len);
fwrite(sig, 1, sig_len, fp);
fclose(fp);
}
令我惊讶的是,我得到了这个:
$ openssl rsautl -verify -inkey rsa_public.pem -pubin -in out.sig -hexdump
Loading 'screen' into random state - done
0000 - 30 21 30 09 06 05 2b 0e-03 02 1a 05 00 04 14 9f 0!0...+.........
0010 - 23 88 15 2b af d6 a6 9f-4f 1f 7e ee b0 90 dd 69 #..+....O.~....i
0020 - 99 2b 3d .+=
现在,如果您观察 out.sig 验证的输出,您会看到最后 20 bytes 匹配 testfile.sig 验证的数据输出。这 20 个字节是 确实是我文件的 SHA-1 哈希值。但开头的前 15 个字节是什么? EVP_SignInit() / EVP_SignUpdate() / EVP_SignFinal() 不应该只将哈希值放入 消息,还是我遗漏了一些明显的东西?
如果您需要更多信息,请告诉我。 感谢
用于签署文件的完整功能:
int do_evp_sign(FILE * rsa_pkey_file, FILE * in_file)
{
OpenSSL_add_all_digests();
ERR_load_crypto_strings();
EVP_PKEY * pkey = PEM_read_PrivateKey(rsa_pkey_file, NULL, NULL, NULL);
if (pkey == NULL) {
ERR_print_errors_fp(stderr);
return 1;
}
fseek(in_file, 0, SEEK_END);
const size_t lSize = ftell(in_file);
rewind(in_file);
EVP_MD_CTX md_ctx;
EVP_SignInit(&md_ctx, EVP_sha1());
size_t len;
unsigned char buffer[4096];
size_t bytesLeft = lSize;
while (bytesLeft > 0) {
const size_t count = (bytesLeft > sizeof(buffer) ? sizeof(buffer) : bytesLeft);
len = fread(buffer, 1, count, in_file);
if (len != count) {
fprintf(stderr, "Read error! len (%u) != count (%u).\n", len, count);
EVP_PKEY_free(pkey);
return 1;
}
if (!EVP_SignUpdate(&md_ctx, buffer, len))
{
ERR_print_errors_fp(stderr);
EVP_PKEY_free(pkey);
return 1;
}
bytesLeft -= len;
}
unsigned int sig_len;
unsigned char * sig = (unsigned char *)malloc(EVP_PKEY_size(pkey));
if (!sig) {
fprintf(stderr, "Couldn't allocate %u bytes of memory.\n", EVP_PKEY_size(pkey));
EVP_PKEY_free(pkey);
return 1;
}
if (!EVP_SignFinal(&md_ctx, sig, &sig_len, pkey))
{
ERR_print_errors_fp(stderr);
EVP_PKEY_free(pkey);
free(sig);
return 1;
}
FILE * fTemp = fopen("out.sig", "wb");
if (fTemp) {
printf("Writing the signature to a file. Number of bytes: %u.\n", sig_len);
fwrite(sig, 1, sig_len, fTemp);
fclose(fTemp);
}
printf("Signature: \n");
for (unsigned int i = 0; i != sig_len; ++i)
{
printf("%02x", sig[i]);
if (i % 16 == 15)
printf("\n");
}
printf("\n");
EVP_PKEY_free(pkey);
free(sig);
return 0;
}
I want to create a signature for a file using OpenSSL.
I believe that my result should match the testfile.sig generated by openssl this way:
$ openssl dgst -sha1 -binary < testfile > testfile.sha1
$ openssl rsautl -sign -in testfile.sha1 -inkey rsa_private.pem -keyform PEM -out testfile.sig
$ openssl rsautl -verify -inkey rsa_public.pem -pubin -in testfile.sig -hexdump
Loading 'screen' into random state - done
0000 - 9f 23 88 15 2b af d6 a6-9f 4f 1f 7e ee b0 90 dd .#..+....O.~....
0010 - 69 99 2b 3d i.+=
So, I used the code by caf that was posted here:
How to read key file for use with HMAC_Init_ex()
and just added a small piece to save the data after EVP_SignFinal() to a file, so then I
could just verify it with openssl and the public key:
FILE * fp = fopen("out.sig", "wb");
if (fp) {
printf("Writing the signature in a file. # of bytes: %u.\n", sig_len);
fwrite(sig, 1, sig_len, fp);
fclose(fp);
}
And to my suprise, I got this:
$ openssl rsautl -verify -inkey rsa_public.pem -pubin -in out.sig -hexdump
Loading 'screen' into random state - done
0000 - 30 21 30 09 06 05 2b 0e-03 02 1a 05 00 04 14 9f 0!0...+.........
0010 - 23 88 15 2b af d6 a6 9f-4f 1f 7e ee b0 90 dd 69 #..+....O.~....i
0020 - 99 2b 3d .+=
Now, if you observe the output of the verification of out.sig, you'll see that the last 20
bytes match the data output of the verification of testfile.sig. And those 20 bytes are
indeed the SHA-1 hash of my file. But what are the first 15 bytes at the beginning?
Isn't EVP_SignInit() / EVP_SignUpdate() / EVP_SignFinal() supposed to put only the hash in
the message, or am I missing something obvious?
If you need more info, please let me know.
Thanks
Full function that was uset to sign the file:
int do_evp_sign(FILE * rsa_pkey_file, FILE * in_file)
{
OpenSSL_add_all_digests();
ERR_load_crypto_strings();
EVP_PKEY * pkey = PEM_read_PrivateKey(rsa_pkey_file, NULL, NULL, NULL);
if (pkey == NULL) {
ERR_print_errors_fp(stderr);
return 1;
}
fseek(in_file, 0, SEEK_END);
const size_t lSize = ftell(in_file);
rewind(in_file);
EVP_MD_CTX md_ctx;
EVP_SignInit(&md_ctx, EVP_sha1());
size_t len;
unsigned char buffer[4096];
size_t bytesLeft = lSize;
while (bytesLeft > 0) {
const size_t count = (bytesLeft > sizeof(buffer) ? sizeof(buffer) : bytesLeft);
len = fread(buffer, 1, count, in_file);
if (len != count) {
fprintf(stderr, "Read error! len (%u) != count (%u).\n", len, count);
EVP_PKEY_free(pkey);
return 1;
}
if (!EVP_SignUpdate(&md_ctx, buffer, len))
{
ERR_print_errors_fp(stderr);
EVP_PKEY_free(pkey);
return 1;
}
bytesLeft -= len;
}
unsigned int sig_len;
unsigned char * sig = (unsigned char *)malloc(EVP_PKEY_size(pkey));
if (!sig) {
fprintf(stderr, "Couldn't allocate %u bytes of memory.\n", EVP_PKEY_size(pkey));
EVP_PKEY_free(pkey);
return 1;
}
if (!EVP_SignFinal(&md_ctx, sig, &sig_len, pkey))
{
ERR_print_errors_fp(stderr);
EVP_PKEY_free(pkey);
free(sig);
return 1;
}
FILE * fTemp = fopen("out.sig", "wb");
if (fTemp) {
printf("Writing the signature to a file. Number of bytes: %u.\n", sig_len);
fwrite(sig, 1, sig_len, fTemp);
fclose(fTemp);
}
printf("Signature: \n");
for (unsigned int i = 0; i != sig_len; ++i)
{
printf("%02x", sig[i]);
if (i % 16 == 15)
printf("\n");
}
printf("\n");
EVP_PKEY_free(pkey);
free(sig);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您拥有的是哈希值的 ASN.1 编码。
您到底是如何生成摘要的(以代码形式)?看起来您使用的任何内容都将其转换为 ASN.1,而不是保留“原始”,这就是您签名的内容。
What you have there is an ASN.1 encoding of the hash value.
How exactly did you generate the digest (in code)? It looks like whatever you used converted it to ASN.1 instead of leaving it "raw", and that's what you signed.