Search code examples
c++cryptographypublic-key-encryptionpublic-keycrypto++

Can't BER decode an RSA public key


I'm having a problem similar to the one asked here. I have what I believe to be a DER encoded RSA PKCS#1 public key, and I want to use it to verify some other data/signatures I have, but I can't even get the decoding to work.

I'm using the same code that was proposed in the solutions to that question.

ByteQueue queue;
StringSource ss(key, true, new HexDecoder(new Redirector(queue)));

RSASSA_PKCS1v15_SHA_Verifier verifier;
verifier.AccessKey().BERDecodePublicKey(queue, false, 0);

AutoSeededRandomPool prng;
if (!verifier.AccessKey().Validate(prng, 3))
  throw Exception(Exception::OTHER_ERROR, "Failed to validate public key");

When I use the key that is posted in that question the code works, however when I try to use mine it fails. Do I have the format wrong? Something else? I'm pretty new to crypto so it's probably something dumb/obvious...

Here's the key I'm trying to use.

30819D300D06092A864886F70D010101050003818B0030818702818100B126088
1BDFE84463D88C6AB8DB914A2E593893C10508B8A5ABDF692E9A5419A3EDBAE86
A052849983B75E3B425C18178B260003D857DF0B6505C6CF9C84F5859FCE3B63F
1FB2D4818501F6C5FA4AD1430EEB081A74ABD74CD1F4AA1FCCA3B88DD0548AED3
4443CEB52444EAE9099AA4FE66B2E6224D02381C248025C7044079020111

EDIT:

Forgot to mention, here's the error I get:

Error!
Dynamic exception type: class CryptoPP::BERDecodeErr
std::exception::what: BER decode error

Solution

  • Its a SubjectPublicKeyInfo (SPKI). You need to call Load on it after HexDecoding.

    First, save it to a file in ASN.1/DER to see what it is:

    string dek("30819D300D06092A864886F70D010101050003818B0030818702818100B126088"
           "1BDFE84463D88C6AB8DB914A2E593893C10508B8A5ABDF692E9A5419A3EDBAE86"
           "A052849983B75E3B425C18178B260003D857DF0B6505C6CF9C84F5859FCE3B63F"
           "1FB2D4818501F6C5FA4AD1430EEB081A74ABD74CD1F4AA1FCCA3B88DD0548AED3"
           "4443CEB52444EAE9099AA4FE66B2E6224D02381C248025C7044079020111");
    
    HexDecoder decoder(new FileSink("key.der", true));
    decoder.Put((const byte*)dek.data(), dek.size());
    decoder.MessageEnd();
    

    Then, see what it is with Gutmann's dumpasn1:

    $ dumpasn1 key.der 
      0 157: SEQUENCE {
      3  13:   SEQUENCE {
      5   9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
     16   0:     NULL
           :     }
     18 139:   BIT STRING, encapsulates {
     22 135:     SEQUENCE {
     25 129:       INTEGER
           :         00 B1 26 08 81 BD FE 84 46 3D 88 C6 AB 8D B9 14
           :         A2 E5 93 89 3C 10 50 8B 8A 5A BD F6 92 E9 A5 41
           :         9A 3E DB AE 86 A0 52 84 99 83 B7 5E 3B 42 5C 18
           :         17 8B 26 00 03 D8 57 DF 0B 65 05 C6 CF 9C 84 F5
           :         85 9F CE 3B 63 F1 FB 2D 48 18 50 1F 6C 5F A4 AD
           :         14 30 EE B0 81 A7 4A BD 74 CD 1F 4A A1 FC CA 3B
           :         88 DD 05 48 AE D3 44 43 CE B5 24 44 EA E9 09 9A
           :         A4 FE 66 B2 E6 22 4D 02 38 1C 24 80 25 C7 04 40
           :         79
    157   1:       INTEGER 17
           :       }
           :     }
           :   }
    

    rsaEncryption (1 2 840 113549 1 1 1) tells you its a RSA key and SPKI.


    So here's how I might do it:

    AutoSeededRandomPool prng;
    string dek("30819D300D06092A864886F70D010101050003818B0030818702818100B126088"
               "1BDFE84463D88C6AB8DB914A2E593893C10508B8A5ABDF692E9A5419A3EDBAE86"
               "A052849983B75E3B425C18178B260003D857DF0B6505C6CF9C84F5859FCE3B63F"
               "1FB2D4818501F6C5FA4AD1430EEB081A74ABD74CD1F4AA1FCCA3B88DD0548AED3"
               "4443CEB52444EAE9099AA4FE66B2E6224D02381C248025C7044079020111");
    
    try {
    
        ByteQueue queue;
        HexDecoder decoder(new Redirector(queue));
    
        decoder.Put((const byte*)dek.data(), dek.size());
        decoder.MessageEnd();
    
        RSASSA_PKCS1v15_SHA_Verifier verifier;
        verifier.AccessKey().Load(queue);
    
        if (!verifier.AccessKey().Validate(prng, 3))
            throw Exception(Exception::OTHER_ERROR, "Failed to validate public key");
    
        cout << "Verified key" << endl;
    }
    catch(CryptoPP::Exception& ex)
    {
        cerr << ex.what() << endl;
    }
    

    The program results in (as expected):

    $ ./cryptopp-test.exe
    Verified key
    

    Based on you Pastebin with the following (some rather poor formatting added by me):

    text:1002712F                 
    mov
         [ebp+a1], offset ??_7?$TF_VerifierImpl@U?$TF_SignatureSchemeOptions@V?
         $TF_SS@UPKCS1v15@CryptoPP@@VSHA1@2@URSA@2@H@CryptoPP@@URSA@2@
         VPKCS1v15_SignatureMessageEncodingMethod@2@VSHA1@2@@CryptoPP@@@CryptoPP@@6B?
         $TF_VerifierImpl@U?$TF_SignatureSchemeOptions@V?
         $TF_SS@UPKCS1v15@CryptoPP@@VSHA1@2@URSA@2@H@CryptoPP@@URSA@2@
         VPKCS1v15_SignatureMessageEncodingMethod@
         2@VSHA1@2@@CryptoPP@@@CryptoPP@@@ ; const
         CryptoPP::TF_VerifierImpl<CryptoPP::TF_SignatureSchemeOptions<CryptoPP::TF_SS<
         CryptoPP::PKCS1v15,CryptoPP::SHA1,CryptoPP::RSA,int>,
         CryptoPP::RSA,CryptoPP::PKCS1v15_SignatureMessageEncodingMethod,
         CryptoPP::SHA1>>::`vftable'{for `CryptoPP::TF_VerifierImpl<
         CryptoPP::TF_SignatureSchemeOptions<CryptoPP::TF_SS<
         CryptoPP::PKCS1v15,CryptoPP::SHA1,CryptoPP::RSA,int>,
         CryptoPP::RSA,CryptoPP::PKCS1v15_SignatureMessageEncodingMethod,CryptoPP::SHA1>>'
    

    I'm guessing RSASSA_PKCS1v15_SHA_Verifier will be OK. But you won't know until you try to consume an encoded signature.

    If RSASSA_PKCS1v15_SHA_Verifier does not work, then try adding a typedef that uses SHA256:

    typedef RSASS<PKCS1v15, SHA256>::Signer RSASSA_PKCS1v15_SHA256_Signer;
    typedef RSASS<PKCS1v15, SHA256>::Verifier RSASSA_PKCS1v15_SHA256_Verifier;
    

    Here are the original typedefs from the library at rsa.h:

    00161 typedef RSASS<PKCS1v15, SHA>::Signer RSASSA_PKCS1v15_SHA_Signer;
    00162 typedef RSASS<PKCS1v15, SHA>::Verifier RSASSA_PKCS1v15_SHA_Verifier;
    

    The Crypto++ wiki has a page on Keys and Formats. It appears to be a lot of rambling until you have a concrete case to look at :) It even shows you how to create keys using other libraries, like OpenSSL and GnuTLS.