使用 C 例程和 openssl dgst、rsautl 命令时的不同签名
我使用以下语句来创建 RSA 公钥和私钥。
openssl genrsa -out ksign_private.pem 1024 openssl rsa -in ksign_private.pem -pubout > ksign_public.pem
然后我有一个程序使用 openssl libcrypto 中的 PEM_read_RSAPrivateKey、EVP_PKEY_assign_RSA、EVP_SignInit、EVP_SignUpdate、EVP_SignFinal 函数来生成签名文件。
我还有例程来验证是否可以使用 PEM_read_RSA_PUBKEY、EVP_PKEY_assign_RSA、EVP_VerifyInit、EVP_VerifyUpdate、EVP_VerifyFinal 来验证签名。 下面附有这些例程的源代码。
使用这些函数时,我可以创建 SHA1 签名,使用私钥对其进行加密,并使用公钥对其进行解密。
但是,我尝试使用 openssl rsautl 使用相同的数据文件、相同的私钥、公钥,并且由 openssl rsautl 创建的签名有很大不同。
openssl dgst -sha1 -binary < myData > testfile.sha1
openssl rsautl -sign -in testfile.sha1 -inkey ksign_private.pem -keyform PEM -out testfile.sig
谁能告诉我在使用 openssl rsautl 或 dgst 命令时我使用了哪些选项是错误的?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <openssl/sha.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
int ksignEvpSign(FILE * private_key, FILE * inFileFP, FILE * outFileFP);
int ksignEvpVerify(FILE * public_key, FILE * dataFileFP, FILE * signFileFP);
int ksignEvpSign(FILE * privateKeyFP, FILE * inFileFP, FILE * outFileFP)
{
RSA *rsa_pkey = NULL;
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_MD_CTX ctx;
unsigned char buffer[4096];
size_t len;
unsigned char *sig;
unsigned int siglen;
if (!PEM_read_RSAPrivateKey(privateKeyFP, &rsa_pkey, NULL, NULL)) {
fprintf(stderr, "Error loading RSA Private Key File.\n");
return 2;
}
if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey)) {
fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
return 3;
}
EVP_MD_CTX_init(&ctx);
if (!EVP_SignInit(&ctx, EVP_sha1())) {
fprintf(stderr, "EVP_SignInit: failed.\n");
EVP_PKEY_free(pkey);
return 3;
}
while ((len = fread(buffer, 1, sizeof buffer, inFileFP)) > 0) {
if (!EVP_SignUpdate(&ctx, buffer, len)) {
fprintf(stderr, "EVP_SignUpdate: failed.\n");
EVP_PKEY_free(pkey);
return 3;
}
}
if (ferror(inFileFP)) {
perror("input file");
EVP_PKEY_free(pkey);
return 4;
}
sig = malloc(EVP_PKEY_size(pkey));
if (!EVP_SignFinal(&ctx, sig, &siglen, pkey)) {
fprintf(stderr, "EVP_SignFinal: failed.\n");
free(sig);
EVP_PKEY_free(pkey);
return 3;
}
fwrite(sig, siglen, 1, outFileFP);
free(sig);
EVP_PKEY_free(pkey);
return 0;
}
int ksignEvpVerify(FILE * publicKeyFP, FILE * dataFileFP, FILE * sigFileFP)
{
RSA *rsa_pkey = NULL;
EVP_PKEY *pkey;
EVP_MD_CTX ctx;
unsigned char buffer[4096];
size_t len;
unsigned char *sig;
unsigned int siglen;
struct stat stat_buf;
if (!PEM_read_RSA_PUBKEY(publicKeyFP, &rsa_pkey, NULL, NULL)) {
fprintf(stderr, "Error loading RSA public Key File.\n");
return 2;
}
pkey = EVP_PKEY_new();
if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey)) {
fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
return 3;
}
/* Read the signature */
if (fstat(fileno(sigFileFP), &stat_buf) == -1) {
fprintf(stderr, "Unable to read signature \n");
return 4;
}
siglen = stat_buf.st_size;
sig = (unsigned char *)malloc(siglen);
if (sig == NULL) {
fprintf(stderr, "Unable to allocated %d bytes for signature\n",
siglen);
return 5;
}
if ((fread(sig, 1, siglen, sigFileFP)) != siglen) {
fprintf(stderr, "Unable to read %d bytes for signature\n",
siglen);
return 6;
}
/*
printf("Signature:");
for (i = 0; i < siglen; i++) {
fprintf(stdout, "%02x", sig[i]);
if (i % 16 == 15)
fprintf(stdout, "\n");
}
fprintf(stdout, "\n");
*/
EVP_MD_CTX_init(&ctx);
if (!EVP_VerifyInit(&ctx, EVP_sha1())) {
fprintf(stderr, "EVP_SignInit: failed.\n");
EVP_PKEY_free(pkey);
return 7;
}
while ((len = fread(buffer, 1, sizeof buffer, dataFileFP)) > 0) {
if (!EVP_VerifyUpdate(&ctx, buffer, len)) {
fprintf(stderr, "EVP_SignUpdate: failed.\n");
EVP_PKEY_free(pkey);
return 8;
}
}
if (ferror(dataFileFP)) {
perror("input file");
EVP_PKEY_free(pkey);
return 9;
}
if (!EVP_VerifyFinal(&ctx, sig, siglen, pkey)) {
fprintf(stderr, "EVP_VerifyFinal: failed.\n");
free(sig);
EVP_PKEY_free(pkey);
return 10;
}
free(sig);
EVP_PKEY_free(pkey);
return 0;
}
I am using following statement to create a RSA public and private key.
openssl genrsa -out ksign_private.pem 1024
openssl rsa -in ksign_private.pem -pubout > ksign_public.pem
Then I have program that uses, PEM_read_RSAPrivateKey, EVP_PKEY_assign_RSA, EVP_SignInit, EVP_SignUpdate, EVP_SignFinal functions from openssl libcrypto to generate signature file.
I also have routine that verifies that signature can be verified using PEM_read_RSA_PUBKEY, EVP_PKEY_assign_RSA, EVP_VerifyInit, EVP_VerifyUpdate, EVP_VerifyFinal.
Source code for these routines is attached below.
When using these functions I can create SHA1 signature, encrypt it with private key, and decrypt it using public key.
However I tried to use the same data file, same private, public key using the openssl rsautl and the signature that is getting created by openssl rsautl is vastly different.
openssl dgst -sha1 -binary < myData > testfile.sha1
openssl rsautl -sign -in testfile.sha1 -inkey ksign_private.pem -keyform PEM -out testfile.sig
Can any one tell me what options I am using wrong when using openssl rsautl or dgst command?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <openssl/sha.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
int ksignEvpSign(FILE * private_key, FILE * inFileFP, FILE * outFileFP);
int ksignEvpVerify(FILE * public_key, FILE * dataFileFP, FILE * signFileFP);
int ksignEvpSign(FILE * privateKeyFP, FILE * inFileFP, FILE * outFileFP)
{
RSA *rsa_pkey = NULL;
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_MD_CTX ctx;
unsigned char buffer[4096];
size_t len;
unsigned char *sig;
unsigned int siglen;
if (!PEM_read_RSAPrivateKey(privateKeyFP, &rsa_pkey, NULL, NULL)) {
fprintf(stderr, "Error loading RSA Private Key File.\n");
return 2;
}
if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey)) {
fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
return 3;
}
EVP_MD_CTX_init(&ctx);
if (!EVP_SignInit(&ctx, EVP_sha1())) {
fprintf(stderr, "EVP_SignInit: failed.\n");
EVP_PKEY_free(pkey);
return 3;
}
while ((len = fread(buffer, 1, sizeof buffer, inFileFP)) > 0) {
if (!EVP_SignUpdate(&ctx, buffer, len)) {
fprintf(stderr, "EVP_SignUpdate: failed.\n");
EVP_PKEY_free(pkey);
return 3;
}
}
if (ferror(inFileFP)) {
perror("input file");
EVP_PKEY_free(pkey);
return 4;
}
sig = malloc(EVP_PKEY_size(pkey));
if (!EVP_SignFinal(&ctx, sig, &siglen, pkey)) {
fprintf(stderr, "EVP_SignFinal: failed.\n");
free(sig);
EVP_PKEY_free(pkey);
return 3;
}
fwrite(sig, siglen, 1, outFileFP);
free(sig);
EVP_PKEY_free(pkey);
return 0;
}
int ksignEvpVerify(FILE * publicKeyFP, FILE * dataFileFP, FILE * sigFileFP)
{
RSA *rsa_pkey = NULL;
EVP_PKEY *pkey;
EVP_MD_CTX ctx;
unsigned char buffer[4096];
size_t len;
unsigned char *sig;
unsigned int siglen;
struct stat stat_buf;
if (!PEM_read_RSA_PUBKEY(publicKeyFP, &rsa_pkey, NULL, NULL)) {
fprintf(stderr, "Error loading RSA public Key File.\n");
return 2;
}
pkey = EVP_PKEY_new();
if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey)) {
fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
return 3;
}
/* Read the signature */
if (fstat(fileno(sigFileFP), &stat_buf) == -1) {
fprintf(stderr, "Unable to read signature \n");
return 4;
}
siglen = stat_buf.st_size;
sig = (unsigned char *)malloc(siglen);
if (sig == NULL) {
fprintf(stderr, "Unable to allocated %d bytes for signature\n",
siglen);
return 5;
}
if ((fread(sig, 1, siglen, sigFileFP)) != siglen) {
fprintf(stderr, "Unable to read %d bytes for signature\n",
siglen);
return 6;
}
/*
printf("Signature:");
for (i = 0; i < siglen; i++) {
fprintf(stdout, "%02x", sig[i]);
if (i % 16 == 15)
fprintf(stdout, "\n");
}
fprintf(stdout, "\n");
*/
EVP_MD_CTX_init(&ctx);
if (!EVP_VerifyInit(&ctx, EVP_sha1())) {
fprintf(stderr, "EVP_SignInit: failed.\n");
EVP_PKEY_free(pkey);
return 7;
}
while ((len = fread(buffer, 1, sizeof buffer, dataFileFP)) > 0) {
if (!EVP_VerifyUpdate(&ctx, buffer, len)) {
fprintf(stderr, "EVP_SignUpdate: failed.\n");
EVP_PKEY_free(pkey);
return 8;
}
}
if (ferror(dataFileFP)) {
perror("input file");
EVP_PKEY_free(pkey);
return 9;
}
if (!EVP_VerifyFinal(&ctx, sig, siglen, pkey)) {
fprintf(stderr, "EVP_VerifyFinal: failed.\n");
free(sig);
EVP_PKEY_free(pkey);
return 10;
}
free(sig);
EVP_PKEY_free(pkey);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
pkeyutl
命令应优先于rsautl
,因为pkeyutl
可以处理任何算法。要在命令行上获得相同的签名,您应该使用以下内容:重要的部分是告诉
openssl
您正在使用摘要值。否则它看起来像是在签署你的摘要的摘要。The
pkeyutl
command should be preferred torsautl
sincepkeyutl
can handle any algorithm. To obtain the same signature on the command line, you should use the following:The important part is telling
openssl
that you're using a digest value. Otherwise it seems to be signing a digest of your digest.您可以直接使用 dgst 命令对数据进行哈希和签名,例如:
openssl dgst -sha1 -binary -sign privkey.pem
openssl dgst -sha1 -binary -sign privkey.pem
openssl dgst -sha1 -binary -sign privkey.pem <我的数据> mySignature
请参阅文档了解所有选项。
You can directly use
dgst
command to hash and sign data like:openssl dgst -sha1 -binary -sign privkey.pem < myData > mySignature
see docs for all options.