За последние 24 часа нас посетили 15629 программистов и 1558 роботов. Сейчас ищет 831 программист ...

RSA шифрование порт с JAVA на PHP нужен хелп

Тема в разделе "Прочие вопросы по PHP", создана пользователем orfelin, 2 апр 2014.

  1. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    ипемся очень сильно с попыткой портирования одного джава проекта на пхп
    споткнулись на работе с RSA ключами и шифрованием
    вот код:

    Код (Text):
    1.  
    2. RSAPublicKeySpec localRSAPublicKeySpec = new RSAPublicKeySpec(new BigInteger( modulus ), publicExponent );
    3. RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic( localRSAPublicKeySpec );
    4. Cipher localCipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
    5. localCipher.init( 1, localRSAPublicKey );
    6. byte[] encodedstring = localCipher.doFinal( arrayOfByte4 );
    проблема только одна - хз как создать публичный ключ используя два массива BigInteger и зашифровать требуемый массив
     
  2. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
  3. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    openssl_encrypt не поможет.

    в джава коде создается публичный RSA ключ из двух массивов ( modulus и publicExponent ) после чего какой то массив шифруется "RSA/ECB/PKCS1Padding"

    проблема в том чтобы зашифровать что то используя для шифрования "вручную" собранным публичным ключем. И только им.

    от ключа есть только publicExponent массив и modulus массив

    джава код прекрасно рботает но поднимать на сервер томкат ради 30 строчек кода не айс
     
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
  5. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    Ну так это решение - обёртка для openssl
     
  6. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    парни, проблема не в том что я не могу кусок данных зашифровать ( хотя и в этом тоже ) а в том что у меня публичный ключ в очень хитропопом виде хранится:

    в виде массива 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 строчек поднимать томкат
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    есть подозрение, что вы так и не наняли php-программиста )

    строка в PHP может содержать любые данные. можно считать, что это массив байт. для упаковки в нее из различных других форматов есть функция pack()

    приведите здесь полный пример, входные данные, выходные данные. мы подберем php-аналог (наверное)
     
  8. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    код на джаве который на пхп переписат треба:
    Код (Text):
    1. RSAPublicKeySpec localRSAPublicKeySpec = new RSAPublicKeySpec( new BigInteger( modulus ), new BigInteger( publicExponent ) );
    2. RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic( localRSAPublicKeySpec );
    3. Cipher localCipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
    4. localCipher.init( 1, localRSAPublicKey );
    5.  
    6. byte[] encodedstring = localCipher.doFinal( arrayOfByte4 );
    publicExponent массив содержит одно hex число: { 25 };
    modulus массив содержит 257 чисел:
    Код (Text):
    1. 7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f
    2. d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46
    3. dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9
    4. cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32
    5. 70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60
    6. 1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1
    7. 90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d
    8. 3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0
    9. e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb
    10. d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b
    11. ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d
    12. e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8
    13. 76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1
    14. fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f
    15. 5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b
    16. 60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b
    массив который надо зашифровать:
    Код (Text):
    1. 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
    2. 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
    3. E9 79
    массив encodedstring всегда разный потому что спецификация "RSA/ECB/PKCS1Padding" так что приводить его тут смысла нет
     
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    как проверить результат на валидность? консольная openssl сможет нам помочь?
     
  10. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    orfelin, Результат зашифрованных данных приведите пожалуйста (который генерирует java).
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    topas,
    нужен способ проверить достоверность, а не буквально сравнить
     
  12. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    http://www.identityblog.com/?p=389

    Добавлено спустя 2 минуты 51 секунду:
    Код (PHP):
    1. <?php
    2.  
    3. $modulus = trim("
    4. 7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f
    5. d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 
    6. dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 
    7. cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 
    8. 70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 
    9. 1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 
    10. 90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 
    11. 3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 
    12. e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb 
    13. d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b 
    14. ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d 
    15. e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 
    16. 76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 
    17. fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 
    18. 5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 
    19. 60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b
    20. ");
    21.  
    22. $hex = str_replace([" ", "\n"], "", $modulus);
    23. $bin = hex2bin($hex);
    24.  
    25. $base = base64_encode($bin);
    Добавлено спустя 4 минуты 53 секунды:
    http://stackoverflow.com/a/20291753
     
  13. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    вольная компиляция всего вышеперечисленного:
    Код (PHP):
    1. <?php
    2.  
    3. function myHexToBin($s)
    4. {
    5.     return hex2bin(str_replace(array("\r","\n"," "), '', $s));
    6. }
    7.  
    8. /**
    9.  * See: http://www.identityblog.com/?p=389
    10.  */
    11. function makePublicKey($modulus, $exponent)
    12. {
    13.     // decode to binary
    14.     $modulus = $modulus;
    15.     $exponent = $exponent;
    16.  
    17.     // make an ASN publicKeyInfo
    18.     $exponentEncoding = makeAsnSegment(0x02, $exponent);    
    19.     $modulusEncoding = makeAsnSegment(0x02, $modulus);    
    20.     $sequenceEncoding = makeAsnSegment(0x30, 
    21.         $modulusEncoding.$exponentEncoding);
    22.     $bitstringEncoding = makeAsnSegment(0x03, $sequenceEncoding);
    23.     $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); 
    24.     $publicKeyInfo = makeAsnSegment (0x30, 
    25.         $rsaAlgorithmIdentifier.$bitstringEncoding);
    26.  
    27.     // encode the publicKeyInfo in base64 and add PEM brackets
    28.     $publicKeyInfoBase64 = base64_encode($publicKeyInfo);    
    29.     $encoding = "-----BEGIN PUBLIC KEY-----\n";
    30.     $offset = 0;
    31.     while ($segment=substr($publicKeyInfoBase64, $offset, 64)){
    32.        $encoding = $encoding.$segment."\n";
    33.        $offset += 64;
    34.     }
    35.     $encoding = $encoding."-----END PUBLIC KEY-----\n";
    36.  
    37.     // use the PEM version of the key to get a key handle
    38.     $publicKey = openssl_pkey_get_public ($encoding);
    39.  
    40.     return ($publicKey);
    41. }
    42.  
    43. function makeAsnSegment($type, $string)
    44. {
    45.     // fix up integers and bitstrings
    46.     switch ($type){
    47.         case 0x02:
    48.             if (ord($string) > 0x7f)
    49.                 $string = chr(0).$string;
    50.             break;
    51.         case 0x03:
    52.             $string = chr(0).$string;
    53.             break;
    54.     }
    55.  
    56.     $length = strlen($string);
    57.  
    58.     if ($length < 128){
    59.        $output = sprintf("%c%c%s", $type, $length, $string);
    60.     }
    61.     else if ($length < 0x0100){
    62.        $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
    63.     }
    64.     else if ($length < 0x010000) {
    65.        $output = sprintf("%c%c%c%c%s", $type, 0x82, $length/0x0100, $length%0x0100, $string);
    66.     }
    67.     else {
    68.         $output = NULL;
    69.     }
    70.  
    71.     return($output);
    72. }
    73.  
    74. $modulus = myHexToBin('
    75.   7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f
    76.   d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 
    77.   dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 
    78.   cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 
    79.   70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 
    80.   1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 
    81.   90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 
    82.   3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 
    83.   e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb 
    84.   d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b 
    85.   ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d 
    86.   e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 
    87.   76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 
    88.   fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 
    89.   5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 
    90.   60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b');
    91.  
    92. $exponent = myHexToBin('25');
    93.  
    94. $data = myHexToBin('
    95.   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 
    96.   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 
    97.   E9 79');
    98.  
    99. $key = makePublicKey($modulus, $exponent);
    100.  
    101. if (openssl_public_encrypt ($data, $crypted, $key, OPENSSL_PKCS1_PADDING)) {
    102.     echo base64_encode($crypted);
    103. } else {
    104.     echo 'Oops!';
    105. }
    106.  
    проверяйте соответствует ли ожиданиям.
     
  14. topas

    topas Активный пользователь

    С нами с:
    16 авг 2006
    Сообщения:
    2.258
    Симпатии:
    36
    Складывается впечатление, что проще создать pem ключ, положить его на сервер, и спокойно использовать openssl_encrypt вместо всего этого мракобесия.
     
  15. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
  16. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    у меня есть готовыи публичный ключ который представлен таким вот хитрым способом. другого публичного ключа для работы с чужим сервером у меня нет.

    upd
    вопрос решен.
    просто дописал одну функцию в phpseclib ( в RSA.php ) которая и позволяет задать ключ по e и n компонентам

    потому что вот как советуют тут: http://stackoverflow.com/questions/20289597/php-rsa-encrypt ... 3#20291753
    Код (Text):
    1. $rsa->loadKey(
    2.     array(
    3.         'e' => new Math_BigInteger('...'),
    4.         'n' => new Math_BigInteger('...')
    5.     )
    6. );
    не работает.
     
  17. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    может поделитесь? вдруг еще кому пригодится.
     
  18. orfelin

    orfelin Активный пользователь

    С нами с:
    3 мар 2011
    Сообщения:
    36
    Симпатии:
    0
    в библиотеку phpseclib в код RSA.php добавить одну функцию:
    Код (Text):
    1.  
    2. function loadKeyEx( $n, $e )
    3. {
    4.     $this->modulus = $n;
    5.     $this->k = strlen( $this->modulus->toBytes() );
    6.  
    7.     $this->exponent = $e;
    8. }
    ну и юзаю так:
    Код (Text):
    1.  
    2.     $n = new Math_BigInteger( $n, 256);
    3.     $e = new Math_BigInteger( $e, 256);
    4.  
    5.     $rsa = new Crypt_RSA();
    6.     $rsa->loadKeyEx( $n, $e );
    в $n и $e предварительно загружаю массив байт modulus и exponent соотвественно