Good day. I was busy connecting to a cyber payment, everything would be fine but it’s impossible for me to check the signature of the string that they send.

Input data:

  1. The string to which we have the signature String text = "action=check&number=00842&amount=10.54&type=1"

  2. Signature

     String sign = "C41545C19E86D0001F11D9D98EA6630EFAE4AB26AEC5933E05B5ADE7B6571B7B0FF5230F33B306D174290D3E6FAF1133A6FD1F0155A5D04294DE7DD0A20E3B037884121D399CEF9D91EC519AB56B67448E116EAF8629293E1F66A780E0028A2EC7C831D1F5ADF68B9703B576B30D80DA940187A23104A9304A74A9C86AD6E68B";` 
  3. Public key http://yadi.sk/d/u892DkgA3zh9a

So I load the public key

  PEMReader reader = new PEMReader(new FileReader(f)); Object obj; PublicKey pubKey = null; while ((obj = reader.readObject()) != null) { if (obj instanceof PublicKey) { pubKey = (PublicKey) obj; } } 

If after that I make Sytem.out.println(pubKey) , I get a module and a public exponent at the output. RSA key algorithm, X.509 format.

So I do the signature verification:

 try { byte [] data = text.getBytes(); byte [] subscript = subscriptText.getBytes(); Signature signature = Signature.getInstance("RSA","BC"); signature.initVerify(pubKey); signature.update(data); System.out.println(signature.verify(subscript) ? "Подписано верно!!!!!!!!!!!!!!!!!!": "Подписано не верно"); } catch (Exception e) { e.printStackTrace(); } 

But the result is always the same. He made his signature on this line (with his private key) and tried to verify the signature with his public key, but he also received a negative answer. Errors do not deduce what, just says not the correct signature.

Help verify the signature.

 **Update** техподдержка киберплата скинула код на perl в котором проверка проходит успешно. осталось только реализовать все на Java #!/usr/bin/perl use strict; use Crypt::OpenSSL::RSA; my $cyberplat_message='action=check&number=00842&amount=10.54&type=1&sign=C41545C19E86D0001F11D9D98EA6630EFAE4AB26AEC5933E05B5ADE7B6571B7B0FF5230F33B306D174290D3E6FAF1133A6FD1F0155A5D04294DE7DD0A20E3B037884121D399CEF9D91EC519AB56B67448E116EAF8629293E1F66A780E0028A2EC7C831D1F5ADF68B9703B576B30D80DA940187A23104A9304A74A9C86AD6E68B'; my $message=$cyberplat_message; my $signature_hex=$cyberplat_message; undef $cyberplat_message; $message=~s/\&sign.*?$//; $signature_hex=~s/^.*?\&sign\=(.*?)$/$1/sg; my $signature_bin=pack("H*",$signature_hex); my $pub_key_string=`cat CyberPlat_RU_pub.pem`; my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($pub_key_string); if (!$rsa_pub->verify($message, $signature_bin)) { print "Error"; } else { print "Succes"; } & number = **Update** техподдержка киберплата скинула код на perl в котором проверка проходит успешно. осталось только реализовать все на Java #!/usr/bin/perl use strict; use Crypt::OpenSSL::RSA; my $cyberplat_message='action=check&number=00842&amount=10.54&type=1&sign=C41545C19E86D0001F11D9D98EA6630EFAE4AB26AEC5933E05B5ADE7B6571B7B0FF5230F33B306D174290D3E6FAF1133A6FD1F0155A5D04294DE7DD0A20E3B037884121D399CEF9D91EC519AB56B67448E116EAF8629293E1F66A780E0028A2EC7C831D1F5ADF68B9703B576B30D80DA940187A23104A9304A74A9C86AD6E68B'; my $message=$cyberplat_message; my $signature_hex=$cyberplat_message; undef $cyberplat_message; $message=~s/\&sign.*?$//; $signature_hex=~s/^.*?\&sign\=(.*?)$/$1/sg; my $signature_bin=pack("H*",$signature_hex); my $pub_key_string=`cat CyberPlat_RU_pub.pem`; my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($pub_key_string); if (!$rsa_pub->verify($message, $signature_bin)) { print "Error"; } else { print "Succes"; } 

    3 answers 3

    I’m confused by the innocent text.getBytes() in all this history - as you know, the current system encoding is used to translate into bytes. Allah only knows what the current encoding is with you and the sender ...

    Here it is necessary to clearly understand what the encoding of the source line should be - I would not rely on Allah and explicitly prescribe the expected encoding.

     text.getBytes("UTF-8"); //например... 

    Update

    The signature must be recoded into bytes from HEX like this:

     public static byte[] hexToBytes(String hexString) { static final String HEX="0123456789ABCDEF"; byte[] out=new byte[hexString.length() / 2]; int n=hexString.length(); for(int i=0; i < n; i+=2) { //make a bit representation in an int of the hex value int hn=HEX.indexOf(hexString.charAt(i)); int ln=HEX.indexOf(hexString.charAt(i + 1)); if(hn < 0 || ln < 0) return null; //now just shift the high order nibble and add them together out[i / 2]=(byte) ((hn << 4) | ln); } return out; } 
    • I put the encodings and UTF-8 and windows-1251 - I did this at the very beginning, now I just despaired. Found a brief mention that the signature needs to be decoded Base64.decod, but again the result is negative - G1yyK
    • @ G1yyK Yes, this is not a fig not Base64 - but the usual HEX! - Barmaley
    • byte [] subscript = convertHexToString (subscriptText) .getBytes (); public static String convertHexToString (String hex) {StringBuilder sb = new StringBuilder (); StringBuilder temp = new StringBuilder (); for (int i = 0; i <hex.length () - 1; i + = 2) {String output = hex.substring (i, (i + 2)); int decimal = Integer.parseInt (output, 16); sb.append ((char) decimal); temp.append (decimal); } return sb.toString (); } After the envelope, the result remained negative - G1yyK
    • @ G1yyK no need wrong! Hex should be immediately in bytes, and not through a string! See Answer Update - Barmaley
    • Pancake. Does not work. And I do not even know where to dig. There is no way to know where the error is, where I messed up - G1yyK
     Signature signature = Signature.getInstance("SHA1WithRSAEncryption"); 

    It should help, I have a similar code that you initially gave works, but I’m doing so getting the signature object. And yet

     signature.verify(subscript) 

    change to

     signature.verify(Hex.decode(subscript)) 

      I, unfortunately, have not touched RSA for 5 years. I can advise you to study the example of the interaction between the bot and the server Lineage II. There, the 3rd and 4th client-login interaction packets use RSA. At one time I was looking for information about this protocol for a very long time, it is difficult.