我遇到的问题是您似乎不知道自己拥有什么,并且您使用的某些参数与其他参数一起使用时是错误的。所以这几乎是在黑暗中刺伤。
首先,您应该将磁盘操作包装在try/catch
。 I/O 总是会导致问题,因此一定要捕获与 I/O 相关的异常iostream
东西。您还应该捕获与密钥加载相关的 Crypto++ 异常。这将在没有信息的情况下处理“崩溃”。
所以你的代码可能看起来像这样:
try
{
// Read key from disk, load it into Crypto++ object
}
catch(const Exception& ex)
{
cerr << "Caught Crypto++ exception " << ex.what() << endl;
}
catch(const std::runtime_error& ex)
{
cerr << "Caught C++ runtime error " << ex.what() << endl;
}
其次,这看起来像一个私有指数,而不是私钥:
std::string privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
而且它太大了,无法进入P-128
。也许你应该这样做:
try
{
AutoSeededRandomPool prng;
std::string exponent="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
StringSource ss(exponent, true /*pumpAll*/, new HexDecoder);
Integer x;
x.Decode(ss, ss.MaxRetrievable(), Integer::UNSIGNED);
// cout << "Exponent: " << std::hex << x << endl;
ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().Initialize(ASN1::secp256r1(), x);
bool valid = decryptor.AccessKey().Validate(prng, 3);
if(!valid)
throw Exception(Exception::OTHER_ERROR, "Exponent is not valid for P-256");
// Or: decryptor.AccessKey().ThrowIfInvalid(prng, 3);
cout << "Exponent is valid for P-256" << endl;
}
catch(const Exception& ex)
{
cerr << ex.what() << endl;
}
或者,您可以:
ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp256r1());
decryptor.AccessKey().SetPrivateExponent(x);
如果将以下内容添加到上面的程序中:
// Encode key, use OID versus domain paramters
string encoded;
HexEncoder encoder(new StringSink(encoded));
decryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
decryptor.GetKey().Save(encoder);
cout << "Private key: " << encoded << endl;
您将获得以下私钥:
$ ./ecies-test.exe
Exponent: 2c200102c180f9e6a4e7a2f58b5be86bc179478h
Private key: 3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010
42000000000000000000000000002C200102C180F9E6A4E7A2F58B5BE86BC179478
正如你所看到的,关键是is not "02C200102C180F9E6A4E7A2F58B5BE86BC179478"
.
12 个前导 0 对我来说看起来很可疑。尽管指数有效,但您应该验证指数和字段。我能找到的最接近的拟合是曲线secp160r2
(当然,像这样的曲线secp192k1
and secp224k1
也工作)。
上面的私钥是十六进制编码的ecies.priv.der
如下所示。
第三,由于领先,这可能是压缩形式的公共点02
.
std::string privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
如果是这种情况,那么你应该能够做到这一点,但我无法让它解码该点(请参阅最小化密钥大小以实现持久性在维基百科上)。x
and y
运算后均为0;也许问题出在该领域:
std::string public_point="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
StringSource ss(public_point, true, new HexDecoder);
ECIES<ECP>::Encryptor encryptor;
encryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp128r1());
ECP::Point point;
encryptor.GetKey().GetGroupParameters().GetCurve().DecodePoint(point, ss, ss.MaxRetrievable());
cout << "X: " << std::hex << point.x << endl;
cout << "Y: " << std::hex << point.y << endl;
encryptor.AccessKey().SetPublicElement(point);
encryptor.AccessKey().ThrowIfInvalid(prng, 3);
第四,您可能应该保存整个密钥,而不仅仅是指数。这是一个适合您的程序,向您展示如何保存和加载密钥。它还向您展示了如何单行执行加密和解密。
/////////////////////////////////////////////////
// Part one - generate keys
ECIES<ECP>::Decryptor decryptor(prng, ASN1::secp256r1());
ECIES<ECP>::Encryptor encryptor(decryptor);
/////////////////////////////////////////////////
// Part two - save keys
FileSink fs1("ecies.priv.der", true /*binary*/);
decryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
decryptor.GetKey().Save(fs1);
FileSink fs2("ecies.pub.der", true /*binary*/);
encryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
encryptor.GetKey().Save(fs2);
/////////////////////////////////////////////////
// Part three - encrypt/decrypt
string message, encrypted, recovered;
if(argc >= 2 && argv[1] != NULL)
message = argv[1];
else
message = "Attack at dawn!";
StringSource ss1 (message, true /*pumpAll*/, new PK_EncryptorFilter(prng, encryptor, new StringSink(encrypted)));
StringSource ss2 (encrypted, true /*pumpAll*/, new FileSink("ecies.encrypted.bin", true /*binary*/));
StringSource ss3 (encrypted, true /*pumpAll*/, new PK_DecryptorFilter(prng, decryptor, new StringSink(recovered)));
cout << recovered << endl;
这是上面测试程序中私钥的样子。请注意,它已将字段编码到结构中,因此您不必猜测它(P-256
versus P-128
versus P-521
).
$ dumpasn1 ecies.priv.der
0 65: SEQUENCE {
2 1: INTEGER 0
5 19: SEQUENCE {
7 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
16 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
26 39: OCTET STRING, encapsulates {
28 37: SEQUENCE {
30 1: INTEGER 1
33 32: OCTET STRING
: 00 00 00 00 00 00 00 00 00 00 00 00 02 C2 00 10
: 2C 18 0F 9E 6A 4E 7A 2F 58 B5 BE 86 BC 17 94 78
: }
: }
: }
和公钥:
$ dumpasn1 ecies.pub.der
0 89: SEQUENCE {
2 19: SEQUENCE {
4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
13 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
23 66: BIT STRING
: 04 08 9B D2 1C 3A DC 08 8B 1F F1 D0 F4 97 A0 87
: FE 4F 78 EA E2 B8 30 B8 E7 06 37 68 27 4C 71 CD
: 63 C3 E2 90 66 64 2B 1C F6 79 00 36 AF 72 4C 61
: 69 FA E9 06 00 9A 15 32 0B 85 B5 88 B2 C5 88 46
: 5E
: }
Crypto++ 在 ECIES 上有一个 wiki 页面。看椭圆曲线综合加密方案。他们还有 Bouncy Castle 互操作解决方法。
您还可以对密钥进行 PEM 编码,但您需要一个补丁才能完成此操作,因为它不是库的一部分。对于补丁,请参见PEM Pack在 Crypto++ wiki 上。