Ecdsa

ECDSA 的 PEM 格式

  • December 6, 2015

我一直在查看Coinapult 的 API 文件,其中詳細介紹了 PEM 格式在*python-ecdsa*中的使用。具體來說,私鑰和公鑰需要使用 PEM 進行格式化。

讓我們使用 Coinapult 指定的公鑰:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWp9wd4EuLhIZNaoUgZxQztSjrbqgTT0w
LBq8RwigNE6nOOXFEoGCjGfekugjrHWHUi8ms7bcfrowpaJKqMfZXg==
-----END PUBLIC KEY-----

使用 python-ecdsa:

vk = ecdsa.VerifyingKey.from_pem(ECC_COINAPULT_PUB)
s = vk.to_string()
s.encode('hex')   
>>> "5a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e"

或者,如果它是比特幣公鑰,那就是045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e

好的,這是有道理的,但是當我們在前導和尾隨之間獲取 base64 編碼數據時-----BEGIN-----

base64_data = "".join(ECC_COINAPULT_PUB[27:-26 ].split('\n'))
s = base64.b64decode(base64_data)
result = s.encode("hex")
>>> "3056301006072a8648ce3d020106052b8104000a034200045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e"  # WTF is this??

請注意,PEM 格式解碼為某種 DER 字元串,3056301006072a8648ce3d020106052b8104000a034200045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e但是這個 DER 字元串到底是什麼?我看到5a9f7077....a8c7d95e在那個字元串中,那麼前導字節是什麼意思?

問題: 1. 如何在不使用 python-ecdsa 的情況下將pubkey 編碼為 PEM 格式?2.私鑰與公鑰的過程是否相同?

#0 格式是什麼?****SubjectPublicKeyInfo正如您部分猜到的那樣,這是來自 X.509 的 ASN.1 類型的 DER 編碼的“PEM”裝甲,作為RFC5280 第 4.1 節特別是 4.1.2.7重新發布以供 Internet 使用。為了支持多種算法,包括將來的新算法,這個結構是一個SEQUENCE標識AlgorithmIdentifier算法的(使用OBJECT IDENTIFIER算法和各種類型的參數,取決於算法),後跟一個BIT STRING包含以某種格式編碼的鍵值的這取決於算法。特定於 ECDSA(和 ECDH)的 AlgId 和密鑰格式在RFC3279 第 2.3.5 節中,儘管您可以忽略關於ECParameters因為實際上每個人都使用更簡單的namedCurve OBJECT IDENTIFIER選項,而密鑰格式只是 SEC1/X9.62 點。

301006072a8648ce3d020106052b8104000a是 AlgId 並解碼為

   0:d=0  hl=2 l=  16 cons: SEQUENCE
   2:d=1  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
  11:d=1  hl=2 l=   5 prim: OBJECT            :secp256k1

(正如您已經知道的,“PEM”只是 DER 的 base64,有間隔的換行符,加上----BEGIN whatever-----頂部的-----END whatever-----一行和底部的一行。)

**#1 沒有 python 編碼?**除了自己實現(部分)DER(如果你願意的話,這並不難),我看到你連結到的頁面談論了很多關於 OpenSSL 兼容性:對於 C 或可以(輕鬆)呼叫 C 的語言的程序,這是許多,OpenSSL 可以生成、讀取、寫入和使用這種格式的 ECC 密鑰(以及未裝甲的 DER 形式)。Java 7+ 密碼學可以做到,但標準提供者僅在 DER 中;對於 PEM,您必須自己解除/解除裝甲或使用<http://www.BouncyCastle.org>反而。我希望 dot-NET 可以做到,但我不使用它,也不能肯定地說。我知道我已經看到了 DER 的 perl 模組,但不知何故,即使那是它的目的,我也永遠無法在 CPAN 中找到東西。如果您想要更具體的答案,請修改您的問題(或者如果它足夠不同,請提出一個新問題)。

**#2 私鑰?該頁面說它使用-----BEGIN EC PRIVATE KEY-----的可能是OpenSSL 中的兩種“傳統”格式之一:**未加密或加密。由於範例沒有顯示任何密碼,我將假設前者。如果您查看密鑰文件並看到行Proc-type之後但在 base64 數據之前插入的DEK-info它是傳統加密的,並且更複雜。-----BEGIN

沒有它,它是由 C.4 中http://www.secg.org/的 SEC1 文件定義的私鑰結構,其中包含一個OCTET STRING用於私鑰(實際上是一個整數,但沒有這樣編碼),定義的參數在 C.2 中,如果您仔細檢查,它基本上等同於 RFC 3279 中的內容,並且再次BIT STRING包含公鑰(一個點)。

OpenSSL 還支持私鑰的“新”(大約 2000 年!)PKCS#8 格式。與用於公鑰的 X.509 SPKI 非常相似,這是一個通用包裝器,基本上是AlgorithmIdentifier算法加上OCTET STRING包含取決於算法的密鑰值,除了 PKCS#8 還具有在 PKCS#8 級別進行加密的選項(相對於“PEM”級別)。我不知道 python 模組是否處理這些格式,如果沒有,您是否想使用它們從而與 python 模組不兼容。如果您不想使用 PKCS#8 並且確實想使用 OpenSSL,請小心使用特定的 EC 常式,而不是通用的常式。

引用自:https://bitcoin.stackexchange.com/questions/41666