Javaで文字列の暗号化/複合化(※外部ライブラリを使わずに)

僕がいま係っているシステムで、別システムのログインパスワードを文字列でデータベースに格納することになりました。これを実現するために、Javaで文字列の暗号化/復合化を行う方法を調べたので、その結果を記しておきます。(※既に別の方々が解説している内容をまとめただけですが。)

まず、大きく以下の工程にわけて考えます。

  1. 文字列を暗号化する(バイト配列を得る)
  2. 暗号化されたバイト配列を文字列化する(暗号化文字列を得る)
  3. 暗号化された文字列をバイト配列化する(暗号化バイト配列を得る)
  4. バイト配列を復号化する(文字列を得る)

「1. 文字列を暗号化する(バイト配列を得る)」
Java Tips:手軽に暗号化・復号化するには? このページにばっちり解説してあるとおりです。

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public static byte[] encrypt(String key, String text)
    throws Exception {
		
    SecretKeySpec sksSpec = 
        new SecretKeySpec(key.getBytes(), "Blowfish");
		
    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, sksSpec);
		
    return cipher.doFinal(text.getBytes());
}

「4. バイト配列を復号化する(文字列を得る)」
工程2,3は飛ばして「4. バイト配列を復号化する(文字列を得る)」です。これも先ほどのページに解説してあるとおりです。

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public static String decrypt(String key, byte[] encrypted) 
    throws Exception {
		
    SecretKeySpec sksSpec = 
        new SecretKeySpec(key.getBytes(), "Blowfish");

    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, sksSpec);
		
    return new String(cipher.doFinal(encrypted)); 
}

「2. 暗号化されたバイト配列を文字列化する(暗号化文字列を得る)」
これが以外に悩みました。普通に new String(byte[]) とやると一部の情報が失われてしまいます。たぶん、文字コードとのマッピングの問題なんだと思います。では別のやり方を探してみたところ、、、Java/暗号化/Blowfish方式 このページで紹介されているやり方はその問題はクリアしているのですが、commonsライブラリを使っているのが僕にとってはちと障害でした。
で、なるべく外部ライブラリを使わずにバイト配列から文字列を作っている方法を調べてみたところ、、、やまろうのJavaなわけ このページがまさにぴったりの内容でしたので、さっそく参考にさせて頂きました。

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import javax.mail.internet.MimeUtility;

public static String encodeBase64(byte[] data) throws Exception {
  	
    ByteArrayOutputStream forEncode = new ByteArrayOutputStream();
  	
    OutputStream toBase64 = MimeUtility.encode(forEncode, "base64");
    toBase64.write(data);	
    toBase64.close();
  	
    return forEncode.toString("iso-8859-1");
}

「3. 暗号化された文字列をバイト配列化する(暗号化バイト配列を得る)」
これも先ほどのページに書いてあるとおりのやり方で解決しました。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.mail.internet.MimeUtility;

public static byte[] decodeBase64(String base64) throws Exception {

    InputStream fromBase64 = MimeUtility.decode(
        new ByteArrayInputStream(base64.getBytes()), "base64");

    byte[] buf = new byte[1024];
    ByteArrayOutputStream toByteArray = new ByteArrayOutputStream();
  	
    for (int len = -1;(len = fromBase64.read(buf)) != -1;) 
        toByteArray.write(buf, 0, len);
  	
    return toByteArray.toByteArray();
}

以上で完成です。例外処理をいれなければコードもかなりシンプルです。情報を提供してくださっている方々に感謝、感謝です。