c - 使用 C 例程和 openssl dgst、rsautl 命令时的不同签名

标签 c openssl rsa signature

我正在使用以下语句创建 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;
}

最佳答案

pkeyutl 命令应该优于 rsautl,因为 pkeyutl 可以处理任何算法。要在命令行上获得相同的签名,您应该使用以下命令:

openssl pkeyutl -sign -in testfile.sha1 -inkey ksign_private.pem -pkeyopt digest:sha1 -outfile testfile.sig

重要的部分是告诉 openssl 您正在使用摘要值。否则它似乎正在签署您的摘要的摘要。

关于c - 使用 C 例程和 openssl dgst、rsautl 命令时的不同签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9380856/

相关文章:

c - 如何关闭 GCC 中的所有优化

c - 为什么多了一个数字?

c - SQL 中的外部 C 函数

c - gprof 输出为空

c# - 使用 Azure Key Vault RSA key 加密和解密字符串

c - OpenSSL:在没有 SSL_read()/SSL_write() 的情况下执行加密/解密

Java 1.8.0_271 不符合 TLS RFC : during handshake, 服务器在没有 close_notify 或警报的情况下关闭 TCP 连接

apache - OpenSSL 在 csr 文件中生成未知的电子邮件地址?

java - 使用 OpenSSL 签名消息;无法使用 Android Java 进行验证

java - RSA 安全 ID 的替代解决方案