実行環境
MacOS 12.6
Python 3.10.6
PHP8.1
モジュールのインストール
Python側でrsaモジュールを使うのでインストールします
pip install rsa
PEMファイル(鍵)の準備
PEMファイルを生成します
生成したいディレクトリで実行してください
openssl genrsa 2048 > private_key.pem
openssl rsa -in private_key.pem -pubout -out public_key.pem
実行するとこんな感じのファイルができます
private_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA8DoEBfIPUiTOBEivztYvcXVhZONbnbP8rihRFyRkaxBd9QVR
DG66TFefuMpbhLDTjD...p6qeqxzh2kBiTIfQDSQNakN8/mARLaLPlFN5Ly2QlTa
7aXFjs/+P6L17kD9DH25mTbTgpHz0OxjLmK/4ovsgMgTzkQpJa0=
-----END RSA PRIVATE KEY-----
public_key.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8DoEBfIPUiTOBEivztYv
cXVhZONbnbP8rihR...u37fLCSFgQZm9CbT67R8hGbVshqfH0Jpye68Oy6LMEHHv
e9tcc+MdmMLNiq3DLPzF7IgGPjyB9C3BCJzrHQwO7PiVcg6VAxz7aA+7f01VFHfu
9wIDAQAB
-----END PUBLIC KEY-----
Pythonで暗号化→phpで復号化
値の受け渡し方は色々なやり方があると思うのでここでは省略します
Python(暗号化)
encryption.py
import base64
import rsa
text = "hello world!" # 暗号化する文字列
pub_key_path = "./public_key.pem" # 公開鍵のパス
text_bytes = bytes(text, encoding="utf-8")
with open(pub_key_path, "rb") as f:
public_key = rsa.PublicKey.load_pkcs1_openssl_pem(f.read())
cipher = rsa.encrypt(text_bytes, public_key)
cipher_encode = base64.b64encode(cipher)
cipher_str = cipher_encode.decode("utf-8")
print(cipher_str) # 暗号化された文字列
成功するとLDa0cxKYpkGKiKSGMkm+z...EvNh+nqnNRQ==
のように暗号化された文字が出力されます
PHP(復号化)
decoding.php
<?php
$cipher = '{Python側で出力された暗号化された文字列}';
$privateKeyPath = './private_key.pem'; // 秘密鍵のパス
$privateKey = file_get_contents($privateKeyPath);
$cipherDecode = base64_decode($cipher);
openssl_private_decrypt($cipherDecode, $decipher, $privateKey);
echo $decipher.PHP_EOL;
?>
成功すると暗号化前の文字列が出力されます
失敗すると何も出力されないので気をつけてください
PHPで暗号化→Pythonで復号化
PHP(暗号化)
encryption.php
<?php
$text = 'Hello World!'; // 暗号化する文字列
$pubKeyPath = './public_key.pem'; // 公開鍵のパス
$pubKey = file_get_contents($pubKeyPath);
openssl_public_encrypt($text, $cipher, $pubKey);
$cipherEncode = base64_encode($cipher);
echo $cipherEncode.PHP_EOL;
?>
成功すると上と同じくE8Wa8PncC/m1UdK...HSrpAnm9wmY40rAKY+dz2OA==
のように暗号化された文字が出力されます
Python(復号化)
decoding.py
import base64
import rsa
text = "{PHP側で出力された暗号化された文字列}"
private_key_path = "./private_key.pem" # 秘密鍵のパス
with open(private_key_path, "rb") as f:
private_key = rsa.PrivateKey._load_pkcs1_pem(f.read())
cipher_decode = base64.b64decode(text)
decipher = rsa.decrypt(cipher_decode, private_key)
decipher_str = decipher.decode("utf-8")
print(decipher_str)
成功すると暗号化前の文字列が出力されます
注意点
-
privateKey
は絶対に公開しないでください - クエリパラメータ等を使ってPythonからPHPへ値を受け渡すときは
+
や=
を空白やパラメータと見られることがあるので受け渡す時は、
encryption.py(11~13行目)
cipher = rsa.encrypt(text_bytes, public_key)
cipher_encode = base64.b64encode(cipher)
- cipher_str = cipher_encode.decode("utf-8")
+ cipher_str = cipher_encode.decode("utf-8").replace('+', '%2B').replace("=", "%3D")
のようにreplaceを使ってエンコードしてください
おまけ: postを使ってPythonからphpへ値を渡す
暗号化した値の渡し方の例です
urllib
モジュールを使います
encryption.py
import base64
import rsa
+ import urllib.request, urllib.parse
text = "hello world!" # 暗号化する文字列
pub_key_path = "./public_key.pem" # 公開鍵のパス
text_bytes = bytes(text, encoding="utf-8")
with open(pub_key_path, "rb") as f:
public_key = rsa.PublicKey.load_pkcs1_openssl_pem(f.read())
cipher = rsa.encrypt(text_bytes, public_key)
cipher_encode = base64.b64encode(cipher)
cipher_str = cipher_encode.decode("utf-8")
- print(cipher_str) # 暗号化された文字列
+ URL = "http://localhost/decoding.php" # 復号化するPHPのURL
+ data = {"cipher": cipher_str} # 暗号化した文字をphp側に送信
+ post_data = urllib.parse.urlencode(data).encode("utf-8")
+ with urllib.request.urlopen(URL, data=post_data) as re:
+ print(re.read().decode("utf-8")) # 復号化した文字列が返ってくる
decoding.php
<?php
+ if (!isset($_POST['cipher'])) {
+ echo 'No cipher';
+ exit;
+ }
- $cipher = '{Python側で出力された暗号化された文字列}';
+ $cipher = $_POST['cipher'];
$privateKeyPath = './private_key.pem'; // 秘密鍵のパス
$privateKey = file_get_contents($privateKeyPath);
$cipherDecode = base64_decode($cipher);
openssl_private_decrypt($cipherDecode, $decipher, $privateKey);
echo $decipher.PHP_EOL;
?>