Mar 15, 2009

[Tiger] RSA 暗号の鍵を DB に格納する方法

RSA 暗号の公開鍵を DB に格納しようと苦心惨憺したときのメモ。 以下のサイトが非常に参考になった。多謝。

Java Cryptgraphy
http://tokyo.cool.ne.jp/hharuki/java/81crypt.html
@//メモ - JavaSE RSA暗号
http://hondou.homedns.org/pukiwiki/index.php?cmd=read&page=JavaSE%20RSA%B0%C5%B9%E6

コード

ここではテストのためファイルから公開鍵、秘密鍵を取得している。

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.mail.internet.MimeUtility;

...

public void test() throws Exception {

  String data = "hogehogehogehoge";

  // 公開鍵の読み込み
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  InputStream is = null;
  try {
    is = new FileInputStream(new File("./mykey.x509"));
    int ch = 0;
    while ((ch = is.read()) >= 0) {
      baos.write(ch);
    }
  } finally {
    if(is != null) {
      is.close();
    }
  }
  // 暗号化。
  byte[] encrypted = this.encrypt(data.getBytes(), baos.toByteArray());
  System.out.println("" + new String(encrypted));

  // 秘密鍵の読み込み
  baos = new ByteArrayOutputStream();
  try {
    is = new FileInputStream(new File("./mykey.pkcs8"));
    ch = 0;
    while ((ch = is.read()) >= 0) {
      baos.write(ch);
    }
  } finally {
    if(is != null) {
      is.close();
    }
  }
  // 復号化。
  byte[] decrypted = this.decrypt(encrypted, baos.toByteArray());
  System.out.println("" + new String(decrypted));
}

public byte[] encrypt(final byte[] text, final byte[] publicKey)
        throws Exception {
  PublicKey key = KeyFactory.getInstance("RSA").generatePublic(
         new X509EncodedKeySpec(this.decodeBase64(publicKey)));

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

  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  CipherOutputStream cos = new CipherOutputStream(baos, cipher);
  cos.write(text);
  cos.close();

  return baos.toByteArray();
}

public byte[] decrypt(final byte[] text, final byte[] privateKey)
        throws Exception {
  PrivateKey key = KeyFactory.getInstance("RSA").generatePrivate(
         new PKCS8EncodedKeySpec(this.decodeBase64(privateKey)));

  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, key);
  CipherOutputStream cos = new CipherOutputStream(baos, cipher);
  cos.write(text);
  cos.close();

  return baos.toByteArray();
}

protected byte[] decodeBase64(final byte[] text) throws MessagingException,
        IOException {
  InputStream is = MimeUtility.decode(new ByteArrayInputStream(text), "base64");

  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  int ch = 0;
  while ((ch = is.read()) >= 0) {
    baos.write(ch);
  }
  return baos.toByteArray();
}

鍵の作成

下記で作成した mykey.x509, mykey.pkcs8 がそれぞれ公開鍵、秘密鍵になる。

$ openssl genrsa -des 1024 > ./mykey.pem
Generating RSA private key, 1024 bit long modulus
...............++++++
............++++++
e is 65537 (0x10001)
Enter pass phrase:
Verifying - Enter pass phrase:
$ openssl pkcs8 -topk8 -in ./mykey.pem -out ./mykey.pkcs8 -nocrypt
Enter pass phrase for ./mykey.pem:
$ openssl rsa -in ./mykey.pem -pubout -out ./mykey.x509
Enter pass phrase for ./mykey.pem:
writing RSA key
$ cp ./mykey.pkcs8 ./mykey.pkcs8.original
$ vi ./mykey.pkcs8
$ diff ./mykey.pkcs8.original ./mykey.pkcs8
1d0
< -----BEGIN PRIVATE KEY-----
16d14
< -----END PRIVATE KEY-----
$ cp ./mykey.x509 ./mykey.x509.original
$ vi ./mykey.x509
$ diff ./mykey.x509.original ./mykey.x509
1d0
< -----BEGIN PUBLIC KEY-----
6d4
< -----END PUBLIC KEY-----
$