Java+RSA公開鍵暗号化 -> Ruby+RSA秘密鍵復号

JavaからRSA公開鍵で暗号化したデータをRubyからRSA秘密鍵で復号するサンプル。

鍵の保存

require 'openssl'

OpenSSL::Random.seed(File.read("/dev/random", 16))
rsa = OpenSSL::PKey::RSA.generate(2048)

# 秘密鍵を保存
File.open("private_key.pem", "w") do |f|
  f.write(rsa.export)
end

# 公開鍵を保存
public_key = rsa.public_key
File.open("public_key.pem", "w") do |f|
  f.write(public_key.export)
end

Java+RSA公開鍵暗号

package com.example;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

public class RSAPublicKeyExample {
    public static void main(String[] args) throws Exception {
        RSAPublicKeyExample example = new RSAPublicKeyExample();

        String encrypted = example.encrypt("test");
        System.out.println(encrypted);
    }

    public String encrypt(String data) throws IOException,
            GeneralSecurityException {
        // ファイルから公開鍵を読み込む
        PublicKey key = readPublicKeyPem(this.getClass().getResourceAsStream("/public.pem"));

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        // 暗号化+Base64
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.encodeBase64String(encrypted);
    }

    private PublicKey readPublicKeyPem(InputStream stream) throws IOException,
            GeneralSecurityException {
        // PEMのヘッダとフッタを削除
        String pem = IOUtils.toString(stream)
                .replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
        byte[] decoded = Base64.decodeBase64(pem);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);

        return key;
    }
}

Ruby+RSA秘密鍵復号

require 'openssl'
require 'base64'

# ファイルから秘密鍵を読み込む
rsa = OpenSSL::PKey::RSA.new(open('private_key.pem'))

# 復号
puts rsa.private_decrypt(Base64.decode64('{Javaで暗号化+Base64した文字列}'))
# => test

参考