2013-06-26 133 views
2

我使用Wei Dai的Crypto ++在我的應用程序中創建了ECDSA密鑰對(secp128r1)。按預期簽署和驗證工作。我不會將消息本身添加到簽名中以最小化簽名長度(正好是32字節)。ECDSA與OpenSSL簽名,使用Crypto ++驗證

然而,當我創建與OpenSSL的簽名:

$ cat test.txt | openssl dgst -ecdsa-with-SHA1 -sign sample.key -keyform DER > act.bin 

OpenSSL的明顯放消息本身,從而導致更大的簽名(例如,39字節)的簽名。如果我設置了CryptoPP::SignatureVerificationFilter::PUT_MESSAGE,我可以使用Crypto ++驗證簽名。

我可以告訴OpenSSL簽署一條消息,而不是將消息放入簽名,使得生成的簽名完全是32字節嗎?

+1

這些額外的字節很可能是由於BER編碼的ASN.1。 – CodesInChaos

回答

7

CodesInChaos是正確的。簽名中的額外字節來自ASN.1編碼,而不是正在簽名的原始消息。例如,這裏是與曲線secp128r1的ECDSA密鑰產生的39字節的簽名:

30 25 02 10 4E 32 32 90 CA D9 BD D2 5F 8B BE 3B 
F2 BF E9 7F 02 11 00 A7 83 A6 68 AD 74 7E 1A 0E 
8F 73 BD DF 7A E8 B5 

30表明一個序列如下。 25告訴你該序列長度爲0x25字節。 02表示序列中的第一項是一個整數。 10告訴你第一個Integer是0x10字節長。以下0x10(16)字節是ECDSA簽名的「r」值。在第一個整數之後是字節02.這告訴你序列的第二整數即將開始。 11告訴你下一個0x11(17)字節組成第二個整數,這是ECDSA簽名的「s」值。這是11個字節,因爲整數的第一個字節是00.只要整數的第一個字節> = 0x80,就插入「00」。這是爲了避免最重要的位是1,這將表示負整數。

所以這一切之後,真正的簽名值是:

r: 4E 32 32 90 CA D9 BD D2 5F 8B BE 3B F2 BF E9 7F 
s: A7 83 A6 68 AD 74 7E 1A 0E 8F 73 BD DF 7A E8 B5 

「額外」字節是ASN.1格式。

+0

在做這種轉換的cryptopp中是否有任何功能? – SandeepAggarwal

+0

@SandeepAggarwal - 是的,您可以使用Crypto ++ ['DSAConvertSignatureFormat'](https://github.com/weidai11/cryptopp/blob/master/dsa.cpp)在ASN.1/DER,P1363和OpenPGP格式之間進行轉換。 ASN.1/DER是一種流行的方式,它被Java,OpenSSL和其他一些使用。 – jww

0

首先你應該知道,128位的EC提供了大約64位的安全性。 第二我不認爲這是openssl增加的消息,因爲5字節是不夠的。 無論如何,你可以使用頭或尾刪除額外的字節。

+0

安全性不是最大的問題,我用它來激活/硬件鎖定我的軟件。 你指的是哪一條「openssl增加的信息」? 當我創建簽名時,我可以選擇是否放置郵件(http://www.cryptopp.com/wiki/SignerFilter)。如果我選擇不這樣做,簽名會變小,但我需要連接簽名和消息來驗證它。 openssl似乎把這個消息導致簽名更長,並且與我的簽名驗證不兼容。我可以告訴openssl dgst不要傳遞消息嗎? – divB

+0

*「...您可以使用頭部或尾部刪除額外的字節...」* - 兩個字節位於流的中間。這兩個字節是參數's'的'INTEGER'的ASN.1類型和長度。 – jww

1

divb>我可以告訴openssl簽署一條消息,而不是將消息放入簽名,使得生成的簽名完全是32字節嗎?

而且

桑迪普>是在有任何cryptopp功能,做到這一點的轉換?

由於@CodesInChaos指出,問題是簽名編碼。另見OpenSSL ECDSA signatures longer than expected

作爲@Sandeep在評論中提出的建議,另一種選擇是讓Crypto ++使用OpenSSL簽名。

這是一個Crypto ++測試程序,用於轉換OpenSSL和Java使用的ASN.1/DER輸出,並將其轉換爲Crypto ++使用的IEEE P1363。它大部分來自Crypto ++ wiki上的Elliptic Curve Digital Signature Algorithm

#include "cryptlib.h" 
#include "eccrypto.h" 
#include "files.h" 
#include "oids.h" 
#include "dsa.h" 
#include "sha.h" 
#include "hex.h" 

#include <iostream> 

using namespace CryptoPP; 

int main(int argc, char* argv[]) 
{ 
    // Load DER encoded public key 
    FileSource pubKey("secp256k1-pub.der", true /*binary*/); 
    ECDSA<ECP, SHA1>::Verifier verifier(pubKey); 

    // Java or OpenSSL created signature. Is is ANS.1 
    // SEQUENCE ::= { r INTEGER, s INTEGER }. 
    const byte derSignature[] = { 
     0x30, 0x44, 0x02, 0x20, 0x08, 0x66, 0xc8, 0xf1, 
     0x6f, 0x15, 0x00, 0x40, 0x8a, 0xe2, 0x1b, 0x40, 
     0x56, 0x28, 0x9c, 0x17, 0x8b, 0xca, 0x64, 0x99, 
     0x37, 0xdc, 0x35, 0xad, 0xad, 0x60, 0x18, 0x4d, 
     0x63, 0xcf, 0x4a, 0x06, 0x02, 0x20, 0x78, 0x4c, 
     0xb7, 0x0b, 0xa3, 0xff, 0x4f, 0xce, 0xd3, 0x01, 
     0x27, 0x5c, 0x6c, 0xed, 0x06, 0xf0, 0xd7, 0x63, 
     0x6d, 0xc6, 0xbe, 0x06, 0x59, 0xe8, 0xc3, 0xa5, 
     0xce, 0x8a, 0xf1, 0xde, 0x01, 0xd5 
    }; 

    // P1363 'r || s' concatenation. The size is 32+32 due to field 
    // size for r and s in secp-256. It is not 20+20 due to SHA-1. 
    byte signature[0x40]; 
    DSAConvertSignatureFormat(signature, sizeof(signature), DSA_P1363, 
          derSignature, sizeof(derSignature), DSA_DER); 

    // Cross check 
    std::cout << "Signature:\n"; 
    ArraySource(signature, sizeof(signature), true, new HexEncoder(new FileSink(std::cout))); 
    std::cout << std::endl; 

    // Message "Attack at dawn!" 
    const byte message[] = { 
     0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x61, 
     0x74, 0x20, 0x64, 0x61, 0x77, 0x6e, 0x21, 0x0a 
    }; 

    // Standard signature checking in Crypto++ 
    // https://www.cryptopp.com/wiki/Elliptic_Curve_Digital_Signature_Algorithm 
    bool result = verifier.VerifyMessage(message, sizeof(message), signature, sizeof(signature)); 
    if (result) 
     std::cout << "Verified message" << std::endl; 
    else 
     std::cout << "Failed to verify message" << std::endl; 

    return 0; 
} 

這裏是運行測試程序的結果。

$ ./test.exe 
Signature (64): 
0866C8F16F1500408AE21B4056289C178BCA649937DC35ADAD60184D63CF4A06784CB70BA3FF4FCE 
D301275C6CED06F0D7636DC6BE0659E8C3A5CE8AF1DE01D5 
Verified message 

這裏是我用來重現cat test.txt | openssl dgst -ecdsa-with-SHA1 -sign sample.key -keyform DER > test.sig設置。

$ cat test.txt 
Attack at dawn! 

$ hexdump -C test.txt 
00000000 41 74 74 61 63 6b 20 61 74 20 64 61 77 6e 21 0a |Attack at dawn!.| 
00000010 

# Create private key in PEM format 
$ openssl ecparam -name secp256k1 -genkey -noout -out secp256k1-key.pem 

$ cat secp256k1-key.pem 
-----BEGIN EC PRIVATE KEY----- 
MHQCAQEEIO0D5Rjmes/91Nb3dHY9dxmbM7gVfxmB2+OVuLmWMbGXoAcGBSuBBAAK 
oUQDQgAEgVNEuirUNCEVdf7nLSBUgU1GXLrtIBeglIbK54s91HlWKOKjk4CkJ3/B 
wGAfcYKa+DgJ2IUQSD15K1T/ghM9eQ== 
-----END EC PRIVATE KEY----- 

# Convert private key to ASN.1/DER format 
$ openssl ec -in secp256k1-key.pem -inform PEM -out secp256k1-key.der -outform DER 

$ dumpasn1 secp256k1-key.der 
    0 116: SEQUENCE { 
    2 1: INTEGER 1 
    5 32: OCTET STRING 
     :  ED 03 E5 18 E6 7A CF FD D4 D6 F7 74 76 3D 77 19 
     :  9B 33 B8 15 7F 19 81 DB E3 95 B8 B9 96 31 B1 97 
39 7: [0] { 
41 5:  OBJECT IDENTIFIER secp256k1 (1 3 132 0 10) 
     :  } 
48 68: [1] { 
50 66:  BIT STRING 
     :  04 81 53 44 BA 2A D4 34 21 15 75 FE E7 2D 20 54 
     :  81 4D 46 5C BA ED 20 17 A0 94 86 CA E7 8B 3D D4 
     :  79 56 28 E2 A3 93 80 A4 27 7F C1 C0 60 1F 71 82 
     :  9A F8 38 09 D8 85 10 48 3D 79 2B 54 FF 82 13 3D 
     :  79 
     :  } 
     : } 

# Create public key from private key 
$ openssl ec -in secp256k1-key.der -inform DER -pubout -out secp256k1-pub.der -outform DER 

$ dumpasn1 secp256k1-pub.der 
    0 86: SEQUENCE { 
    2 16: SEQUENCE { 
    4 7:  OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) 
13 5:  OBJECT IDENTIFIER secp256k1 (1 3 132 0 10) 
     :  } 
20 66: BIT STRING 
     :  04 81 53 44 BA 2A D4 34 21 15 75 FE E7 2D 20 54 
     :  81 4D 46 5C BA ED 20 17 A0 94 86 CA E7 8B 3D D4 
     :  79 56 28 E2 A3 93 80 A4 27 7F C1 C0 60 1F 71 82 
     :  9A F8 38 09 D8 85 10 48 3D 79 2B 54 FF 82 13 3D 
     :  79 
     : } 

# Sign the message using the private key 
$ cat test.txt | openssl dgst -ecdsa-with-SHA1 -sign secp256k1-key.der -keyform DER > test.sig 

# Dump the signature as hex 
$ hexdump -C test.sig 
00000000 30 44 02 20 08 66 c8 f1 6f 15 00 40 8a e2 1b 40 |0D. [email protected]@| 
00000010 56 28 9c 17 8b ca 64 99 37 dc 35 ad ad 60 18 4d |V(....d.7.5..`.M| 
00000020 63 cf 4a 06 02 20 78 4c b7 0b a3 ff 4f ce d3 01 |c.J.. xL....O...| 
00000030 27 5c 6c ed 06 f0 d7 63 6d c6 be 06 59 e8 c3 a5 |'\l....cm...Y...| 
00000040 ce 8a f1 de 01 d5         |......| 
00000046 

# Dump the signature as ASN.1/DER 
$ dumpasn1 test.sig 
    0 68: SEQUENCE { 
    2 32: INTEGER 
     :  08 66 C8 F1 6F 15 00 40 8A E2 1B 40 56 28 9C 17 
     :  8B CA 64 99 37 DC 35 AD AD 60 18 4D 63 CF 4A 06 
36 32: INTEGER 
     :  78 4C B7 0B A3 FF 4F CE D3 01 27 5C 6C ED 06 F0 
     :  D7 63 6D C6 BE 06 59 E8 C3 A5 CE 8A F1 DE 01 D5 
     : } 

,能夠使用PEM的編碼密鑰而不是加密的ASN.1/DER編碼鍵++。要做到這一點,你需要PEM Pack。它是一個社區插件,而不是圖書館本身的一部分。

如果將PEM Pack添加到庫中,則需要重新生成庫。或者,您可以將其作爲程序的一部分來構建。