This has been asked before over the years and there is no definitive answer
Is the consensus that JUCE’s RSAKey class is not compatible with public & private keys generated using openssl?
Over the past few days I have figured out how to parse PEM-formatted public keys. When I print the key as a hex string, it produces the same hex output as shown here for the same key:
I know I am on the right track, but it seems like the juce::RSAKey
is just not compatible with keys produced externally. using BigInteger::exponentModulo
also produces garbage with the parsed values.
I am not sure, when loading this hex string into the BigInteger, whether or not the external SSL public key is stored in little endian or big-endian format.
Here is what I’m currently doing, which works up until the point of decryption:
static juce::String convertPEMPublicKeyToString(juce::String pubKey)
{
jassert( pubKey.contains("-----BEGIN PUBLIC KEY-----"));
jassert( pubKey.contains("-----END PUBLIC KEY-----"));
jassert( pubKey.contains("MII")); //PEM keys start with 'MII'
auto keyDataArr = juce::StringArray::fromLines(pubKey);
keyDataArr.remove(keyDataArr.indexOf("-----END PUBLIC KEY-----"));
keyDataArr.remove(0);
keyDataArr.removeEmptyStrings();
auto pemData = keyDataArr.joinIntoString("");
DBG( "pemData: " );
DBG( pemData );
return pemData;
}
using PEMMemoryBlock = juce::MemoryBlock;
using PEMDataType = juce::uint8;
static PEMMemoryBlock convertPEMStringToPEMMemoryBlock(juce::String pemString)
{
PEMMemoryBlock mb;
{
juce::MemoryOutputStream mos(mb, false);
auto ok = juce::Base64::convertFromBase64(mos, pemString);
jassert(ok);
juce::ignoreUnused(ok);
}
return mb;
}
usage:
auto pemString = PEMHelpers::convertPEMPublicKeyToString(pubKey);
if( ! pemString.contains("MII") )
{
//it's not a PEM key. abort!
DBG( "invalid key!" );
return;
}
auto pemData = PEMHelpers::convertPEMStringToPEMMemoryBlock(pemString);
//parsing of PEM data goes here...
//then...
auto modulusHexStr = juce::String::toHexString(modulusBlock.getData(), modulus->length);
modulusHexStr = modulusHexStr.removeCharacters(" ");
DBG( "modulus hex: ");
DBG( modulusHexStr );
auto modulusBigInteger = juce::BigInteger();
modulusBigInteger.parseString(modulusHexStr, 16);
auto exponentHexStr = juce::String::toHexString(exponentBlock.getData(), exponent->length);
exponentHexStr = exponentHexStr.removeCharacters(" ");
DBG( "exponent hex: ");
DBG( exponentHexStr );
auto exponentBigInteger = juce::BigInteger();
exponentBigInteger.parseString(exponentHexStr, 16);
DBG( "exponent val: " );
DBG( exponentBigInteger.toString(10));
auto confirmation = resultVar["confirmation"].toString();
auto confirmationBlock = PEMHelpers::convertPEMStringToPEMMemoryBlock(confirmation);
auto confirmationHex = juce::String::toHexString(confirmationBlock.getData(),
confirmationBlock.getSize());
juce::BigInteger confirmationBigInt;
confirmationBigInt.parseString(confirmationHex, 16);
confirmationBigInt.exponentModulo(exponentBigInteger, modulusBigInteger);
auto decrypted = confirmationBigInt.toMemoryBlock();
decrypted
never contains the correct result.
but the exponentHexStr
and modulusHexStr
printouts match the output from various online tools that show the exponent and modulus in hex for a given public key.
Also, the value
printout matches the various online tools’ values for these massive exponents and modulos.
Comments?