Search code examples
javac++encryptionrsacrypto++

Passing RSA keys between Java and Crypto++ code


I have a server written in java that generates RSA key pair. I want to use the private key in a C++ client for decryption.

This is the code I use to create the private key:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(4096);
KeyPair keyPair = keyGen.genKeyPair();

PrivateKey privateKey = keyPair.getPrivate();
byte[] encoded = privateKey.getEncoded();
String b64Encoded = Base64.getEncoder().encodeToString(encoded);

I then save the base64 encoded string and try to load it as a private key in my cpp code.

I decode the base64 string to a binary array and then use the following code to try loading the private key (encodedString should be the DER encoded data after decoding it from base64):

ByteQueue queue;

StringSource ss(encodedString,true);
ss.TransferTo(queue);
queue.MessageEnd();

key.BERDecodePrivateKey(queue, false , queue.MaxRetrievable());

However this code always crashes with exception: CryptoPP::BERDecodeErr.

I believe both libraries use PKCS#8 to encode the key parameters.

Note: When I create the key pair using crypto++ and then encode it (DER + base64) I get a 3172/3176 chars string while in my java code I get a 3168 chars string. I'm not sure whether this info helps with anything.


Solution

  • It looks like you need to call Load and not BERDecodePrivateKey. You call Load when you have a key+info (like version and algorithm id); while you call BERDecodePrivateKey when you have just a key. The following works for me.

    If the private key is password protected, then you will need the PEM Pack. The PEM Pack is a community contribution, but its maintained like the proper library.

    $ cat rsa_java.java 
    import java.io.*;
    import java.util.*;
    import java.security.*;
    
    public class rsa_java {
        public static void main (String[] args) throws Exception {
    
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(4096);
        KeyPair keyPair = keyGen.genKeyPair();
    
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] encodedPrivateKey = privateKey.getEncoded();
        String b64Encoded = Base64.getEncoder().encodeToString(encodedPrivateKey);
    
        try (PrintStream out = new PrintStream(new FileOutputStream("rsa_key.txt")))
        {
            out.print(b64Encoded);
        }
    }
    

    And:

    $ cat rsa_cryptopp.cxx
    #include <iostream>
    using namespace std;
    
    #include "cryptopp/rsa.h"
    #include "cryptopp/files.h"
    #include "cryptopp/osrng.h"
    #include "cryptopp/base64.h"
    using namespace CryptoPP;
    
    int main(int argc, char* argv[])
    {
      try
      {
        RSA::PrivateKey key;
        FileSource fs("rsa_key.txt", true, new Base64Decoder);
        key.Load(fs);
    
        cout << "Loaded RSA key" << endl;
    
        AutoSeededRandomPool prng;
        key.Validate(prng, 3);
    
        cout << "Validated RSA key" << endl;
      }
      catch(const Exception& ex)
      {
        cout << "Exception: " << ex.what() << endl;
      }
    
      return 0;
    }
    

    It results in:

    $ javac rsa_java.java && java rsa_java
    $ g++ -I. rsa_cryptopp.cxx cryptopp/libcryptopp.a -o rsa_cryptopp.exe
    $ ./rsa_cryptopp.exe 
    Loaded RSA key
    Validated RSA key
    

    For completeness, here's the key with the Base64 encoding. Its 3168 bytes:

    $ fold -w 80 -s rsa_key.txt
    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