1. 程式人生 > >SM2演算法第二十五篇:ECDSA數字簽名演算法原理與實現

SM2演算法第二十五篇:ECDSA數字簽名演算法原理與實現

---------------------------------------------轉載原因------------------------------------------------- 這邊部落格中有關 EC_KEY_set_private_key和EC_KEY_set_public_key函式 EC_POINT_mul
對於理解SM2有很大幫助 ---------------------------------------------轉載原因-------------------------------------------------
ECDSA的全名是Elliptic Curve DSA,即橢圓曲線DSA。它是Digital Signature Algorithm (DSA)應用了橢圓曲線加密演算法的變種。橢圓曲線演算法的原理很複雜,但是具有很好的公開金鑰演算法特性,通過公鑰無法逆向獲得私鑰。 第一部分 : DSA的簽名和驗證過程 要了解ECDSA,首先要了解DSA簽名的過程和驗證過程。為了理解的方便,這裡省去諸多DSA演算法的細節,僅就重要的幾個點進行討論。 1. 簽名過程     假設要簽名的訊息是一個字串:“Hello World!”。DSA簽名的第一個步驟是對待簽名的訊息生成一個訊息摘要。不同的簽名演算法使用不同的訊息摘要演算法。比如,DSS使用SHA1來生成160位元的摘要,而ECDSA256使用SHA256生成256位元的摘要。     摘要生成結束後,應用簽名演算法對摘要進行簽名:
  1. 產生一個隨機數k
  2. 利用隨機數k,計算出兩個大數r和s。將r和s拼在一起就構成了對訊息摘要的簽名。
    這裡需要注意的是,因為隨機數k的存在,對於同一條訊息,使用同一個演算法,產生的簽名是不一樣的。從函式的角度來理解,簽名函式對同樣的輸入會產生不同的輸出。因為函式內部會將隨機值混入簽名的過程。
2. 驗證過程     關於驗證過程,這裡不討論它的演算法細節。從巨集觀上看,訊息的接收方從簽名中分離出r和s,然後利用公開的金鑰資訊和s計算出r。如果計算出的r和接收到的r值相同,則表示驗證成功。否則,表示驗證失敗。
第二部分 : 用Openssl來實現ECDSA簽名 Openssl實現了ECDSA演算法,並預定義好了各個橢圓曲線的引數。以下以RFC4745中定義的ECDSA256為例,詳述用Openssl實現ECDSA簽名的過程。關於ECDSA演算法的各種資料結構的意義和介面的使用方法,可以參考Openssl的官方文件。 第一步 - 計算訊息摘要 Openssl的上層介面EVP提供了計算訊息摘要和簽名各種藉口,前提是必須有預定義好的EVP_MD。對於ECDSA演算法,Openssl預定義好了一個EVP_ecdsa結構,其中定義的訊息摘要演算法是SHA1,並不是我們需要的SHA256。因此,不能直接使用EVP_DigestSignFinal()介面一步生成簽名,需要分開計算摘要和簽名。 程式碼如下:

第二步 - 計算對摘要的簽名 ECDSA簽名演算法是一個確定的演算法。不同的橢圓曲線只有引數上的不同。所以,算出正確簽名的前提是設定正確的引數。ECDSA簽名的輸入引數有:待簽名的數字摘要,數字摘要的長度,金鑰EC_KEY。 金鑰可以來自於私鑰檔案,也可以隨機生成。如果隨機生成,則程式碼如下:
這裡,首先通過橢圓曲線的識別符號NID_X9_62_prime256v1生成一個EC_KEY。通過這種方式生成的EC_KEY裡已經包含了橢圓曲線的引數。否則,需要手動設定EC_GROUP。然後呼叫EC_KEY_generate_key來生成私鑰和公鑰。 ECDSA_do_sign的返回值是一個包含了r和s的資料結構。可以呼叫i2d_ECDSA_SIG函式將其編碼成DER結構。但是IPSec的payload中傳輸的是(r,s)的聯合,所以需要將這兩個BIGNUM轉換成二進位制位元流。 前面提到,金鑰可以來自於私鑰檔案。如果金鑰來自於私鑰檔案,可以首先呼叫PEM的相關函式,生成EVP_PKEY,然後呼叫EVP_PKEY_get1_EC_KEY函式從EVP_PKEY中取得EC_KEY。需要注意的是,從EVP_PKEY中取得的EC_KEY可能沒有設定橢圓曲線引數EC_GROUP。所以,或者手動設定EC_GROUP,或者建立一個新的EC_KEY,然後呼叫EC_KEY_set_private_key和EC_KEY_set_public_key函式將私鑰和公鑰設定進來。 第三部分 : 其他
如果只知道私鑰和所使用橢圓曲線,可以通過EC_POINT_mul函式生成公鑰。第一個引數是EC_GROUP,第二個引數儲存生成的公鑰,第三個引數是私鑰,其他引數忽略。