Develop with pleasure!

福岡でCloudとかBlockchainとか。

JavaとRubyで暗号化/復号化

Rubyで暗号化したデータをJavaで復号化、またその逆を行ってみた。

今回はAES128ビットの暗号化モードCBC、パディングはPKCS#5で実施。
まずRuby側のコード。

require 'openssl'
require 'base64'
class CryptUtil

  def self.encrypt(pass, value)
    enc = OpenSSL::Cipher.new('aes-128-cbc')
    # 暗号化or復号化どちらを行うかセット(今回は暗号化)、復号化の場合はdecrypt
    enc.encrypt 
    # ivを生成
    iv = OpenSSL::Random.random_bytes(16) 
    # 暗号化する際のキー文字列をセット
    enc.key = pass
    # ivをセット
    enc.iv = iv
    crypted = ""
    crypted << enc.update(value) # 暗号化
    crypted << enc.final
    # 暗号化した文字列と暗号化に使用したivをBase64エンコードして返却
    return Base64.b64encode(crypted), Base64.b64encode(iv)
  end

  def self.decrypt(pass, encrypted, iv)
    dec = OpenSSL::Cipher.new('aes-128-cbc')
    # 暗号化する際のキー文字列をセット
    dec.key = pass
    # Base64エンコードされたivをデコードしてセット
    dec.iv = Base64.decode64(iv) unless iv.nil?
    dec.decrypt
    plain_text = ""
    plain_text << dec.update(Base64.decode64(encrypted))
    plain_text << dec.final
    return plain_text
  end

end


Cipherを使用する際にkey,ivメソッドで暗号化する際のキーとiv(初期ベクトル)を指定するようにしているのは、ivがわからないと復号化できないため。通常、暗号化する際はCipher#pkcs5_keyivgenを使用する。ただpkcs5_keyivgenは内部でivを生成するんだけど、そのivを取得する仕組みが無いため、今回は↑みたいにkey,ivメソッドでそれぞれキーとivを指定した。

続いてJava側の実装。

public class CryptUtil {
        /**
	 * 暗号化
         * @param src 暗号化対象の文字列
         * @param key 暗号化に使用する文字列(128bit)
         * @param iv 暗号化に使用する初期ベクトル(Base64エンコードされた値)
	 */
	public static String encrypt(String src, String key, String iv) {
		try {
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                        Key skey = new SecretKeySpec(key.getBytes(), "AES");
                        IvParameterSpec param = new IvParameterSpec(decodeBase64(iv));
			cipher.init(Cipher.ENCRYPT_MODE, skey, param);
			return encodeBase64(cipher.doFinal(src.getBytes()));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 復号化
         * @param src 復号化対象の文字列(Base64デコードされた状態)
         * @param key 暗号化の際に使用した文字列(128bit)
         * @param iv 暗号化で使用した初期ベクトル(Base64エンコードされた値)
	 */
	public static String decrypt(byte[] src, String key, String iv) {
		try {
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                        Key skey = new SecretKeySpec(key.getBytes(), "AES");
                        IvParameterSpec param = new IvParameterSpec(decodeBase64(iv));
			cipher.init(Cipher.DECRYPT_MODE, skey, param);
			return new String(cipher.doFinal(src));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

    private static byte[] decodeBase64(String value) throws Exception {
        return new BASE64Decoder().decodeBuffer(value);
    }

    private static String encodeBase64(byte[] value) throws Exception {
        return new BASE64Encoder().encodeBuffer(value);
    }
}


な感じ。↑でRubyで暗号化した文字列をJavaで復号化、Javaで暗号化した文字列をRubyで復号化が可能。