PHP(openssl)、Android / Java、JavaScript、およびGoでのRSA暗号化

RSAは公開鍵暗号化アルゴリズムです。 公開鍵暗号化は非常に便利です。 RSAでは、パブリックとプライベートの2つのキーを作成できます。 公開キーをどこかに配置して暗号化すると、秘密キーの所有者のみが復号化できます。



たとえば、PhPでクレジットカード情報を含む注文を受け付けるWebストアを作成できます。 PHPストアは、公開キーを使用してクレジットカード情報を暗号化します。 PCストア自体は、これらの暗号化されたデータを復号化できません。 良い解決策は、ハッカーが予期せずに(PCPで書かれた)Webストアに侵入し、カードが暗号化されることです。



しかし、サイト所有者はどのようにしてマップにアクセスできますか? 彼は暗号文、秘密鍵を取り、それを解読する必要があります。 秘密鍵が電話に保存され、電話が管理パネルからQRコードを介して暗号文を取得できることが想像できます。 しかし、異なる言語では、暗号化の実装はわずかに異なります。私の記事は、あるプログラミング言語でテキストを暗号化し、別の言語で復号化する方法に関するものです。



違いは何ですか?

-キーの保存方法。

-暗号文の保存方法:バイナリ形式またはbase64エンコード;

-パディング。



まず、キーが必要です。 opensslを使用して作成することをお勧めします



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







画面スペースを節約するために、512ビットを選択しました。1024または2048ビットを使用することをお勧めします。 たとえば、SSL gitgub.comは2048を使用します。



また、キーのサイズによって、暗号化できるデータの最大量が決まりますが、OPENSSL_PKCS1_PADDING(PCPではデフォルト)を使用するという事実を考慮して、キーのサイズから11バイトを差し引く必要があり、512ビットキーで53バイトを暗号化できます。 パディングが必要な理由がわからない場合、パディングを使用しないのは危険です。



これでprivate.pemとpublic.pemができました。 これらのキーはテキスト形式であり、例で使用すると非常に便利です。 各プログラムが1つのファイルで構成されているため、より視覚的になります。



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-----
      
      







phpから始めましょう



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



次のようなものが得られます(テキストを暗号化しようとするたびに、新しい一意の暗号文を受け取ります)。



 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



さあ



 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は常に同じ乱数を与えるため、結果は次のようになります。



 aOleRSXhBT1XR7Al9cxdmM/8KnM2CvQdnNqnvwtq1ivFJ1aITxJUCuTw8ZRB8mY+elhoiUmC4UjM mwyTKmjqQw==
      
      





Javascript暗号化



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.github.io/april14/html/encrypt.html



そして受け取った:



 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.github.io/april14/html/decrypt.html



AndroidはJavaではありません



Javaは非常に多く、気の利いたものではありません。



Androidにはandroid.util.Base64があり、Java 8にはjava.util.Base64があり、org.apache.commons.codec.binary.Base64もあります。



Javaは、PEM形式の証明書の読み取り方法、java.securityおよびjavax.cryptoの作成者向けに設定されたガイドがどのようなタスクと目標に暗いのかを知りませんが、明らかにディスクスペースを節約しませんでした。



Bouncy CastleにPEMParserがあります。 ただし、オンラインエディタでBouncy Castleを選択することはできません。Androidでは、どのBouncy Castleが使用されているかは明確ではありません。 したがって、 スポンジの城がありますが、それはすでに「補足番号の形で暗号化の実装の別の列になります。 パート742の5 —暗号化登録」、段落6および7に「いいえ、いいえ」と答えることはできません。



SNAP-R
(6)製品には、米国以外のソースまたはベンダーによって製造または提供された暗号化コンポーネントが組み込まれていますか? (不明な場合は説明してください。)



いや



(7)会社の暗号化製品に関して、それらのいずれかは米国外で製造されていますか? はいの場合、製造場所を提供します。 (暗号化製品の主要生産者でない場合は、「該当なし」を挿入します。)



いや




したがって、private.pemから、モジュール、プライベートおよびパブリックの出展者を削除できます。 (これは有効です。最初に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
      
      





Javaでは、次のようになります。



 // 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);
      
      





Java 8プログラム全体:



 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

(コンパイル、実行をクリック)

 ik1Dvev7AffP+mOgxkbnYmpZrN9nGCKEzwCA4qsADcSKZFDYC/32B4uzUNSH8D+yCjBbrE5HUDL6vs6W5idG6Q==
      
      







Androidプログラム
 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:テキストではなく、AESキーを暗号化できます。



すべての春と幸運。



All Articles