Несовпадение подписи сообщения приватным ключом в Android Java и PHP
День добрый, господа разработчики! Прошу помощи и совета. Преамбулу, что я новенький в программировании под Android и тд и тп опустим. Итак. Разрабатываю приложение которому по протоколу обмена с API необходимо каждый свой запрос подписывать электронным приватным ключом (самоподписанным). Эта подпись на сервере проверяется с помощью PHP и публичного ключа. Приватный ключ, необходимый для подписания запроса лежит в raw в виде .pfx Вот так я его читаю:
public static PrivateKey getCompanyPrivateKey(Context myContext) { String keyAlias = null; KeyStore keystore = null; PrivateKey key = null; Enumeration aliases = null; InputStream is; try { is = myContext.getResources().openRawResource(R.raw.company); keystore = KeyStore.getInstance("PKCS12"); } catch ( KeyStoreException e) { return null; } try { assert keystore != null; keystore.load(is, PKCS_PASSWD.toCharArray()); } catch (IOException | NoSuchAlgorithmException | CertificateException e) { return null; } try { aliases = keystore.aliases(); } catch (KeyStoreException e) { //e.printStackTrace(); return null; } assert aliases != null; while (aliases.hasMoreElements()) { keyAlias = (String) aliases.nextElement(); } try { key = (PrivateKey) keystore.getKey(keyAlias, PKCS_PASSWD.toCharArray()); } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e ) { return null; } return key; }
Вот так подписываю:
public static String openssl_sign(PrivateKey privateKey, String plainText) { byte[] signature = null; try { Signature sig = Signature.getInstance("SHA256withRSA"); sig.initSign(privateKey); sig.update(plainText.getBytes(StandardCharsets.UTF_8)); signature = sig.sign(); } catch(Exception ex) { ex.printStackTrace(); } return Base64.encodeToString(signature, Base64.DEFAULT); }
Все это работает без ошибок. Я получаю приватный ключи из .pfx и подпись строки в виде base64.
n4TLl9Lz86ufMdp4M2an/8Dwg+NuZ//+QvxSgbPZglr9af62jGKuh0omp2DWSK6BCapuSaC+c99w w5bbgnzbbajNUakLUDC2A+hgd0yn4XKOducp0TpSbadw6zprvA1UoXzUUfot/R5g8Fpmg1slrGY5 0ohB6u5EJ1wEI60yT3e1uz5KKSdJKh3pYr/WVHyfBGOvuyqRAFVkSElHh7QCuFCxxYrMQTXeOxzP YuO6u7KF69EYsKe6tlgf+cKntwtBoiQJa1nCMAYslB0DZxVDruxcKCX12yvwGoTlNgtbdADuh+WZ +SDBqdkUFoMxx6zkFJ64E4tI/UbPW+YWfOojZA==
Проблема заключается в том, что тот же самый алгоритм реализованный на PHP
$data = file_get_contents('./company.p12'); $certPassword = 'UiO389jh'; openssl_pkcs12_read($data, $certs, $certPassword); $pkey = openssl_pkey_get_private( $certs['pkey'] ); function signJsonString( $private_key = '', $jsonString = '' ) { $result = ''; if ( is_string( $jsonString ) && trim( strval( $jsonString ) ) != '' ) { $binarySignature = ''; if ( openssl_sign( $jsonString, $binarySignature, $private_key, 'sha256WithRSAEncryption' ) ) { $result = base64_encode( $binarySignature ); } } return $result; } $jsonString = '{"signupid":"2150bf6609de47a9b0233a3a458cbfbc"}'; $signature = signJsonString($pkey, $jsonString); echo $signature;
дает совершенно другую подпись в формате base64.
wnq0zhTm3cu2zwUQR9fbyxXP8Bj07W5rHbQ22iWhcyGNWURoz1tPosw5Rdg6i/1zGI9G++8F3Lt+ XlkXtsjzNoIRyaReZ8FUhQO4CPu1eT5B4z5sEYlGbdqr81+RX2tny9K1PcS3OpMXdg80GDvBZzY9 ktldh4a66tEqoAa5sMWc91fDdmm3MTSVm0L8l5WD2mXCsBLKVLkA/ejt+HD0f5v6t1W9rbmOJBD8 hAs5pTrpRNte1fuOhgpwLUgFXzvyoPKVBdB6GQs5v1eRfkEj/hWk3/CdifPZvr1VMAOS+M4XaXGm b4n6RtknHprSpU78gF/ZAkOSvtF7j8LUIE5M6A==
Естественно алгоритмы подписи одни и теже и в Java и в PHP, .pfx-файл тоже один и тот же, сама подписываемая строка тоже абсолютно идентична в обоих случаях.
Бьюсь уже несколько месяцев. Перечитал тонны советов и подсказок. Затер stackoverflow уже до дыр, но так и не нашел конца ниточки за которую бы стоило потянуть. Во всех похожих случаях пишут уверенно только одно - подпись на PHP верна. Искать нужно в Java. Чувствую, что ларчик открывается просто, но собственных познаний в Java пока не хватает. Буду рад любой помощи и подсказке. Готов предоставить желающим помочь все необходимые файлы.
P.S Знакомый Java-программист написал на "чистой" Java пример (https://bitbucket.org/andryha/signtext/src/master/) и у него там подпись сошлась c PHP. Но на Android этого не происходит.