[英]Crypto++ BERDecode exception when importing key from memory?
我正在嘗試從內存中導入公鑰,但它失敗並出現以下異常:“BER 解碼錯誤”。 一旦我使用FileSource
從文件中導入它,它就會成功。
為什么我無法從內存中解碼它,但可以成功地從文件中解碼? 我嘗試了Load()
和BERDecode()
函數。
namespace CryptoHelper
{
byte key[292] =
{
0x30, 0x82, 0x01, 0x20, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0D, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01,
0x00, 0xB6, 0x87, 0x31, 0x96, 0xE3, 0xAD, 0x61, 0x66, 0x30, 0x0D, 0xE6, 0x91, 0xED, 0x9D, 0x41,
0x4E, 0xA2, 0x30, 0x10, 0xCD, 0x5C, 0x24, 0x90, 0xD2, 0x9A, 0xD9, 0xBD, 0xF9, 0x70, 0x14, 0xF9,
0x57, 0x36, 0xE7, 0xE7, 0x9D, 0xCF, 0xFE, 0x85, 0x6F, 0x28, 0x81, 0x16, 0x10, 0x95, 0x80, 0x2B,
0xCA, 0xA2, 0xB7, 0x88, 0x95, 0xF1, 0xCA, 0x5E, 0xEF, 0xCD, 0x3B, 0xEC, 0x30, 0xB9, 0xE3, 0xC6,
0x88, 0xB3, 0xF4, 0xA2, 0x5D, 0xF3, 0xC7, 0x9C, 0x2A, 0xA7, 0x54, 0xAE, 0xBF, 0xEC, 0x7D, 0x14,
0xE8, 0x63, 0xE7, 0x2C, 0x8E, 0xAE, 0x06, 0xFF, 0xA2, 0x21, 0x04, 0xF8, 0x1B, 0x3F, 0x94, 0x01,
0xFC, 0xDE, 0x28, 0xA1, 0x6F, 0x05, 0x76, 0xBE, 0x81, 0x6B, 0xF0, 0x60, 0x19, 0xB3, 0x8E, 0x6A,
0xBE, 0x39, 0x54, 0xC3, 0xF5, 0xA8, 0xC9, 0xC0, 0x3F, 0x30, 0x87, 0x48, 0x64, 0xBE, 0x8E, 0x8A,
0xFF, 0x8D, 0xC8, 0x51, 0xCC, 0x5A, 0x99, 0xD5, 0xDF, 0x0B, 0x41, 0x8F, 0xFE, 0xAD, 0xBC, 0xD2,
0x01, 0x79, 0x6F, 0x6E, 0xFC, 0x46, 0xEC, 0x73, 0xD4, 0xF7, 0xD4, 0xD4, 0x34, 0x1F, 0xCF, 0x1E,
0xBE, 0xA9, 0xD5, 0xDF, 0x9B, 0x45, 0x15, 0xF4, 0xB5, 0x0F, 0xA1, 0x22, 0x06, 0xED, 0x5B, 0x21,
0xC0, 0x8C, 0x1C, 0xC8, 0xF3, 0x47, 0x7A, 0x6D, 0x3D, 0x03, 0x87, 0xF7, 0x0D, 0xF9, 0x5C, 0xF0,
0xA9, 0xD0, 0xD4, 0xAD, 0x89, 0x86, 0x08, 0xAE, 0xC2, 0x4B, 0x2B, 0x1C, 0xC1, 0xCA, 0xA7, 0xBD,
0x37, 0x5D, 0x62, 0xD9, 0x0A, 0xF8, 0x1F, 0x12, 0x64, 0xBA, 0xD1, 0x43, 0x33, 0xA2, 0xFC, 0xAD,
0xE0, 0x5A, 0x17, 0x7B, 0x86, 0xD1, 0x8F, 0xF8, 0x05, 0x5F, 0xB6, 0x32, 0x59, 0xAB, 0x70, 0x1C,
0xD4, 0x30, 0x68, 0xA2, 0xC6, 0x68, 0xD7, 0x7B, 0x21, 0xE3, 0xE9, 0x4D, 0x4C, 0x54, 0x40, 0x95,
0xEB, 0x02, 0x01, 0x11,
};
AutoSeededRandomPool rng; // TODO: Check whether this is thread-safe
ArraySink keySink(key, 292); // TODO: Check whether this is thread-safe
RSA::PublicKey rsaPublic; // TODO: Check whether this is thread-safe
void EncryptBuffer()
{
std::string plain = "RSA Encryption", cipher, recovered;
FileSource input("rsapublic.dat", true);
// This one works perfectly
// rsaPublic.BERDecode(input);
rsaPublic.Load(keySink);
RSAES_OAEP_SHA_Encryptor e(rsaPublic);
// Encrypt
StringSource ss1(plain, true,
new PK_EncryptorFilter(rng, e, new StringSink(cipher)
));
return;
}
}
為什么我無法從內存中解碼它,但可以成功地從文件中解碼? 我嘗試了
Load()
和BERDecode()
函數。
你很近。 使用ArraySource
而不是ArraySink
來加載密鑰。 數據從源流向接收器。 另請參閱 Crypto++ wiki 上的ArraySource和ArraySink 。
您還需要Load
因為密鑰具有SubjectPublicKeyInfo
前導碼。 另請參閱 Crypto++ wiki 上的密鑰和格式。
$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "osrng.h"
#include "files.h"
#include "rsa.h"
#include "hex.h"
#include <iostream>
#include <string>
using CryptoPP::byte;
extern const byte key[292];
int main (int argc, char* argv[])
{
using namespace CryptoPP;
AutoSeededRandomPool rng;
ArraySource keySource(key, 292, true);
RSA::PublicKey rsaPublic;
rsaPublic.Load(keySource);
RSAES_OAEP_SHA_Encryptor enc(rsaPublic);
std::string plain = "RSA Encryption", cipher, recovered;
StringSource ss1(plain, true,
new PK_EncryptorFilter(rng, enc, new StringSink(cipher)
));
std::cout << "Encrypted: ";
StringSource(cipher, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
return 0;
}
const byte key[292] =
{
0x30, 0x82, 0x01, 0x20, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0D, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01,
0x00, 0xB6, 0x87, 0x31, 0x96, 0xE3, 0xAD, 0x61, 0x66, 0x30, 0x0D, 0xE6, 0x91, 0xED, 0x9D, 0x41,
0x4E, 0xA2, 0x30, 0x10, 0xCD, 0x5C, 0x24, 0x90, 0xD2, 0x9A, 0xD9, 0xBD, 0xF9, 0x70, 0x14, 0xF9,
0x57, 0x36, 0xE7, 0xE7, 0x9D, 0xCF, 0xFE, 0x85, 0x6F, 0x28, 0x81, 0x16, 0x10, 0x95, 0x80, 0x2B,
0xCA, 0xA2, 0xB7, 0x88, 0x95, 0xF1, 0xCA, 0x5E, 0xEF, 0xCD, 0x3B, 0xEC, 0x30, 0xB9, 0xE3, 0xC6,
0x88, 0xB3, 0xF4, 0xA2, 0x5D, 0xF3, 0xC7, 0x9C, 0x2A, 0xA7, 0x54, 0xAE, 0xBF, 0xEC, 0x7D, 0x14,
0xE8, 0x63, 0xE7, 0x2C, 0x8E, 0xAE, 0x06, 0xFF, 0xA2, 0x21, 0x04, 0xF8, 0x1B, 0x3F, 0x94, 0x01,
0xFC, 0xDE, 0x28, 0xA1, 0x6F, 0x05, 0x76, 0xBE, 0x81, 0x6B, 0xF0, 0x60, 0x19, 0xB3, 0x8E, 0x6A,
0xBE, 0x39, 0x54, 0xC3, 0xF5, 0xA8, 0xC9, 0xC0, 0x3F, 0x30, 0x87, 0x48, 0x64, 0xBE, 0x8E, 0x8A,
0xFF, 0x8D, 0xC8, 0x51, 0xCC, 0x5A, 0x99, 0xD5, 0xDF, 0x0B, 0x41, 0x8F, 0xFE, 0xAD, 0xBC, 0xD2,
0x01, 0x79, 0x6F, 0x6E, 0xFC, 0x46, 0xEC, 0x73, 0xD4, 0xF7, 0xD4, 0xD4, 0x34, 0x1F, 0xCF, 0x1E,
0xBE, 0xA9, 0xD5, 0xDF, 0x9B, 0x45, 0x15, 0xF4, 0xB5, 0x0F, 0xA1, 0x22, 0x06, 0xED, 0x5B, 0x21,
0xC0, 0x8C, 0x1C, 0xC8, 0xF3, 0x47, 0x7A, 0x6D, 0x3D, 0x03, 0x87, 0xF7, 0x0D, 0xF9, 0x5C, 0xF0,
0xA9, 0xD0, 0xD4, 0xAD, 0x89, 0x86, 0x08, 0xAE, 0xC2, 0x4B, 0x2B, 0x1C, 0xC1, 0xCA, 0xA7, 0xBD,
0x37, 0x5D, 0x62, 0xD9, 0x0A, 0xF8, 0x1F, 0x12, 0x64, 0xBA, 0xD1, 0x43, 0x33, 0xA2, 0xFC, 0xAD,
0xE0, 0x5A, 0x17, 0x7B, 0x86, 0xD1, 0x8F, 0xF8, 0x05, 0x5F, 0xB6, 0x32, 0x59, 0xAB, 0x70, 0x1C,
0xD4, 0x30, 0x68, 0xA2, 0xC6, 0x68, 0xD7, 0x7B, 0x21, 0xE3, 0xE9, 0x4D, 0x4C, 0x54, 0x40, 0x95,
0xEB, 0x02, 0x01, 0x11
};
該程序的結果是:
$ ./test.exe
Encrypted: 004EE30C8B91F07056FAB43D6DB17DA0A193B19856BB725898301B5717B929066BC37
37F587063ECC4EA81A3ED06219C24335B3997A612C2B0BFAE17F555D6B05D759A1BE3D812B3E6018
6E114E13B6CD7D145D4DBB125D7B56F7640875F16854C911F4552272FBD3E3437E6C3CD6F6059FB5
C2ED50E62B65EAC9B78645E86C2EFC606FCAD2F823CA19F846C6F1837DDA4AA81CAA73108B30F8DC
9107FF442708CD97BF1800BA4E7FE60D3F5B08376B0BD9A41021FC5812FA4B0F1B2A08F504C2B622
A8684D189AD2BCDD85E647AAE2023D923F2F3B2531F315F97E0135489B282DB6F3C05F78233AC810
E184028743B943B07FFFEA93CC6A69511BF113888F2
如果添加以下內容,則可以將密鑰寫入文件:
FileSink fs("rsa.der");
fs.Put(key, sizeof(key));
fs.MessageEnd();
或者:
ArraySource(key, sizeof(key), true, new FileSink("rsa.der"));
然后,您可以使用 Gutmann 的dumpasn1
檢查密鑰。 請注意,您有一個 RSA SubjectPublicKeyInfo。 當您有 SubjectPublicKeyInfo 或 PrivateKeyInfo 時,您可以使用Load()
或Save()
。 (並使用BERDecode
和DEREncode
加載和保存沒有*Info
標頭的公鑰或私鑰)。
$ dumpasn1 rsa.der
0 288: SEQUENCE {
4 13: SEQUENCE {
6 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
17 0: NULL
: }
19 269: BIT STRING, encapsulates {
24 264: SEQUENCE {
28 257: INTEGER
: 00 B6 87 31 96 E3 AD 61 66 30 0D E6 91 ED 9D 41
: 4E A2 30 10 CD 5C 24 90 D2 9A D9 BD F9 70 14 F9
: 57 36 E7 E7 9D CF FE 85 6F 28 81 16 10 95 80 2B
: CA A2 B7 88 95 F1 CA 5E EF CD 3B EC 30 B9 E3 C6
: 88 B3 F4 A2 5D F3 C7 9C 2A A7 54 AE BF EC 7D 14
: E8 63 E7 2C 8E AE 06 FF A2 21 04 F8 1B 3F 94 01
: FC DE 28 A1 6F 05 76 BE 81 6B F0 60 19 B3 8E 6A
: BE 39 54 C3 F5 A8 C9 C0 3F 30 87 48 64 BE 8E 8A
: [ Another 129 bytes skipped ]
289 1: INTEGER 17
: }
: }
: }
0 warnings, 0 errors.
AutoSeededRandomPool prng; // TODO: Check whether this is thread-safe
ArraySink keySink(key, 292); // TODO: Check whether this is thread-safe
RSA::PublicKey rsaPublic; // TODO: Check whether this is thread-safe
關於評論...所有 Crypto++ 對象在類級別都是線程安全的,這意味着它們不共享數據。 這在自述文件中說明:
Crypto++ 在類級別是線程安全的。 這意味着您可以在多線程應用程序中安全地使用 Crypto++,但是當多個線程訪問一個公共 Crypto++ 對象時,您必須提供同步。
這意味着,如果您有兩個線程使用同一個對象,那么您需要提供鎖。 例如,使用prng
意味着生成器的內部狀態將發生變化。 沒有內部鎖,您必須序列化對prng
訪問。
關於隨機數生成器,戴維(庫的原作者)建議為每個線程使用單獨的生成器。 來自郵件列表上 AutoSeededRandomPool 的使用:
我建議每個線程一個實例,這樣您就不必擔心同步訪問它。 如果這樣更方便的話,每次使用一個實例也可以。 在大多數情況下,額外的系統開銷可能並不明顯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.