简体   繁体   English

从内存导入密钥时,Crypto++ BERDecode 异常?

[英]Crypto++ BERDecode exception when importing key from memory?

I'm trying to import a public key from memory, but it fails with the following exception: "BER decode error".我正在尝试从内存中导入公钥,但它失败并出现以下异常:“BER 解码错误”。 As soon as I import it from file using FileSource it succeeds.一旦我使用FileSource从文件中导入它,它就会成功。

How come I can't decode it from memory, but succeed to decode from file?为什么我无法从内存中解码它,但可以成功地从文件中解码? I tried both Load() and BERDecode() function.我尝试了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;
    }
}

How come I can't decode it from memory, but succeed to decode from file?为什么我无法从内存中解码它,但可以成功地从文件中解码? I tried both Load() and BERDecode() function.我尝试了Load()BERDecode()函数。

You are close.你很近。 Use an ArraySource rather than ArraySink to load the key.使用ArraySource而不是ArraySink来加载密钥。 Data flows from sources to sinks.数据从源流向接收器。 Also see ArraySource and ArraySink on the Crypto++ wiki.另请参阅 Crypto++ wiki 上的ArraySourceArraySink

You also need Load since the key has the SubjectPublicKeyInfo preamble.您还需要Load因为密钥具有SubjectPublicKeyInfo前导码。 Also see Keys and Formats on the Crypto++ wiki.另请参阅 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
};

The program results in:该程序的结果是:

$ ./test.exe
Encrypted: 004EE30C8B91F07056FAB43D6DB17DA0A193B19856BB725898301B5717B929066BC37
37F587063ECC4EA81A3ED06219C24335B3997A612C2B0BFAE17F555D6B05D759A1BE3D812B3E6018
6E114E13B6CD7D145D4DBB125D7B56F7640875F16854C911F4552272FBD3E3437E6C3CD6F6059FB5
C2ED50E62B65EAC9B78645E86C2EFC606FCAD2F823CA19F846C6F1837DDA4AA81CAA73108B30F8DC
9107FF442708CD97BF1800BA4E7FE60D3F5B08376B0BD9A41021FC5812FA4B0F1B2A08F504C2B622
A8684D189AD2BCDD85E647AAE2023D923F2F3B2531F315F97E0135489B282DB6F3C05F78233AC810
E184028743B943B07FFFEA93CC6A69511BF113888F2

If you add the following, then you can write the key to a file:如果添加以下内容,则可以将密钥写入文件:

FileSink fs("rsa.der");
fs.Put(key, sizeof(key));
fs.MessageEnd();

Or:或者:

ArraySource(key, sizeof(key), true, new FileSink("rsa.der"));

Then, you can inspect the key using Gutmann's dumpasn1 .然后,您可以使用 Gutmann 的dumpasn1检查密钥。 Notice you have a RSA SubjectPublicKeyInfo.请注意,您有一个 RSA SubjectPublicKeyInfo。 When you have a SubjectPublicKeyInfo or PrivateKeyInfo, then you use Load() or Save() .当您有 SubjectPublicKeyInfo 或 PrivateKeyInfo 时,您可以使用Load()Save() (And use BERDecode and DEREncode to load and save a public key or private key without the *Info header). (并使用BERDecodeDEREncode加载和保存没有*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

Regarding the comments... All Crypto++ objects are thread safe at the class level, meaning they don't share data.关于评论...所有 Crypto++ 对象在类级别都是线程安全的,这意味着它们不共享数据。 This is stated in the README :这在自述文件中说明

Crypto++ is thread safe at the class level. Crypto++ 在类级别是线程安全的。 This means you can use Crypto++ safely in a multithreaded application, but you must provide synchronization when multiple threads access a common Crypto++ object.这意味着您可以在多线程应用程序中安全地使用 Crypto++,但是当多个线程访问一个公共 Crypto++ 对象时,您必须提供同步。

What that means is, if you have two threads using the same object, then you need to supply the locks.这意味着,如果您有两个线程使用同一个对象,那么您需要提供锁。 For example, using prng means the internal state of the generator will change.例如,使用prng意味着生成器的内部状态将发生变化。 There are no internal locks, and you have to serialize access to the prng .没有内部锁,您必须序列化对prng访问。

And regarding the random number generator, Wei Dai (original author of the library), recommends using a separate generator for each thread.关于随机数生成器,戴维(库的原作者)建议为每个线程使用单独的生成器。 From Use of AutoSeededRandomPool on the mailing list:来自邮件列表上 AutoSeededRandomPool 的使用

I suggest one instance per thread so you don't have to worry about synchronizing access to it.我建议每个线程一个实例,这样您就不必担心同步访问它。 One instance per use is fine also if that is more convenient.如果这样更方便的话,每次使用一个实例也可以。 The extra system overhead is probably unnoticeable in most situations.在大多数情况下,额外的系统开销可能并不明显。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM