Java - Python 間のRSA暗号→複合

今回は OpenSSL で作成する RSA鍵です。
RSA鍵作成
PEM形式の秘密鍵を生成する → private_key.pem

openssl genrsa -out private_key.pem 1024

パスワード付きの秘密鍵にするなら、

openssl genrsa -aes256 2048 > private_key.pem

で、入力求められるのでパスフレーズを入れます
PKC8/DER形式に変換する → private_key.pk8
Java で複合する場合の秘密鍵です

openssl pkcs8 -in private_key.pem -topk8 -nocrypt -outform DER -out private_key.pk8

DER形式の公開鍵を生成する → public_key.der

openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der

Java で暗号化

String str = "サンプル1234_ABCD";
try{
	KeyFactory keyfactory = KeyFactory.getInstance("RSA");
	// 秘密鍵
	KeySpec keyspec = new PKCS8EncodedKeySpec(readFile("private_key.pk8"));
	Key secret_key = keyfactory.generatePrivate(keyspec);
	// 公開鍵
	keyspec = new X509EncodedKeySpec(readFile("public_key.der"));
	Key public_key = keyfactory.generatePublic(keyspec);

	String encryptString = Base64.getEncoder()
		.encodeToString(encrypt(str, public_key));

	System.out.println(encryptString);

	String str = new String(
		decrypt(Base64.getDecoder()
			.decode(encryptString), secret_key)
	);
	System.out.println(str);

	// 暗号化文字列 Base64 ファイル出力 
	try(FileWriter fw=new FileWriter("encrypt.txt", StandardCharsets.UTF_8)){
		fw.write(encryptString);
	}

}catch(NoSuchAlgorithmException e){
	e.printStackTrace();
}catch(IOException e){
	e.printStackTrace();
}catch(InvalidKeySpecException e){
	e.printStackTrace();
}catch(InvalidKeyException e){
	e.printStackTrace();
}catch(NoSuchPaddingException e){
	e.printStackTrace();
}catch(IllegalBlockSizeException e){
	e.printStackTrace();
}catch(BadPaddingException e){
	e.printStackTrace();
}
static byte[] readFile(String path) throws IOException{
	try(InputStream in = new FileInputStream(path)){
		byte[] data = new byte[in.available()];
		in.read(data);
		in.close();
		return data;
	}
}
/* 暗号化 */
static byte[] encrypt(String target, Key key)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
	, IllegalBlockSizeException, BadPaddingException
{
	Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
	cipher.init(Cipher.ENCRYPT_MODE, key);
	return cipher.doFinal(target.getBytes());
}
/* 複合化 */
static byte[] decrypt(byte[] data, Key key)
 throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
, IllegalBlockSizeException, BadPaddingException {
	Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
	cipher.init(Cipher.DECRYPT_MODE, key);
	return cipher.doFinal(data);
}

Python で複合
準備として、pycrypto は古いので
pycryptodome をインストールしておきます。
pip install pycryptodome

https://www.pycryptodome.org/en/latest/

秘密鍵 PEM ファイル使用して複合する場合
 -----BEGIN RSA PRIVATE KEY-----

 -----END RSA PRIVATE KEY-----
の間を鍵として読込みます。

def rsa_decrypt(s):
    with open("private_key.pem") as f:
        from Crypto.PublicKey import RSA
        from Crypto.Cipher import PKCS1_v1_5
        from base64 import b64decode
        pemkey = b64decode(f.read().replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "").replace("\n", ""))
        rsakey = RSA.importKey(pemkey)
        cipher = PKCS1_v1_5.new(rsakey)
        text = cipher.decrypt(b64decode(s), "Error while decrypt")
    return text.decode('utf-8')

Javaで複合時と同じ秘密鍵 pk8 ファイルから複合する場合

def rsa_decrypt(s):
    with open("private_key.pk8", "rb") as f:
        from Crypto.PublicKey import RSA
        from Crypto.Cipher import PKCS1_v1_5
        from base64 import b64decode
        rsakey = RSA.importKey(f.read())
        cipher = PKCS1_v1_5.new(rsakey)
        text = cipher.decrypt(b64decode(s), "Error while decrypt")
    return text.decode('utf-8')

暗号化されたテキストを読んで上の複合メソッドを呼び出します

with open("encrypt.txt", "r") as f:
    enctext = f.read()
    planetext = rsa_decrypt(enctext)

次に、、、
Pythonで暗号化
公開鍵で暗合化します。

def rsa_encrypt(s):
    with open("public_key.der", "rb") as f:
        from Crypto.PublicKey import RSA
        from Crypto.Cipher import PKCS1_v1_5
        from base64 import b64encode
        key = RSA.importKey(f.read())
        cipher = PKCS1_v1_5.new(key)
        return b64encode(cipher.encrypt(bytes(s, 'utf-8'))).decode('utf-8')

Java で複合化
秘密鍵で複合します、秘密鍵でメソッド呼び出し前に抱えるように作って
以下のようなメソッドにすれば簡単になります

public String decrpt(String encstring) throws Exception{
     Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
     cipher.init(Cipher.DECRYPT_MODE, secret_key);
    return new String(cipher.doFinal(Base64.getDecoder().decode(encstring)));
}