📜 ⬆️ ⬇️

RSA encryption in PHP (openssl), Android / Java, JavaScript and Go

RSA is a public key encryption algorithm. Public key encryption is a very useful thing. RSA allows you to create two keys: open and closed. Place the public key somewhere and encrypt it, and only the owner of the private key can decrypt it.

For example, we can make a web store on PCP, which will take orders with credit card data. A PCP store will encrypt credit card data with an open key. The php-shop itself will not be able to decrypt these encrypted data. A good solution, a hacker unexpectedly hacks into a web store (written in PCP), and the cards are encrypted.

But how will the site owner get access to the cards? He needs to take the ciphertext, the private key and decrypt it. You can imagine that the private key will be stored in the phone, and the phone can extract the ciphertext from the admin through the QR code. But in different languages, the implementation of cryptography is slightly different, and my article is just about how to encrypt text in one programming language, and decipher it in another language.

What are the differences?
- how keys are stored;
- how the ciphertext is stored: binary form or in base64 encoding;
- padding.
')
First of all, we need keys. I propose to create them using openssl

openssl genrsa -out private.pem 512 openssl rsa -in private.pem -out public.pem -outform PEM -pubout 


To save space on the screen I chose 512 bits, it is advisable to use 1024 or 2048 bits. For example, SSL gitgub.com uses 2048.

The key size also determines the maximum amount of data that you can encrypt, but given that we will use OPENSSL_PKCS1_PADDING (by default in PCP), we must subtract 11 bytes from the key size and we can encrypt 53 bytes with the 512-bit key. Do not use padding at all is dangerous if you do not know why it is needed.

Now we have private.pem and public.pem. These keys are in text format, and they will be quite convenient to use in the examples. I want each program to consist of one file, so it will be clearer.

private.pem
 -----BEGIN RSA PRIVATE KEY----- MIIBPQIBAAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mqaH9/GnWjGavZM02fos4l c2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQJBAKn6O+tFFDt4MtBsNcDz GDsYDjQbCubNW+yvKbn4PJ0UZoEebwmvH1ouKaUuacJcsiQkKzTHleu4krYGUGO1 mEECIQD0dUhj71vb1rN1pmTOhQOGB9GN1mygcxaIFOWW8znLRwIhAMNqlfLijUs6 rY+h1pJa/3Fh1HTSOCCCCWA0NRFnMANhAiEAwddKGqxPO6goz26s2rHQlHQYr47K vgPkZu2jDCo7trsCIQC/PSfRsnSkEqCX18GtKPCjfSH10WSsK5YRWAY3KcyLAQIh AL70wdUu5jMm2ex5cZGkZLRB50yE6rBiHCd5W1WdTFoe -----END RSA PRIVATE KEY----- 


public.pem
 -----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mq aH9/GnWjGavZM02fos4lc2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQ== -----END PUBLIC KEY----- 


Let's start with PCP


encode.php

 <?php $pub = <<<SOMEDATA777 -----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mq aH9/GnWjGavZM02fos4lc2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQ== -----END PUBLIC KEY----- SOMEDATA777; $data = "PHP is my secret love."; $pk = openssl_get_publickey($pub); openssl_public_encrypt($data, $encrypted, $pk); echo chunk_split(base64_encode($encrypted)); ?> 

goo.gl/Xb7ayw

We get something of a type (you will receive a new unique ciphertext with each attempt to encrypt the text):

 JutBa0GLHzGrlygxwWr66cizw4W4za+DbzZweNM0iloCD7xEP9LclL013lcksJL5XhjW44U+oxpq cX1ZSLhWuA== 

decode.php

 <?php $key = <<<SOMEDATA777 -----BEGIN RSA PRIVATE KEY----- MIIBPQIBAAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mqaH9/GnWjGavZM02fos4l c2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQJBAKn6O+tFFDt4MtBsNcDz GDsYDjQbCubNW+yvKbn4PJ0UZoEebwmvH1ouKaUuacJcsiQkKzTHleu4krYGUGO1 mEECIQD0dUhj71vb1rN1pmTOhQOGB9GN1mygcxaIFOWW8znLRwIhAMNqlfLijUs6 rY+h1pJa/3Fh1HTSOCCCCWA0NRFnMANhAiEAwddKGqxPO6goz26s2rHQlHQYr47K vgPkZu2jDCo7trsCIQC/PSfRsnSkEqCX18GtKPCjfSH10WSsK5YRWAY3KcyLAQIh AL70wdUu5jMm2ex5cZGkZLRB50yE6rBiHCd5W1WdTFoe -----END RSA PRIVATE KEY----- SOMEDATA777; $data = "JutBa0GLHzGrlygxwWr66cizw4W4za+DbzZweNM0iloCD7xEP9LclL013lcksJL5XhjW44U+oxpq cX1ZSLhWuA=="; $pk = openssl_get_privatekey($key); openssl_private_decrypt(base64_decode($data), $out, $pk); echo $out; ?> 

goo.gl/0CWTQ9

Now on go


 package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "strings" ) func main() { b64 := `JutBa0GLHzGrlygxwWr66cizw4W4za+DbzZweNM0iloCD7xEP9LclL013lcksJL5XhjW44U+oxpq cX1ZSLhWuA== ` b1, err := Base64Dec(b64) if err != nil { panic(err) } b2, err := RsaDecrypt(b1, privateKey) fmt.Println(string(b2), err) b1, err = RsaEncrypt([]byte("Go the best language"), publicKey) if err != nil { panic(err) } s1 := Base64Enc(b1) fmt.Println(s1) b1, err = Base64Dec(s1) b2, err = RsaDecrypt(b1, privateKey) fmt.Println(string(b2), err) } func Base64Enc(b1 []byte) string { s1 := base64.StdEncoding.EncodeToString(b1) s2 := "" var LEN int = 76 for len(s1) > 76 { s2 = s2 + s1[:LEN] + "\n" s1 = s1[LEN:] } s2 = s2 + s1 return s2 } func Base64Dec(s1 string) ([]byte, error) { s1 = strings.Replace(s1, "\n", "", -1) s1 = strings.Replace(s1, "\r", "", -1) s1 = strings.Replace(s1, " ", "", -1) return base64.StdEncoding.DecodeString(s1) } func RsaDecrypt(ciphertext []byte, key []byte) ([]byte, error) { block, _ := pem.Decode(key) if block == nil { return nil, errors.New("private key error!") } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) } func RsaEncrypt(origData []byte, key []byte) ([]byte, error) { block, _ := pem.Decode(key) if block == nil { return nil, errors.New("public key error") } pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } pub := pubInterface.(*rsa.PublicKey) return rsa.EncryptPKCS1v15(rand.Reader, pub, origData) } var publicKey = []byte(` -----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mq aH9/GnWjGavZM02fos4lc2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQ== -----END PUBLIC KEY----- `) var privateKey = []byte(` -----BEGIN RSA PRIVATE KEY----- MIIBPQIBAAJBALqbHeRLCyOdykC5SDLqI49ArYGYG1mqaH9/GnWjGavZM02fos4l c2w6tCchcUBNtJvGqKwhC5JEnx3RYoSX2ucCAwEAAQJBAKn6O+tFFDt4MtBsNcDz GDsYDjQbCubNW+yvKbn4PJ0UZoEebwmvH1ouKaUuacJcsiQkKzTHleu4krYGUGO1 mEECIQD0dUhj71vb1rN1pmTOhQOGB9GN1mygcxaIFOWW8znLRwIhAMNqlfLijUs6 rY+h1pJa/3Fh1HTSOCCCCWA0NRFnMANhAiEAwddKGqxPO6goz26s2rHQlHQYr47K vgPkZu2jDCo7trsCIQC/PSfRsnSkEqCX18GtKPCjfSH10WSsK5YRWAY3KcyLAQIh AL70wdUu5jMm2ex5cZGkZLRB50yE6rBiHCd5W1WdTFoe -----END RSA PRIVATE KEY----- `) 

play.golang.org/p/nsyAw5kYDt

Go Playground always give the same random numbers and therefore the result:

 aOleRSXhBT1XR7Al9cxdmM/8KnM2CvQdnNqnvwtq1ivFJ1aITxJUCuTw8ZRB8mY+elhoiUmC4UjM mwyTKmjqQw== 

Javascript encryption


I will encrypt using jsEncrypt :

 $(function () { $('#but').click(function(){ var pub = $('#pub').val(); var crypt = new JSEncrypt(); crypt.setPublicKey(pub); var data = $('#data').val(); $('#out').val(crypt.encrypt(data)); }); }); 

cossackpyra.imtqy.com/april14/html/encrypt.html

And received:

 C2uWXwp6OsxLKnr3cXpJIf/RcPzgjlxNXj8IX2R47binEo2dLFhJISDnOioQaM8kAl/lqSSOCLdrYP12Tc/YXQ== 

 $(function () { $('#but').click(function(){ var key = $('#key').val(); var crypt = new JSEncrypt(); crypt.setPrivateKey(key); var data = $('#data').val(); $('#out').val(crypt.decrypt(data)); }); }); 

cossackpyra.imtqy.com/april14/html/decrypt.html

Android is not Java


Java is so much and there is no fig.

Android has android.util.Base64, and Java 8 is java.util.Base64, and there is also org.apache.commons.codec.binary.Base64.

Java does not know how to read certificates in the PEM format, which tasks and goals were set by the creators of java.security and javax.crypto - this is dark, but it’s not to save space on the disk.

In Bouncy Castle there is a PEMParser . But Bouncy Castle cannot be picked up by the online editor, and in Android it is not clear what Bouncy Castle is used. Therefore, there is Spongy Castle , but this will be another graph in the implementation of cryptography in the form of “Supplement No. 5 to Part 742 — Encryption Registration ”on items 6 and 7 you can’t say no, no.

SNAP-R
(6) What do you think about the products? (If unsure, please explain.)

No.

(7) United States? If yes, provide manufacturing locations. (Insert “not applicable”, if you are a provider of encryption products.)

No.


Therefore, from private.pem you can remove the module, private and public exhibitors. (This is valid, I initially created the keys using openssl.)

 openssl rsa -in private.pem -text -noout Private-Key: (512 bit) modulus: 00:ba:9b:1d:e4:4b:0b:23:9d:ca:40:b9:48:32:ea: 23:8f:40:ad:81:98:1b:59:aa:68:7f:7f:1a:75:a3: 19:ab:d9:33:4d:9f:a2:ce:25:73:6c:3a:b4:27:21: 71:40:4d:b4:9b:c6:a8:ac:21:0b:92:44:9f:1d:d1: 62:84:97:da:e7 publicExponent: 65537 (0x10001) privateExponent: 00:a9:fa:3b:eb:45:14:3b:78:32:d0:6c:35:c0:f3: 18:3b:18:0e:34:1b:0a:e6:cd:5b:ec:af:29:b9:f8: 3c:9d:14:66:81:1e:6f:09:af:1f:5a:2e:29:a5:2e: 69:c2:5c:b2:24:24:2b:34:c7:95:eb:b8:92:b6:06: 50:63:b5:98:41 prime1: 00:f4:75:48:63:ef:5b:db:d6:b3:75:a6:64:ce:85: 03:86:07:d1:8d:d6:6c:a0:73:16:88:14:e5:96:f3: 39:cb:47 prime2: 00:c3:6a:95:f2:e2:8d:4b:3a:ad:8f:a1:d6:92:5a: ff:71:61:d4:74:d2:38:20:82:09:60:34:35:11:67: 30:03:61 exponent1: 00:c1:d7:4a:1a:ac:4f:3b:a8:28:cf:6e:ac:da:b1: d0:94:74:18:af:8e:ca:be:03:e4:66:ed:a3:0c:2a: 3b:b6:bb exponent2: 00:bf:3d:27:d1:b2:74:a4:12:a0:97:d7:c1:ad:28: f0:a3:7d:21:f5:d1:64:ac:2b:96:11:58:06:37:29: cc:8b:01 coefficient: 00:be:f4:c1:d5:2e:e6:33:26:d9:ec:79:71:91:a4: 64:b4:41:e7:4c:84:ea:b0:62:1c:27:79:5b:55:9d: 4c:5a:1e 

In Java, it will look like this:

 // Private key BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger exp = new BigInteger( "00a9fa3beb45143b7832d06c35c0f3183b180e341b0ae6cd5becaf29b9f83c9d1466811e6f09af1f5a2e29a52e69c25cb224242b34c795ebb892b6065063b59841", 16); //Public Key BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger pubExp = new BigInteger("010001", 16); 

The entire Java 8 program:

 import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import java.util.Base64; //import javax.xml.bind.DatatypeConverter; public class HelloWorld { public static void main(String[] args) throws Exception { try { byte[] b1 = decrypt("JutBa0GLHzGrlygxwWr66cizw4W4za+DbzZweNM0iloCD7xEP9LclL013lcksJL5XhjW44\nU+oxpqcX1ZSLhWuA=="); String s1 = new String(b1, "UTF-8"); System.out.println(s1); byte[] b2 = encrypt("Java kills".getBytes("UTF-8")); String s2 = Base64.getEncoder().encodeToString(b2); System.out.println(s2); byte[] b3 = decrypt(s2); String s3 = new String(b3, "UTF-8"); System.out.println(s3); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static byte[] decrypt(String key) throws Exception { BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger exp = new BigInteger( "00a9fa3beb45143b7832d06c35c0f3183b180e341b0ae6cd5becaf29b9f83c9d1466811e6f09af1f5a2e29a52e69c25cb224242b34c795ebb892b6065063b59841", 16); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exp); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey privKey = kf.generatePrivate(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privKey); byte[] decodedStr = Base64.getDecoder().decode( key.replace("\n", "").replace("\r", "").replace(" ", "")); byte[] plainText = cipher.doFinal(decodedStr); return plainText; } private static byte[] encrypt(byte[] b1) throws Exception { BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger pubExp = new BigInteger("010001", 16); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, pubExp); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey publicKey = kf.generatePublic(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // byte[] decodedStr = Base64.decode(key, Base64.DEFAULT); byte[] plainText = cipher.doFinal(b1); return plainText; } } 


goo.gl/t27IWw
(You must click Compile, Execute)
 ik1Dvev7AffP+mOgxkbnYmpZrN9nGCKEzwCA4qsADcSKZFDYC/32B4uzUNSH8D+yCjBbrE5HUDL6vs6W5idG6Q== 


Android program
 import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import javax.crypto.Cipher; import android.util.Base64; import android.util.Log; public class TestX { public static byte[] decrypt(String key) throws Exception { BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger exp = new BigInteger( "00a9fa3beb45143b7832d06c35c0f3183b180e341b0ae6cd5becaf29b9f83c9d1466811e6f09af1f5a2e29a52e69c25cb224242b34c795ebb892b6065063b59841", 16); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exp); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey privKey = kf.generatePrivate(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privKey); byte[] decodedStr = Base64.decode(key, Base64.DEFAULT); byte[] plainText = cipher.doFinal(decodedStr); return plainText; } public static void test() { try { byte[] b1 = decrypt("JutBa0GLHzGrlygxwWr66cizw4W4za+DbzZweNM0iloCD7xEP9LclL013lcksJL5XhjW44U+oxpq\ncX1ZSLhWuA=="); String s1 = new String(b1, "UTF-8"); Log.i("TEST", s1); byte[] b2 = encrypt("Java kills".getBytes("UTF-8")); String s2 = Base64.encodeToString(b2, Base64.CRLF); Log.i("TEST", s2); byte[] b3 = decrypt(s2); String s3 = new String(b3, "UTF-8"); Log.i("TEST", s3); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } private static byte[] encrypt(byte[] b1) throws Exception { BigInteger modulus = new BigInteger( "BA9B1DE44B0B239DCA40B94832EA238F40AD81981B59AA687F7F1A75A319ABD9334D9FA2CE25736C3AB4272171404DB49BC6A8AC210B92449F1DD1628497DAE7", 16); BigInteger pubExp = new BigInteger("010001", 16); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, pubExp); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey publicKey = kf.generatePublic(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] plainText = cipher.doFinal(b1); return plainText; } } 


KO: you can encrypt not the text, but the AES key.

All spring and good luck.

Source: https://habr.com/ru/post/255799/


All Articles