对于不同的消息,OpenSSL签名长度是不同的

时间:2017-04-11 09:57:50

标签: c++ c openssl rsa

我一直在努力解决RSA_verify的一个奇怪问题。我正在尝试使用C ++使用C和RSA_verify进行RSA_sign。我使用OpenSSL命令生成了私钥和证书。

message = "1.2.0:08:00:27:2c:88:77"

当我使用上面的消息时,生成一个哈希并使用RSA_sign对摘要进行签名,我得到一个长度为256(strlen(signature))的签名,并且从RSA_sign返回的长度也是256.我用这个长度来验证和验证成功。

但是当我使用message = "1.2.0:08:00:27:2c:88:08"时,签名长度为60,RSA_sign返回256.当我使用此长度60来验证它失败时。它也无法验证长度为256。对于某些消息(1.2.0:08:00:27:2c:88:12),生成的签名为零。

我使用SHA256来散列消息,使用NID_SHA256来RSA_sign和RSA_verify这个摘要。我在使用OpenSSL命令生成密钥时使用了-sha256。

我通过解析使用某些字符串操作读取某些标记的XML文件来形成消息。

请建议。

以下是用于签名的代码。

int main(void)  
{  
    int     ret;  
    RSA    *prikey;  
    char *data ;  
    unsigned char* signature;  
    int slen = 0;  
    FILE * fp_priv = NULL;  
    char* privfilepath = "priv.pem";  
    unsigned char* sign = NULL; 

    ERR_load_crypto_strings();

    data = generate_hash();
    printf("Message after generate hash %s: %d\n", data, strlen(data));

    fp_priv = fopen(privfilepath, "r"); 
    if (fp_priv == NULL)
    {
        printf("Private key path not found..");
        return 1;
    }
    prikey = RSA_new();
    prikey = PEM_read_RSAPrivateKey(fp_priv, &prikey, NULL, NULL);
    if (prikey == NULL)
    {
        printf("Private key returned is NULL\n");
        return 1;
    }

    signature = (unsigned char*)malloc(RSA_size(prikey)); 

    if( signature == NULL )
        return 1;

    if(RSA_sign(NID_sha256, (unsigned char*)data, strlen(data), 
         signature, &slen, prikey) != 1) {
        ERR_print_errors_fp(stdout); 
        return 1;
    }
    printf("Signature length while signing... %d : %d : %d ",  
       strlen(signature), slen, strlen(data)); 

    FILE * sig_bin = fopen("sig_bin", "w");
    fprintf(sig_bin, "%s", signature);
    fclose(sig_bin);

    system("xxd -p -c256 sig_bin sig_hex"); 

    RSA_free(prikey);
    if(signature)
        free(signature);    
    return 0; 
} 

1 个答案:

答案 0 :(得分:2)

了解C的一个非常非常重要的事情是它有两个不同类型的同名。

  • char*:这表示字符串的开头。你可以做strstr或strlen之类的事情。
    • 你永远不应该是strstr或strlen,而是strnstr和strnlen,但这是一个不同的问题。
  • char*:这表示数据blob的开头(也就是字节数组,也就是八位字符串),你不能有意义地将strlen / etc应用于它。

RSA_sign使用后者。它返回“数据”,而不是“消息”。所以,在你的代码片段中

printf("Signature length while signing... %d : %d : %d ",  
   strlen(signature), slen, strlen(data));

FILE * sig_bin = fopen("sig_bin", "w");
fprintf(sig_bin, "%s", signature);
fclose(sig_bin);

data来自名为generate_hash()的函数;它可能是非文本的,所以strlen不适用。 signature肯定是数据,因此strlen不适用。由于同样的原因,fprintf也不适用。这些函数通过第一次出现零字节(0x00,'\ 0'等)来识别字符串的结尾。但是0x00在签名,哈希或大量“数据”中是完全合法的。

RSA_sign输出的长度写入传递给第5个参数的地址。你传递了&slen(地址为slen),所以一旦函数退出(成功)slen就是签名的长度。请注意,它很少匹配strlen(签名)。

要将您的签名编写为二进制文件,您应该使用fwrite,例如fwrite(sig_bin, sizeof(char), signature, slen);。如果您希望将其作为文字,则应Base-64对数据进行编码。