ECDSA使用OpenSSL进行签名,使用Crypto++进行验证
ECDSA sign with OpenSSL, verify with Crypto++
我用戴的Crypto++在我的应用程序中创建了一个ECDSA密钥对(secp128r1)。按预期签署和验证工作。我不会将消息本身添加到签名中以最小化签名长度(正好是32字节)。
但是,当我使用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字节吗?
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表示序列中的第一个项目是Integer。10告诉您第一个整数的长度为0x10字节。以下0x10(16)字节是ECDSA签名的"r"值。第一个整数后面是字节02。这告诉你序列的第二个整数即将开始。11告诉您,接下来的0x11(17)字节组成第二个整数,这是ECDSA签名的"s"值。它是11个字节,因为Integer的第一个字节是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格式。
divb>我可以告诉openssl在不将消息放入签名的情况下对消息进行签名,这样得到的签名正好是32字节吗?
和
sandeep>cryptopp中有任何函数可以进行这种转换吗?
正如@CodesInChaos所说,问题在于签名编码。另请参阅比预期更长的OpenSSL ECDSA签名。
正如@Sandeep在评论中建议的那样,另一种选择是让Crypto++使用OpenSSL签名。
这里有一个Crypto++测试程序,用于从OpenSSL和Java使用的ASN.1/DER输出转换,并将其转换为Crypto++使用的IEEE P1363。它主要取自Crypto++维基上的椭圆曲线数字签名算法。
#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.
SecByteBlock signature(verifier.SignatureLength());
DSAConvertSignatureFormat(signature, signature.size(), DSA_P1363,
derSignature, sizeof(derSignature), DSA_DER);
// Message "Attack at dawn!"
const byte message[] = {
0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x61,
0x74, 0x20, 0x64, 0x61, 0x77, 0x6e, 0x21, 0x0a
};
// https://www.cryptopp.com/wiki/Elliptic_Curve_Digital_Signature_Algorithm
bool result = verifier.VerifyMessage(message, sizeof(message), signature, signature.size());
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. .f..o..@...@|
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
: }
在Crypto++中可以使用PEM编码的密钥,而不是ASN.1/DER编码的密钥。要做到这一点,您将需要PEM包。它是一个社区插件,而不是库本身的一部分。
如果将PEM Pack添加到库中,则需要重建库。或者,您可以将其作为程序的一部分进行构建。
首先,您应该知道128位的EC提供了大约64位的安全性。其次,我不认为这是openssl添加的消息,因为5个字节还不够。无论如何,您可以使用head或tail来删除多余的字节。
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- "byte":使用Crypto++和Windows SDK时出现不明确的符号错误
- "ChaCha"尚未在此范围内使用Crypto++声明?
- 使用crypto++的HMAC解密植物文本
- 使用Crypto 散列包含C 中的NUL字符的字符串
- ECDSA签名与Bouncycastle签名,并使用Crypto 验证
- 使用 Crypto++/AES CFB 加密不起作用
- 如何在 Windows 7 上使用 Crypto API 下一代创建 AES 持久密钥
- 使用Crypto++库仅从x压缩坐标检索ECDSA公钥
- 使用Crypto++使用私钥进行签名;SHA1 vs惠而浦
- 使用Crypto++进行恒定时间密码摘要比较
- AES128在CBC模式下使用Crypto++库实现
- 使用Crypto++进行MD4哈希会导致错误的哈希
- 使用 Crypto++ 实现 ECC 加密解密时,是否可以将加密文本缩小?
- ECDSA使用OpenSSL进行签名,使用Crypto++进行验证
- 使用crypto++解密时,原始文本末尾的垃圾冗余字符
- 在Clion IDE中使用Crypto++
- 关于使用crypto++库进行加密和解密
- 使用Crypto++加密/解密AES CBC/ECB模式
- 使用Crypto实现c++和c#之间加密的互操作性