【问题标题】:How to sign a file using libssl?如何使用 libssl 对文件进行签名?
【发布时间】:2011-10-15 22:26:37
【问题描述】:

我想使用 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 发布的代码: How to read key file for use with 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 字节匹配 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;
}

【问题讨论】:

    标签: c openssl rsa


    【解决方案1】:

    您所拥有的是哈希值的 ASN.1 编码。

    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                                          .+=
    
    30 - SEQUENCE
    21 - length (33 bytes)
     30 - SEQUENCE
     09 - length (9 bytes)
      06 - OID
      05 - length (5 bytes)
       2b 0e 03 02 1a = 1 2 14 3 2 26 = SHA-1
      05 - NULL
      00 - length (0 bytes)
     04 - Octet String
     14 - length (20 bytes)
      9f ... 3d - contents (the digest)
    

    您究竟是如何生成摘要的(在代码中)?看起来您使用的任何东西都将其转换为 ASN.1 而不是将其保留为“原始”,这就是您签署的内容。

    【讨论】:

    • 谢谢,现在这很有意义.. 我只是不知道如何将其保留为原始哈希.. 尚未。我用这个功能更新了帖子。如您所见,我没有单独进行散列,因为它是由 EVP_Sign* 函数隐式完成的。所以,如果你知道我该如何改变它,请告诉我。
    • 看起来 EVP_Sign 遵循 EMSA-PKCS1-v1_5(请参阅 tools.ietf.org/html/rfc3447#section-9.2)。如您所见,第 2 步是“编码”,它会产生您得到的输出。我不确定这是默认行为还是固定行为。当我需要使用其他东西时,我直接调用了 RSA_private_encrypt。
    猜你喜欢
    • 2011-05-11
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多