ипемся очень сильно с попыткой портирования одного джава проекта на пхп споткнулись на работе с RSA ключами и шифрованием вот код: Код (Text): RSAPublicKeySpec localRSAPublicKeySpec = new RSAPublicKeySpec(new BigInteger( modulus ), publicExponent ); RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic( localRSAPublicKeySpec ); Cipher localCipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" ); localCipher.init( 1, localRSAPublicKey ); byte[] encodedstring = localCipher.doFinal( arrayOfByte4 ); проблема только одна - хз как создать публичный ключ используя два массива BigInteger и зашифровать требуемый массив
openssl_encrypt не поможет. в джава коде создается публичный RSA ключ из двух массивов ( modulus и publicExponent ) после чего какой то массив шифруется "RSA/ECB/PKCS1Padding" проблема в том чтобы зашифровать что то используя для шифрования "вручную" собранным публичным ключем. И только им. от ключа есть только publicExponent массив и modulus массив джава код прекрасно рботает но поднимать на сервер томкат ради 30 строчек кода не айс
парни, проблема не в том что я не могу кусок данных зашифровать ( хотя и в этом тоже ) а в том что у меня публичный ключ в очень хитропопом виде хранится: в виде массива RSA Modulus ( n ): и в виде массива RSA Exponent (e) вроде как по этому RFC http://tools.ietf.org/html/rfc3447#page-44 фак мой брайн но я не знаю как мне собрать ключ который пхп реализация опенссл схавает за корректный и без эксепшена выполнит шифрование: openssl_public_encrypt ( $data, $crypted, $rsapublickey, OPENSSL_PKCS1_PADDING ); ну и частично ( но я уже знаю как решить ) проблема в том что $data у меня ниразу не строка а байтовый массив: уже есть устойчивое подозрение что задача на пхп не решается и придется ради долбанного кода в 40 строчек поднимать томкат
есть подозрение, что вы так и не наняли php-программиста ) строка в PHP может содержать любые данные. можно считать, что это массив байт. для упаковки в нее из различных других форматов есть функция pack() приведите здесь полный пример, входные данные, выходные данные. мы подберем php-аналог (наверное)
код на джаве который на пхп переписат треба: Код (Text): RSAPublicKeySpec localRSAPublicKeySpec = new RSAPublicKeySpec( new BigInteger( modulus ), new BigInteger( publicExponent ) ); RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic( localRSAPublicKeySpec ); Cipher localCipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" ); localCipher.init( 1, localRSAPublicKey ); byte[] encodedstring = localCipher.doFinal( arrayOfByte4 ); publicExponent массив содержит одно hex число: { 25 }; modulus массив содержит 257 чисел: Код (Text): 7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b массив который надо зашифровать: Код (Text): 20 37 63 37 30 34 39 64 37 63 63 37 30 62 38 38 37 33 35 36 39 65 36 64 65 38 65 61 32 32 37 39 30 20 89 58 83 79 76 D5 C2 FD 87 58 01 4D 15 B4 A8 87 EA 3F 4D 76 83 A2 BD E5 E4 F9 60 0D 37 F6 E9 79 массив encodedstring всегда разный потому что спецификация "RSA/ECB/PKCS1Padding" так что приводить его тут смысла нет
http://www.identityblog.com/?p=389 Добавлено спустя 2 минуты 51 секунду: Код (PHP): <?php $modulus = trim(" 7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b "); $hex = str_replace([" ", "\n"], "", $modulus); $bin = hex2bin($hex); $base = base64_encode($bin); Добавлено спустя 4 минуты 53 секунды: http://stackoverflow.com/a/20291753
вольная компиляция всего вышеперечисленного: Код (PHP): <?php function myHexToBin($s) { return hex2bin(str_replace(array("\r","\n"," "), '', $s)); } /** * See: http://www.identityblog.com/?p=389 */ function makePublicKey($modulus, $exponent) { // decode to binary $modulus = $modulus; $exponent = $exponent; // make an ASN publicKeyInfo $exponentEncoding = makeAsnSegment(0x02, $exponent); $modulusEncoding = makeAsnSegment(0x02, $modulus); $sequenceEncoding = makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding); $bitstringEncoding = makeAsnSegment(0x03, $sequenceEncoding); $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); $publicKeyInfo = makeAsnSegment (0x30, $rsaAlgorithmIdentifier.$bitstringEncoding); // encode the publicKeyInfo in base64 and add PEM brackets $publicKeyInfoBase64 = base64_encode($publicKeyInfo); $encoding = "-----BEGIN PUBLIC KEY-----\n"; $offset = 0; while ($segment=substr($publicKeyInfoBase64, $offset, 64)){ $encoding = $encoding.$segment."\n"; $offset += 64; } $encoding = $encoding."-----END PUBLIC KEY-----\n"; // use the PEM version of the key to get a key handle $publicKey = openssl_pkey_get_public ($encoding); return ($publicKey); } function makeAsnSegment($type, $string) { // fix up integers and bitstrings switch ($type){ case 0x02: if (ord($string) > 0x7f) $string = chr(0).$string; break; case 0x03: $string = chr(0).$string; break; } $length = strlen($string); if ($length < 128){ $output = sprintf("%c%c%s", $type, $length, $string); } else if ($length < 0x0100){ $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string); } else if ($length < 0x010000) { $output = sprintf("%c%c%c%c%s", $type, 0x82, $length/0x0100, $length%0x0100, $string); } else { $output = NULL; } return($output); } $modulus = myHexToBin(' 7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b'); $exponent = myHexToBin('25'); $data = myHexToBin(' 20 37 63 37 30 34 39 64 37 63 63 37 30 62 38 38 37 33 35 36 39 65 36 64 65 38 65 61 32 32 37 39 30 20 89 58 83 79 76 D5 C2 FD 87 58 01 4D 15 B4 A8 87 EA 3F 4D 76 83 A2 BD E5 E4 F9 60 0D 37 F6 E9 79'); $key = makePublicKey($modulus, $exponent); if (openssl_public_encrypt ($data, $crypted, $key, OPENSSL_PKCS1_PADDING)) { echo base64_encode($crypted); } else { echo 'Oops!'; } проверяйте соответствует ли ожиданиям.
Складывается впечатление, что проще создать pem ключ, положить его на сервер, и спокойно использовать openssl_encrypt вместо всего этого мракобесия.
у меня есть готовыи публичный ключ который представлен таким вот хитрым способом. другого публичного ключа для работы с чужим сервером у меня нет. upd вопрос решен. просто дописал одну функцию в phpseclib ( в RSA.php ) которая и позволяет задать ключ по e и n компонентам потому что вот как советуют тут: http://stackoverflow.com/questions/20289597/php-rsa-encrypt ... 3#20291753 Код (Text): $rsa->loadKey( array( 'e' => new Math_BigInteger('...'), 'n' => new Math_BigInteger('...') ) ); не работает.
в библиотеку phpseclib в код RSA.php добавить одну функцию: Код (Text): function loadKeyEx( $n, $e ) { $this->modulus = $n; $this->k = strlen( $this->modulus->toBytes() ); $this->exponent = $e; } ну и юзаю так: Код (Text): $n = new Math_BigInteger( $n, 256); $e = new Math_BigInteger( $e, 256); $rsa = new Crypt_RSA(); $rsa->loadKeyEx( $n, $e ); в $n и $e предварительно загружаю массив байт modulus и exponent соотвественно