执行 RSA 解密时密文无效
Invalid ciphertext when performing RSA decryption
我使用以下代码加密和解密一个使用 Crypto++ 5.6.2 库的字符串
string to_BER(string spriv,bool b)
{
string HEADER, FOOTER;
if(b)
{
HEADER = "-----BEGIN RSA PRIVATE KEY-----";
FOOTER = "-----END RSA PRIVATE KEY-----";
}
else
{
HEADER = "-----BEGIN PUBLIC KEY-----";
FOOTER = "-----END PUBLIC KEY-----";
}
size_t pos1, pos2;
pos1 = spriv.find(HEADER);
if(pos1 == string::npos)
throw std::runtime_error("PEM header not found");
pos2 = spriv.find(FOOTER, pos1+1);
if(pos2 == string::npos)
throw std::runtime_error("PEM footer not found");
// Start position and length
pos1 = pos1 + HEADER.length();
pos2 = pos2 - pos1;
string keystr = spriv.substr(pos1, pos2);
return keystr;
}
string rsa_encrypt(const string &message, const string &public_key)
{
string keystr=to_BER(public_key,false);
ByteQueue queue;
Base64Decoder decoder;
decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
RSAES_PKCS1v15_Encryptor e;
e.AccessKey().Load(queue);
bool key_ok = e.AccessKey().Validate(rng, 3);
if(!key_ok)
{
printf("ERROR IN RSA KEY\n");
return "";
}
string encrypted_data;
StringSource ss1(message, true,
new PK_EncryptorFilter(rng, e,
new StringSink(encrypted_data)
) // PK_EncryptorFilter
); // StringSource
return encrypted_data;
}
string rsa_decrypt(const string &message, const string &private_key,bool b_Base64decode)
{
string keystr=to_BER(private_key,true);
string decoded=message;
if(b_Base64decode)
{
Base64Decoder decoder;
decoder.Put( (byte*)message.data(), message.size() );
decoder.MessageEnd();
word64 size = decoder.MaxRetrievable();
if(size && size <= SIZE_MAX)
{
decoded.resize(size);
decoder.Get((byte*)decoded.data(), decoded.size());
}
}
RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
TransparentFilter privSink( new StringSink(keystr) );
pri.DEREncode( privSink );
privSink.MessageEnd();
string decrypted_data;
try
{
StringSource ss( decoded, true,
new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));
}
catch(Exception *e)
{
printf("ERROR DECRYPTING RSA\n");
return "";
}
return decrypted_data;
}
然后我使用这个代码:
string enc=rsa_encrypt("hola mundo","-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAE= -----END PUBLIC KEY-----");
string aaa=rsa_decrypt(
/*"YTbXg1K4OlXGY6eaLuVTFZrN4qi1zg83h0PjeLd9F3Ge3gKUHsJpoE3iLv1+Gj/PepM8ehiilb5kphxCdcELjaYH9wwYHMpUZUQSRLQUTnofOboI6nfHaKnnNV28QMguM39q1hm7X1wNc69D8R+CkWLka2rQof+BXt+41ivnMj8=",*/
enc
,"-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNprz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Yjwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/AgVl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQCD4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3apyv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn12sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUEUsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNWrFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA== -----END RSA PRIVATE KEY-----"
,false
);
问题是 rsa_decrypt
失败并出现 "invalid ciphertext" 异常,try/catch 代码未捕获该异常。程序崩溃。
我想知道我的代码有什么问题,即使密文错误,如何避免程序崩溃。
我找到了类似的线程 (crypto++ RSA and "invalid ciphertext"),但 none 的解决方案对我有效:我没有发现字符串末尾的 0 有任何问题,我检查密钥是否有效,我知道私有密钥和 public 密钥来自同一密钥对,并且它们与其他 RSA 库一起使用。
这是崩溃的行:
StringSource ss( decoded, true,
new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));
The problem is that rsa_decrypt fails with a "invalid ciphertext" exception
你创建一个new私钥,然后把它编码成keystr
:
RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
TransparentFilter privSink( new StringSink(keystr) );
pri.DEREncode( privSink );
相反,您应该使用 private_key
(而不是新密钥)并像在加密器中那样做一些事情:
string keystr=to_BER(private_key,true);
ByteQueue queue;
Base64Decoder decoder;
decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
RSAES_PKCS1v15_Decryptor d;
d.AccessKey().Load(queue);
... that isn't caught...
将 所有内容 包装在 try/catch 块中,而不仅仅是 PK_DecryptorFilter
调用。
您可以看到 public 和私钥之间的差异(或缺失),例如:
try {
string s1("-----BEGIN PUBLIC KEY-----\n"
"MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAai"
"TrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceF"
"puTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEk"
"I4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSS"
"S9oFItGOFF0jDM7lAgMBAAE="
"\n-----END PUBLIC KEY-----");
string s2("-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj"
"56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6"
"eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi"
"96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNp"
"rz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Y"
"jwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2"
"E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/"
"zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/Ag"
"Vl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQC"
"D4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3ap"
"yv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn1"
"2sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3"
"lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1"
"/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUE"
"UsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNW"
"rFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA=="
"\n-----END RSA PRIVATE KEY-----");
ArraySource as1(s1, true), as2(s2, true);
RSA::PublicKey k1;
RSA::PrivateKey k2;
PEM_Load(as1, k1);
PEM_Load(as2, k2);
AutoSeededRandomPool prng;
k1.ThrowIfInvalid(prng, 3);
k2.ThrowIfInvalid(prng, 3);
Integer i1 = k1.GetModulus() - k2.GetModulus();
Integer i2 = k1.GetPublicExponent() - k2.GetPublicExponent();
cout << i1 << " " << i2 << endl;
} catch (const Exception& ex) {
cerr << ex.what() << endl;
}
相关,封装边界(-----BEGIN PUBLIC KEY-----
和-----END PUBLIC KEY-----
)应该各占一行。您应该使用新行 (\n
) 而不是 space。所以像:
string enc=rsa_encrypt(
"hola mundo",
"-----BEGIN PUBLIC KEY-----\nMIGeMA0G...gMBAAE=\n-----END PUBLIC KEY-----"
);
并且:
string aaa=rsa_decrypt(
enc,
"-----BEGIN RSA PRIVATE KEY-----\nMIICWwIB...7rXPvA==\n-----END RSA PRIVATE KEY-----",
false
);
相关,你应该用RSAES_OAEP_SHA_Encryptor
和RSAES_OAEP_SHA_Decryptor
。 A bad couple of years for the cryptographic token industry.
提供了一种可行的治疗方法
我使用以下代码加密和解密一个使用 Crypto++ 5.6.2 库的字符串
string to_BER(string spriv,bool b)
{
string HEADER, FOOTER;
if(b)
{
HEADER = "-----BEGIN RSA PRIVATE KEY-----";
FOOTER = "-----END RSA PRIVATE KEY-----";
}
else
{
HEADER = "-----BEGIN PUBLIC KEY-----";
FOOTER = "-----END PUBLIC KEY-----";
}
size_t pos1, pos2;
pos1 = spriv.find(HEADER);
if(pos1 == string::npos)
throw std::runtime_error("PEM header not found");
pos2 = spriv.find(FOOTER, pos1+1);
if(pos2 == string::npos)
throw std::runtime_error("PEM footer not found");
// Start position and length
pos1 = pos1 + HEADER.length();
pos2 = pos2 - pos1;
string keystr = spriv.substr(pos1, pos2);
return keystr;
}
string rsa_encrypt(const string &message, const string &public_key)
{
string keystr=to_BER(public_key,false);
ByteQueue queue;
Base64Decoder decoder;
decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
RSAES_PKCS1v15_Encryptor e;
e.AccessKey().Load(queue);
bool key_ok = e.AccessKey().Validate(rng, 3);
if(!key_ok)
{
printf("ERROR IN RSA KEY\n");
return "";
}
string encrypted_data;
StringSource ss1(message, true,
new PK_EncryptorFilter(rng, e,
new StringSink(encrypted_data)
) // PK_EncryptorFilter
); // StringSource
return encrypted_data;
}
string rsa_decrypt(const string &message, const string &private_key,bool b_Base64decode)
{
string keystr=to_BER(private_key,true);
string decoded=message;
if(b_Base64decode)
{
Base64Decoder decoder;
decoder.Put( (byte*)message.data(), message.size() );
decoder.MessageEnd();
word64 size = decoder.MaxRetrievable();
if(size && size <= SIZE_MAX)
{
decoded.resize(size);
decoder.Get((byte*)decoded.data(), decoded.size());
}
}
RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
TransparentFilter privSink( new StringSink(keystr) );
pri.DEREncode( privSink );
privSink.MessageEnd();
string decrypted_data;
try
{
StringSource ss( decoded, true,
new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));
}
catch(Exception *e)
{
printf("ERROR DECRYPTING RSA\n");
return "";
}
return decrypted_data;
}
然后我使用这个代码:
string enc=rsa_encrypt("hola mundo","-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAE= -----END PUBLIC KEY-----");
string aaa=rsa_decrypt(
/*"YTbXg1K4OlXGY6eaLuVTFZrN4qi1zg83h0PjeLd9F3Ge3gKUHsJpoE3iLv1+Gj/PepM8ehiilb5kphxCdcELjaYH9wwYHMpUZUQSRLQUTnofOboI6nfHaKnnNV28QMguM39q1hm7X1wNc69D8R+CkWLka2rQof+BXt+41ivnMj8=",*/
enc
,"-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNprz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Yjwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/AgVl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQCD4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3apyv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn12sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUEUsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNWrFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA== -----END RSA PRIVATE KEY-----"
,false
);
问题是 rsa_decrypt
失败并出现 "invalid ciphertext" 异常,try/catch 代码未捕获该异常。程序崩溃。
我想知道我的代码有什么问题,即使密文错误,如何避免程序崩溃。
我找到了类似的线程 (crypto++ RSA and "invalid ciphertext"),但 none 的解决方案对我有效:我没有发现字符串末尾的 0 有任何问题,我检查密钥是否有效,我知道私有密钥和 public 密钥来自同一密钥对,并且它们与其他 RSA 库一起使用。
这是崩溃的行:
StringSource ss( decoded, true,
new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));
The problem is that rsa_decrypt fails with a "invalid ciphertext" exception
你创建一个new私钥,然后把它编码成keystr
:
RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
TransparentFilter privSink( new StringSink(keystr) );
pri.DEREncode( privSink );
相反,您应该使用 private_key
(而不是新密钥)并像在加密器中那样做一些事情:
string keystr=to_BER(private_key,true);
ByteQueue queue;
Base64Decoder decoder;
decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
RSAES_PKCS1v15_Decryptor d;
d.AccessKey().Load(queue);
... that isn't caught...
将 所有内容 包装在 try/catch 块中,而不仅仅是 PK_DecryptorFilter
调用。
您可以看到 public 和私钥之间的差异(或缺失),例如:
try {
string s1("-----BEGIN PUBLIC KEY-----\n"
"MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAai"
"TrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceF"
"puTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEk"
"I4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSS"
"S9oFItGOFF0jDM7lAgMBAAE="
"\n-----END PUBLIC KEY-----");
string s2("-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj"
"56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6"
"eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi"
"96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNp"
"rz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Y"
"jwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2"
"E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/"
"zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/Ag"
"Vl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQC"
"D4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3ap"
"yv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn1"
"2sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3"
"lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1"
"/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUE"
"UsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNW"
"rFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA=="
"\n-----END RSA PRIVATE KEY-----");
ArraySource as1(s1, true), as2(s2, true);
RSA::PublicKey k1;
RSA::PrivateKey k2;
PEM_Load(as1, k1);
PEM_Load(as2, k2);
AutoSeededRandomPool prng;
k1.ThrowIfInvalid(prng, 3);
k2.ThrowIfInvalid(prng, 3);
Integer i1 = k1.GetModulus() - k2.GetModulus();
Integer i2 = k1.GetPublicExponent() - k2.GetPublicExponent();
cout << i1 << " " << i2 << endl;
} catch (const Exception& ex) {
cerr << ex.what() << endl;
}
相关,封装边界(-----BEGIN PUBLIC KEY-----
和-----END PUBLIC KEY-----
)应该各占一行。您应该使用新行 (\n
) 而不是 space。所以像:
string enc=rsa_encrypt(
"hola mundo",
"-----BEGIN PUBLIC KEY-----\nMIGeMA0G...gMBAAE=\n-----END PUBLIC KEY-----"
);
并且:
string aaa=rsa_decrypt(
enc,
"-----BEGIN RSA PRIVATE KEY-----\nMIICWwIB...7rXPvA==\n-----END RSA PRIVATE KEY-----",
false
);
相关,你应该用RSAES_OAEP_SHA_Encryptor
和RSAES_OAEP_SHA_Decryptor
。 A bad couple of years for the cryptographic token industry.