java php openssl rsa

PublicKey manejando Java/PHP



openssl rsa (2)

Su clave se almacena actualmente en formato binario, que generalmente se conoce como formato "DER". Esa es la forma en que Java almacena la clave. Para poder leerlo desde PHP, debe convertir la clave al formato PEM, que es el formato para OpenSSL. Como resultado, PHP requiere que la clave esté en formato PEM. Aquí hay una función PHP que puede convertir claves codificadas DER a claves codificadas PEM en 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; }

Actualmente estoy atascado con el problema de la administración de claves de RSA. Para ser específico, quiero crear un par de claves RSA en Java, firmar algún contenido (es decir, una cadena) exportar la clave pública, la firma y la cadena firmada en un archivo JSON (¡sí, un JSON!), Importarlo en otro servidor usando PHP, y validar la firma, lo que significa que tengo que volver a crear una clave utilizable a partir de los datos JSON.

Además, tengo que hacerlo al revés (crear en PHP, verificar en Java)

Además, necesito exportar las claves privadas a JSON (¡Sí, JSON otra vez :)!) Y exportar esto.

Entonces en el lado de Java, todo parece funcionar sin problemas. Puedo crear claves, exportarlas a JSON, volver a importarlas y usarlas. Crear y verificar firmas no es un problema. Aquí está el código:

creando un par de llaves:

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(); }

exportar las claves a una cadena (que terminará en el objeto JSON): el código para la clave privada es 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; }

El resultado de lo anterior sería, por ejemplo,

"-----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-----"

luego, leo las claves de JSON nuevamente:

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)); }

Esto funciona bien para mi. Puedo crear, almacenar, volver a importar y usar las claves, tanto públicas como privadas. Firmas que creo usando

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; }

se puede verificar fácilmente usando java.security.Signature.verify() . Hasta ahora estoy feliz.

Ahora la parte complicada: envío los JSON creados al otro servidor, y aquí, mi problema comienza:

Primero, quito el encabezado y el avance de la cadena ("----- BEGIN" y así sucesivamente ...), entonces, uso base64_decode() , y ASUMO, que el resultado se puede usar como una clave con un llamada de openssl_pkey_get_private()

De todos modos, recibo errores como

openssl_sign(): supplied key param cannot be coerced into a private key

cada vez que trato de usar mis llaves.

Entonces, en Java, creo un new X509EncodedKeySpec(keyBytes) , sin embargo, en PHP, no hay tal funcionalidad (?)

¿Dónde se equivoca mi en / decodificación? En realidad estoy un poco perdido :(


Bueno, parece que encontré mi respuesta. Aquí hay un código de ejemplo que resultó funcionar bien:

public class KeyTest{ static final String ALGORITHM = "RSA"; static final int KEYSIZE = 1024; static final String SIGNATURE_ALGORITHM = "SHA512withRSA"; static final String PUBLICKEY_PREFIX = "-----BEGIN PUBLIC KEY-----"; static final String PUBLICKEY_POSTFIX = "-----END PUBLIC KEY-----"; static final String PRIVATEKEY_PREFIX = "-----BEGIN RSA PRIVATE KEY-----"; static final String PRIVATEKEY_POSTFIX = "-----END RSA PRIVATE KEY-----"; public static void main(String args[]) { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); keyPairGenerator.initialize(KEYSIZE); KeyPair keyPair = keyPairGenerator.genKeyPair(); // THIS IS java.security PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); System.out.println("Public java.security: Algorithm: " + publicKey.getAlgorithm() + "Format: " + publicKey.getFormat()); System.out.println("Private java.security: Algorithm: " + privateKey.getAlgorithm() + "Format: " + privateKey.getFormat() + "/n"); // THIS IS DER: byte[] publicKeyDER = publicKey.getEncoded(); byte[] privateKeyDER = privateKey.getEncoded(); System.out.println("Public DER: "+Arrays.toString(publicKeyDER)); System.out.println("Private DER: "+Arrays.toString(privateKeyDER) + "/n"); // THIS IS PEM: String publicKeyPEM = PUBLICKEY_PREFIX + "/n" + DatatypeConverter.printBase64Binary(publicKey.getEncoded()).replaceAll("(.{64})", "$1/n") + "/n" + PUBLICKEY_POSTFIX; String privateKeyPEM = PRIVATEKEY_PREFIX + "/n" + DatatypeConverter.printBase64Binary(privateKey.getEncoded()).replaceAll("(.{64})", "$1/n") + "/n" + PRIVATEKEY_POSTFIX; System.out.println("Public PEM: " + "/n"+publicKeyPEM); System.out.println("Private PEM: " + "/n"+privateKeyPEM + "/n"); // Signing the teststring String message = "Lorem ipsum dolor sit amet"; Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initSign(privateKey); sig.update(message.getBytes()); byte[] signatureByteArray = sig.sign(); String signature = "-----BEGIN SIGNATURE-----" + "/n" + DatatypeConverter.printBase64Binary(signatureByteArray).replaceAll("(.{64})", "$1/n") + "/n" + "-----END SIGNATURE-----"; System.out.println("Message Plaintext: " + message); System.out.println("Signature: " + "/n" + signature + "/n"); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }

El resultado de esto es algo como esto:

Public java.security: Algorithm: RSAFormat: X.509 Private java.security: Algorithm: RSAFormat: PKCS#8 Public DER: [48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, -115, 0, 48, -127, -119, 2, -127, -127, 0, -125, -8, 66, -86, -27, -55, 14, 50, 26, -103, -87, 102, 47, 126, -70, 57, -27, 103, -95, 10, 26, 25, -3, -18, -44, -85, 11, -19, -92, 111, 22, -6, 94, 79, -126, 32, -68, -82, -67, 24, -108, 9, 46, -100, 25, -37, 56, 2, -122, -31, -93, 56, -39, 79, -67, 33, -126, -13, -72, -120, 115, 3, -57, -120, -86, 119, 57, -110, -6, -11, -36, 109, -113, -69, -11, -81, -94, 47, 59, -7, 119, 108, -89, -26, -55, 117, -74, 125, -39, -1, 116, -116, -9, -60, -57, -78, -118, 45, 38, 120, -43, 123, -51, -104, 42, -47, 101, -120, 78, 9, -2, -84, 113, -42, -71, 101, 3, -44, -58, 39, 50, 96, 83, 90, 71, 41, 83, -13, 2, 3, 1, 0, 1] Private DER: [48, -126, 2, 118, 2, 1, 0, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 4, -126, 2, 96, 48, -126, 2, 92, 2, 1, 0, 2, -127, -127, 0, -125, -8, 66, -86, -27, -55, 14, 50, 26, -103, -87, 102, 47, 126, -70, 57, -27, 103, -95, 10, 26, 25, -3, -18, -44, -85, 11, -19, -92, 111, 22, -6, 94, 79, -126, 32, -68, -82, -67, 24, -108, 9, 46, -100, 25, -37, 56, 2, -122, -31, -93, 56, -39, 79, -67, 33, -126, -13, -72, -120, 115, 3, -57, -120, -86, 119, 57, -110, -6, -11, -36, 109, -113, -69, -11, -81, -94, 47, 59, -7, 119, 108, -89, -26, -55, 117, -74, 125, -39, -1, 116, -116, -9, -60, -57, -78, -118, 45, 38, 120, -43, 123, -51, -104, 42, -47, 101, -120, 78, 9, -2, -84, 113, -42, -71, 101, 3, -44, -58, 39, 50, 96, 83, 90, 71, 41, 83, -13, 2, 3, 1, 0, 1, 2, -127, -128, 39, -40, 45, -16, -63, 62, 9, -18, 48, -65, -46, 56, -117, 0, 125, 35, 123, -46, -28, -7, 82, -42, 36, 40, 22, -57, -87, -21, 79, 41, 71, 75, -62, 107, -55, 3, 47, 84, -90, -67, 35, -4, -3, -72, -99, -55, -27, 72, 70, 7, 28, 43, -50, -40, -41, 102, -91, -50, 6, 26, 20, 119, -64, -89, 96, 97, -101, 103, -46, 34, 95, -91, 19, 43, 4, 63, -121, 30, 85, 11, 86, 33, 58, -62, -108, 74, 56, 81, -123, 24, -8, 121, -11, -119, 43, -97, -50, 24, -60, 72, -15, 6, -87, 123, -16, 123, -17, -39, 56, -44, 97, -57, -8, 16, 9, -72, 68, 53, 1, 87, 94, -16, -54, 115, 15, -34, 93, -23, 2, 65, 0, -59, 121, -7, -34, 118, -24, 27, -9, 83, -125, -115, 120, -78, 33, -122, -78, 7, 33, 18, -44, -57, -87, 50, 99, -105, -68, -69, -82, 116, 53, -119, 113, 41, -115, 83, 66, -55, -9, -47, -12, 49, -58, 14, 68, -76, 106, 95, 102, -96, 90, -61, -40, -17, -10, 81, 116, -6, -125, -68, -33, -18, -19, 43, -11, 2, 65, 0, -85, 20, 118, 69, 108, -51, 79, -63, 70, -35, -16, -47, 81, -48, 51, 36, 99, 79, -78, -84, -86, 41, 49, -56, 101, 100, -80, 121, 53, -5, -98, -9, 53, 110, 58, -60, -39, 39, 100, -64, -108, 36, -29, -127, -13, -110, 120, 46, -31, -79, -10, -36, -26, -94, -117, -6, -76, 121, -15, -17, -31, 94, -73, 71, 2, 64, 119, 0, 35, 48, 9, 77, -92, 20, -83, -47, -9, -67, -60, -14, 105, 29, -3, 39, -44, 22, 63, 95, 89, -117, 36, -108, 74, 49, 61, -68, 73, 95, -43, 31, 98, 14, 60, 113, 71, -89, 53, 27, 89, -37, -45, 48, -54, -34, -88, 65, 42, 6, 31, -52, -70, -105, -104, -93, 44, 125, 113, -104, -96, -59, 2, 64, 122, -26, 48, 48, -97, -128, -66, -110, -78, 62, 46, 9, -79, 36, 72, 25, 19, -34, -27, 20, 117, 9, 50, -30, 43, 52, -78, 49, -31, 61, -23, 108, -35, -51, 90, 26, -97, -123, 85, 51, -93, 56, -4, -41, 22, 11, 90, -101, 19, 55, -83, -121, -13, -121, 65, -41, -48, 94, -22, 22, -47, 104, 33, 113, 2, 65, 0, -65, 101, -127, -118, 21, 122, -114, 47, 65, -96, -37, -104, 100, 52, 38, -81, 9, -9, 120, -56, -36, -92, -52, 7, -47, -8, -101, 83, -24, -82, -81, -60, 71, -47, 111, -49, 1, 46, 16, -52, -87, -79, 21, -68, 22, 18, -37, -62, 33, 102, 40, -49, -122, -98, -83, 1, 94, 29, -85, 93, -16, -7, -57, 119] Public PEM: -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCD+EKq5ckOMhqZqWYvfro55Weh ChoZ/e7UqwvtpG8W+l5PgiC8rr0YlAkunBnbOAKG4aM42U+9IYLzuIhzA8eIqnc5 kvr13G2Pu/Wvoi87+Xdsp+bJdbZ92f90jPfEx7KKLSZ41XvNmCrRZYhOCf6scda5 ZQPUxicyYFNaRylT8wIDAQAB -----END PUBLIC KEY----- Private PEM: -----BEGIN RSA PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIP4QqrlyQ4yGpmp Zi9+ujnlZ6EKGhn97tSrC+2kbxb6Xk+CILyuvRiUCS6cGds4AobhozjZT70hgvO4 iHMDx4iqdzmS+vXcbY+79a+iLzv5d2yn5sl1tn3Z/3SM98THsootJnjVe82YKtFl iE4J/qxx1rllA9TGJzJgU1pHKVPzAgMBAAECgYAn2C3wwT4J7jC/0jiLAH0je9Lk +VLWJCgWx6nrTylHS8JryQMvVKa9I/z9uJ3J5UhGBxwrztjXZqXOBhoUd8CnYGGb Z9IiX6UTKwQ/hx5VC1YhOsKUSjhRhRj4efWJK5/OGMRI8Qape/B779k41GHH+BAJ uEQ1AVde8MpzD95d6QJBAMV5+d526Bv3U4ONeLIhhrIHIRLUx6kyY5e8u650NYlx KY1TQsn30fQxxg5EtGpfZqBaw9jv9lF0+oO83+7tK/UCQQCrFHZFbM1PwUbd8NFR 0DMkY0+yrKopMchlZLB5Nfue9zVuOsTZJ2TAlCTjgfOSeC7hsfbc5qKL+rR58e/h XrdHAkB3ACMwCU2kFK3R973E8mkd/SfUFj9fWYsklEoxPbxJX9UfYg48cUenNRtZ 29Mwyt6oQSoGH8y6l5ijLH1xmKDFAkB65jAwn4C+krI+LgmxJEgZE97lFHUJMuIr NLIx4T3pbN3NWhqfhVUzozj81xYLWpsTN62H84dB19Be6hbRaCFxAkEAv2WBihV6 ji9BoNuYZDQmrwn3eMjcpMwH0fibU+iur8RH0W/PAS4QzKmxFbwWEtvCIWYoz4ae rQFeHatd8PnHdw== -----END RSA PRIVATE KEY----- Message Plaintext: Lorem ipsum dolor sit amet Signature: -----BEGIN SIGNATURE----- UxhWlr8Ks3PkfaKK8IGGolUs8qjvbE4dXs8ANUtJdw48g8nk6pOEuEscpSiszc1O fBFEG6lexRFeW4+zpyWHN8oJpVaxz7sd2lstFqu/dUkU8HtPujKkwK6c/3pzsAt8 yHru/BPRwI8Wryqm2dfiHO4cXKq5rIXfj0sSXbwI1PE= -----END SIGNATURE-----

Ahora codifiqué estos valores en PHP:

<?php $publicKeyPEM = "-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCD+EKq5ckOMhqZqWYvfro55Weh ChoZ/e7UqwvtpG8W+l5PgiC8rr0YlAkunBnbOAKG4aM42U+9IYLzuIhzA8eIqnc5 kvr13G2Pu/Wvoi87+Xdsp+bJdbZ92f90jPfEx7KKLSZ41XvNmCrRZYhOCf6scda5 ZQPUxicyYFNaRylT8wIDAQAB -----END PUBLIC KEY-----"; $privateKeyPEM = "-----BEGIN RSA PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIP4QqrlyQ4yGpmp Zi9+ujnlZ6EKGhn97tSrC+2kbxb6Xk+CILyuvRiUCS6cGds4AobhozjZT70hgvO4 iHMDx4iqdzmS+vXcbY+79a+iLzv5d2yn5sl1tn3Z/3SM98THsootJnjVe82YKtFl iE4J/qxx1rllA9TGJzJgU1pHKVPzAgMBAAECgYAn2C3wwT4J7jC/0jiLAH0je9Lk +VLWJCgWx6nrTylHS8JryQMvVKa9I/z9uJ3J5UhGBxwrztjXZqXOBhoUd8CnYGGb Z9IiX6UTKwQ/hx5VC1YhOsKUSjhRhRj4efWJK5/OGMRI8Qape/B779k41GHH+BAJ uEQ1AVde8MpzD95d6QJBAMV5+d526Bv3U4ONeLIhhrIHIRLUx6kyY5e8u650NYlx KY1TQsn30fQxxg5EtGpfZqBaw9jv9lF0+oO83+7tK/UCQQCrFHZFbM1PwUbd8NFR 0DMkY0+yrKopMchlZLB5Nfue9zVuOsTZJ2TAlCTjgfOSeC7hsfbc5qKL+rR58e/h XrdHAkB3ACMwCU2kFK3R973E8mkd/SfUFj9fWYsklEoxPbxJX9UfYg48cUenNRtZ 29Mwyt6oQSoGH8y6l5ijLH1xmKDFAkB65jAwn4C+krI+LgmxJEgZE97lFHUJMuIr NLIx4T3pbN3NWhqfhVUzozj81xYLWpsTN62H84dB19Be6hbRaCFxAkEAv2WBihV6 ji9BoNuYZDQmrwn3eMjcpMwH0fibU+iur8RH0W/PAS4QzKmxFbwWEtvCIWYoz4ae rQFeHatd8PnHdw== -----END RSA PRIVATE KEY-----"; $message_plaintext = "Lorem ipsum dolor sit amet"; $signature = "-----BEGIN SIGNATURE----- UxhWlr8Ks3PkfaKK8IGGolUs8qjvbE4dXs8ANUtJdw48g8nk6pOEuEscpSiszc1O fBFEG6lexRFeW4+zpyWHN8oJpVaxz7sd2lstFqu/dUkU8HtPujKkwK6c/3pzsAt8 yHru/BPRwI8Wryqm2dfiHO4cXKq5rIXfj0sSXbwI1PE= -----END SIGNATURE-----"; function verify_signature($message, $public_key, $signature) { $algorithm = OPENSSL_ALGO_SHA512; $hash_algorithm = ''sha512''; $signature = str_replace(''-----BEGIN SIGNATURE-----'', '''', $signature); $signature = str_replace(''-----END SIGNATURE-----'', '''', $signature); $signature = base64_decode($signature); $success = openssl_verify($message, $signature, $public_key, $algorithm); return $success; } var_dump(verify_signature($message_plaintext, $publicKeyPEM, $signature)); ?>

... y esto realmente funciona Todavía no veo por qué la solución de Jack no funcionó, pero bueno ...

Espero que esto ayude a otras personas a administrar claves, ya que no encontré muchos ejemplos de plataformas cruzadas en la red ...

Sin embargo, un sitio que recomendaría es http://pumka.net/2009/12/19/reading-writing-and-converting-rsa-keys-in-pem-der-publickeyblob-and-privatekeyblob-formats/