2009-07-23 70 views
2

我希望在使用EC密鑰簽署數據期間提供OpenSSL特定數據以用作隨機種子。我正在做這個比較我的應用程序與另一個參考(閉源)。該實用程序將該文件與私鑰相關聯,將文件與數據一起簽名,並將隨機數據作爲參數進行歸檔。如何提供用於ECDSA簽名的OpenSSL隨機數據?

我已經有EC密鑰的生成和數據簽名,但無法比較兩個應用,因爲我沒有共同點。 OpenSSL生成用於簽署數據的隨機數據(可能來自/ dev/random),因此每次運行都會給我一個不同的簽名。

我試過RAND_clear()結合RAND_add(),但不斷變化的簽名。要麼我不理解整個ECDSA概念,要麼我做錯了什麼。

我比較應用程序的第二個選項是導入公鑰並驗證引用程序生成的簽名。這是更好的選擇,但我無法導入給定的示例公鑰(83個字符的十六進制字符串)。 EC_POINT_oct2point()不斷給我空結果。

任何幫助/指針/引用將不勝感激。

char * key_as_binary_data; //369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702 
int data_size; //Size of the key buffer 
EC_POINT * ecpoint = NULL; 
EC_GROUP * ecgroup = NULL; 
EC_KEY * eckey = NULL; 
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; 
int asn1_flag = OPENSSL_EC_NAMED_CURVE; 

eckey = EC_KEY_new(); 
ecpoint = EC_POINT_new(ecgroup); 
ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1")); 
EC_GROUP_set_asn1_flag(ecgroup, asn1_flag); 
EC_GROUP_set_point_conversion_form(ecgroup, form); 
EC_KEY_set_group(eckey,ecgroup); 
EC_KEY_generate_key(eckey); 

//This gives me a null ecpoint 
EC_POINT_oct2point(ecgroup,ecpoint,key_as_binary_data,data_size-1,ctx); 
EC_KEY_set_public_key(eckey,ecpoint); 
+1

如果你想與EC_POINT_oct2point()的幫助,你應該告訴我們你是如何調用它。 – caf 2009-07-23 12:19:52

回答

0

簽名程序純粹是爲了讓其他人確認你簽署了它。它是您的私鑰,用於在沒有私鑰的情況下對郵件(或任何數據)進行簽名。

該算法在維基百科上概述Elliptic_Curve_DSA 閱讀「簽名生成算法」,它顯示隨機數據用於協助簽名的強度,並使其難以找出私鑰。

因此,您應該期望簽名每次都有所不同,因爲這不僅僅是一個散列。

請參閱「簽名驗證算法」一節以查看驗證步驟是您希望用來確認您的openssl版本輸出的有效簽名w.r.t. ECDSA方法和封閉的源程序。

+0

該參考程序聲明支持FIPS 186-2,並作爲一種實用程序提供用於簽署微處理器上使用的數據。我希望我可以在我的程序和參考程序中使用相同的私鑰,隨機數據和數據,並獲得相同的簽名。 如果沒有能力確保兩個應用程序使用相同的隨機數據,我將不得不退回到簽名的完整驗證。感謝您的意見。 – Belrog 2009-07-23 13:33:30

0

我找不到RAND_clear的文檔,所以無法評論爲什麼它不會導致可重複的隨機數。

但即使你完成了,你想要的東西也許是不可能的。 ECDSA簽名生成需要在特定範圍內選擇一個隨機整數。該算法的兩種不同實現可能會有完全不同的想法,關於如何從它們的熵源生成這樣一個整數。 AFAIK將熵位轉換爲所需數量的方法不是ECDSA算法的一部分。所以,即使你給他們相同的種子

int random_number = (rand() * n)/RAND_MAX; 

因此,例如,(當然是很糟糕的例子),一個實現可能做到這一點:

int random_number = rand() % n; 

,另一個可以這樣做數據,你可能仍然會從不同的實現中獲得不同的簽名。您所能做的只是驗證您是否生成了有效的簽名。

+0

是的,缺少文檔是我的主要障礙。我正在通過代碼試圖找到我需要的方法。感謝您的澄清。看來我回頭想弄清楚如何導入該公鑰。我希望提供隨機數據,而不僅僅是種子。那我腦子裏已經解決了隨機數據組件,但是我還沒有絕望到能夠隨機引擎。 – Belrog 2009-07-23 13:55:18

2

這是你應該如何去加載一個公鑰:

EC_KEY *key = NULL; 
    EC_POINT *pub_key; 
    const EC_GROUP *group; 

    SSL_library_init(); 
    SSL_load_error_strings(); 

    key = EC_KEY_new_by_curve_name(NID_sect163k1); 
    group = EC_KEY_get0_group(key); 
    pub_key = EC_POINT_new(group); 

    EC_POINT_hex2point(group, 
    "369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702", pub_key, NULL); 

    EC_KEY_set_public_key(key, pub_key); 

    if (!EC_KEY_check_key(key)) { 
    printf("EC_KEY_check_key failed:\n"); 
    printf("%s\n",ERR_error_string(ERR_get_error(),NULL)); 
    } else { 
    printf("Public key verified OK\n"); 
    } 

這似乎驗證OK,所以它應該檢查的簽名工作。

我覺得你的錯誤可能剛剛傳遞一個NULL(在ecgroup)至EC_POINT_new()。

2

即使您清除池並重置它,但得到不同結果的原因是默認情況下,OpenSSL的RAND實現會將pid散列到輸出塊中(確保即使使用相同種子的應用程序也可以沒有得到相同的PRNG輸出,因爲99.9%的時間是壞事)。

此外,即使不是這種情況下,這是不可能的參考應用程序使用相同的PRNG是OpenSSL使用打開種子文件到一系列的隨機字節。 (當然,除非您的參考應用程序實際上也使用OpenSSL)。你需要做的是首先找出參考應用使用的PRNG類型 - 這可能是像X9.31或FIPS-186的標準PRNG設計,或者可能是完全自定義的。然後重新實現OpenSSL的設計並通過RAND_set_rand_method插入。

至於驗證:它看起來像你需要轉線:

ecpoint = EC_POINT_new(ecgroup); 
    ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1")); 

否則ecpoint設置爲從一開始就空,這將導致EC_KEY_generate_key失敗,因爲該組設置爲NULL 。從的OpenSSL 0.9.8k的密碼報價/ EC/ec_key.c:

if (!eckey || !eckey->group) 
    { 
    ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER); 
    return 0; 
    } 
+0

這很有道理。參考應用程序使用給定的文件作爲隨機數據的來源。當然,他們可能會隨機做任何事情,但比較連續運行的簽名他們是平等的。我相信這表明給定的隨機源實際上是這樣使用的,沒有修改。 他們的內部RAND引擎的OpenSSL種子顯然是更好的方式去隨機 - 除非你不想隨機:) 交換行是一個明顯的錯誤,難怪我錯過了它。感謝您的幫助。 – Belrog 2009-08-12 11:42:26

1

,您可以控制OpenSSL的使用方法簽名過程中產生的隨機數據:

ECDSA_SIG* ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);

其中kinv是簽名期間使用的隨機數。