I'm currently stuck with the problem of RSA key management. To be specific, I want to create an RSA keypair in Java, sign some content (i.e. a String) export the public key, the signature, and the signed String into a JSON file (yes, a JSON!), import it on another server using PHP, and validate the signature, meaning that I have to re-create a usable key from the JSON data.
Plus, I have to do it the other way around (create in PHP, verify in Java)
Plus, I need to export the private keys into JSON (Yes, JSON again :) !) and export this.
So on the Java side, everything seems to work smoothly. I can create keys, export them to JSON, re-import them, and use them. Creating and verifying signatures is no problem. Here is the code:
creating a keypair:
public static final String ALGORITHM = "RSA";
public static final int KEYSIZE = 4096;
public static KeyPair createKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEYSIZE);
return keyPairGenerator.genKeyPair();
}
exporting the keys to a String (that will end up in the JSON Object) - the code for the private Key is similar:
public static final String PUBLICKEY_PREFIX = "-----BEGIN PUBLIC KEY-----";
public static final String PUBLICKEY_POSTFIX = "-----END PUBLIC KEY-----";
public static String exportPublicKey(Key key) {
return PUBLICKEY_PREFIX + DatatypeConverter.printBase64Binary(key.getEncoded()) + PUBLICKEY_POSTFIX;
}
The result of the above would be for example
"-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtBPxEtEWws2pPN5HCB795+nQyX23ZTKJt5PoMQQpwjOY/7U5ODkwHpuHWUhAuB1qTKTUdEWbe5x7WkD6/ksSib64Xq3jIeLQrfhj+g3bGsQjtca5LyIZ/J+G55l7k/Ny/lfQQNfquCcILHW7DrnzTb0D56IOBsR/r0Vv8ZvUxnaXUQtif8Q6dme8uoqzfnF46McqThnvPDxdHmhumb7tqPffzt35bRxFBvMcAWqW0FcPAeXD6cmsOBAATh/gVe1g5J89FyK8PhkNjW3uLMmknCTQg9KoWh4+DDRrLXxqSCBbaIRMCtbhShZOIbtjurJ+ZjhR/WSPnzJrl84rTjWG3Po6jsdtJ0pRHP4YnXXXJWhMt2oTOtHTQj4+99UX7Yuyp2tmFaEdQXvm3k/qbT9PBlwEovC2yqbFMcrM7sAW09NiSDdm1ipzV+vsOGuRXF2vtNX6pplifp5va5hQY/UqmlHSygvecImP5ennFOP7G62W/Q0w0qRzOXmFHN6Hsi8D1ZlWwgjyNahoX2yvgBMzy7MMYJcqiS9GOOETaenXTZViiipceGk96crjh6LG7RudMb+WN2yRXnjdWYd0GYPsaXz/faMohfXRXzRq/oIGZ4EdHhp9TknL2rCZmfR3N4Ozi1BkszAmmQeeNrUgxEjB8TdSer4p4DfR22NFcs9M3YkCAwEAAQ==-----END PUBLIC KEY-----"
then, I read the keys from the JSON again:
public static PublicKey importPublicKey(String key) throws InvalidKeySpecException, NoSuchAlgorithmException {
key = stripKey(key);
byte[] keyBytes = DatatypeConverter.parseBase64Binary(key);
return KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(keyBytes));
}
public static PrivateKey importPrivateKey(String key) throws InvalidKeySpecException, NoSuchAlgorithmException {
key = stripKey(key);
byte[] keyBytes = DatatypeConverter.parseBase64Binary(key);
return KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
}
This works fine for me. I can create, store, re-import, and use the keys - both public and private. Signatures i create using
public static String createSignature(PrivateKey privateKey, String message) {
String algorithm = "SHA512withRSA";
Signature signature = null;
String signedString = null;
try {
signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(message.getBytes());
byte[] signatureByteArray = signature.sign();
signedString = "-----BEGIN SIGNATURE-----"
+ DatatypeConverter.printBase64Binary(signatureByteArray)
+ "-----END SIGNATURE-----";
} catch(Exception e) {
e.printStackTrace();
}
return signedString;
}
can be verified easily using java.security.Signature.verify()
. So far I'm happy.
Now the tricky part: I send the created JSONs to the other server, and here, my trouble starts:
First, I strip the header and trailer from the string ("-----BEGIN" and so on...), then, I use base64_decode()
, and ASSUME, that the result would be usable as a key with a call of openssl_pkey_get_private()
Anyhow, I get errors like
openssl_sign(): supplied key param cannot be coerced into a private key
every time I try to use my keys.
So In Java, I create a new X509EncodedKeySpec(keyBytes)
, yet, in PHP, there is no such functionality (?)
Where does my en/decoding go wrong? I'm actually a bit lost :(
Your key is currently stored in binary format, which is usually known as "DER" format. That is the way Java stores the key. To be able to read it from PHP, you have to convert the key to PEM format, which is the format for OpenSSL. As a result, PHP requires that the key be in PEM format. Here is a PHP function which can convert DER encoded keys to PEM encoded keys in PHP:
function X509_to_pem($der_data) {
$BEGIN= "-----BEGIN SIGNATURE-----";
$END = "-----BEGIN SIGNATURE-----";
$base64Encoded= base64_encode($der_data);
$pem = $BEGIN . "\n";
$pem .= chunk_split($base64Encoded, 64, "\n");
$pem .= $END . "\n";
return $pem;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With