如何使用libssl签名文件?

时间:2011-10-15 22:26:37

标签: c openssl rsa

我想使用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个 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;
}

1 个答案:

答案 0 :(得分: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而不是让它“原始”,这就是你所签署的。