2017-04-11 44 views
0

我一直在與RSA_verify奇怪的問題掙扎。我正在嘗試使用C和RSA_verify使用C++進行RSA_sign。我使用OpenSSL命令生成了私鑰和證書。不同的消息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; 
} 
+2

沒有顯示你的代碼,問題應該被關閉。但是,RSA_sign的輸出是* not *空終止的字符串,所以使用strlen()是沒有意義的。它可能在任何位置包含嵌入的0字節。 RSA_sign在另一個參數中返回結果的長度。 –

回答

0

瞭解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編碼你的數據。

+0

是的非常感謝bartonjs。那就是問題所在 :) – poohgr8