RSA 暗号のコード

privateKey.getEncoded().length > publicKey.getEncoded().length になるのは何でだろう.公開鍵の方が長いと思っていたのに.

rsa.java

// package packagename;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 * 公開鍵暗号の一種RSA暗号をJavaで実装
 * http://lab.moyo.biz/recipes/java/security/publickey.xsp
 * -キーペア生成
 * -個人鍵での復号
 * -公開鍵での暗号化
 * -鍵のファイル入出力機能
 * @author Guernsey
 */
public class Rsa {

	private static final String CRYPT_ALGORITHM = "RSA";

	public static void main(String[] args) {
		// キーペア生成
		KeyPair keyPair = genKeyPair();

		// 個人鍵と公開鍵を取得
		PrivateKey privateKey = keyPair.getPrivate();
		PublicKey publicKey = keyPair.getPublic();

		// 使用するキーペア
		System.out.println("個人鍵");
		System.out.println(byte2String(privateKey.getEncoded()));
		System.out.println("公開鍵");
		System.out.println(byte2String(publicKey.getEncoded()));

		// 暗号化したいデータをバイト列で用意
		String string = "暗号化したい.abcabc123123!!";
		byte[] src = string.getBytes();
		System.out.println("暗号化するデータ(String)");
		System.out.println(string);
		System.out.println("暗号化するデータ(byte)");
		System.out.println(byte2String(src));

		// 暗号化
		byte[] enc = encrypt(src, publicKey);
		System.out.println("暗号化後データ");
		System.out.println(byte2String(enc));

		// 復号
		byte[] dec = decrypt(enc, privateKey);
		System.out.println("復号後データ");
		System.out.println(byte2String(dec));

	}

    private static String byte2String(byte[] b){

        // ハッシュを16進数文字列に変換
        StringBuffer sb= new StringBuffer();
        int cnt= b.length;
        for(int i= 0; i< cnt; i++){
            sb.append(Integer.toHexString( (b[i]>> 4) & 0x0F ) );
            sb.append(Integer.toHexString( b[i] & 0x0F ) );
        }
        return sb.toString();
    }

	/**
	 * バイナリを公開鍵で復号
	 * @param source 復号したいバイト列
	 * @param privateKey
	 * @return 復号したバイト列.失敗時は null
	 */
	public static byte[] decrypt(byte[] source, PrivateKey privateKey){
		try {
			Cipher cipher = Cipher.getInstance(getCRYPT_ALGORITHM());
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			return cipher.doFinal(source);
		} catch (IllegalBlockSizeException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (BadPaddingException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (InvalidKeyException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchAlgorithmException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchPaddingException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}

		return null;
	}

	/**
	 * バイナリを秘密鍵で暗号化
	 * @param source 暗号化したいバイト列
	 * @param publicKey
	 * @return 暗号化したバイト列.失敗時は null
	 */
	public static byte[] encrypt(byte[] source, PublicKey publicKey){
		try {
			Cipher cipher = Cipher.getInstance(getCRYPT_ALGORITHM());
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			return cipher.doFinal(source);
		} catch (IllegalBlockSizeException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (BadPaddingException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (InvalidKeyException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchAlgorithmException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchPaddingException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;
	}

	/**
	 * 公開鍵暗号のキーペアを生成する.
	 * 公開鍵ビット長は 1024
	 * getPrivate(), getPublic() で秘密鍵,公開鍵を参照できる.
	 * @return キーペア.失敗時は null
	 */
	public static KeyPair genKeyPair(){
		KeyPairGenerator generator;
		try {
			generator = KeyPairGenerator.getInstance(getCRYPT_ALGORITHM());
			SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
			generator.initialize(1024, random);
			return generator.generateKeyPair();
		} catch (NoSuchAlgorithmException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}

		return null;
	}

	/**
	 * 個人鍵を外部ファイルから読み込む
	 * @param filename ファイル名
	 * @return 個人鍵.失敗時は null
	 */
	public static PrivateKey loadPrivateKey(String filename){
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(getCRYPT_ALGORITHM());
			byte[] b = loadBinary(filename);
			EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(b);
			return keyFactory.generatePrivate(keySpec);
		} catch (InvalidKeySpecException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchAlgorithmException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;
	}

	/**
	 * 公開鍵を外部ファイルから読み込む
	 * @param filename ファイル名
	 * @return 公開鍵.失敗時は null
	 */
	public static PublicKey loadPublicKey(String filename){
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(getCRYPT_ALGORITHM());
			byte[] b = loadBinary(filename);
			EncodedKeySpec keySpec = new X509EncodedKeySpec(b);
			return keyFactory.generatePublic(keySpec);
		} catch (InvalidKeySpecException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (NoSuchAlgorithmException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;
	}

	/**
	 * バイナリを外部ファイルから入力する
	 * @param filename ファイル名
	 * @return 読み込んだバイト配列.失敗時は null
	 */
	private static byte[] loadBinary(String filename){
		try {
			FileInputStream in = new FileInputStream(filename);
			byte[] b = null;
			in.read(b);
			return b;
		} catch (FileNotFoundException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (IOException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;

	}

	/**
	 * 個人鍵を外部ファイルに保存する
	 * @param privateKey
	 * @param filename ファイル名
	 */
	public static void savePrivateKey(PrivateKey privateKey, String filename){
		saveBinary(privateKey.getEncoded(), filename);
	}

	/**
	 * 公開鍵を外部ファイルに保存する
	 * @param publicKey
	 * @param filename ファイル名
	 */
	public static void savePublickkey(PublicKey publicKey, String filename)
	{
		saveBinary(publicKey.getEncoded(), filename);
	}
	/**
	 * バイナリを外部ファイルに保存する
	 * @param b 保存したいバイト配列
	 * @param filename ファイル名
	 */
	private static void saveBinary(byte[] b, String filename)
	{
		FileOutputStream out;
		try {
			out = new FileOutputStream(filename);
			out.write(b);
			out.close();
		} catch (FileNotFoundException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		} catch (IOException ex) {
			Logger.getLogger(Rsa.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * @return the CRYPT_ALGORITHM
	 */
	public static String getCRYPT_ALGORITHM() {
		return CRYPT_ALGORITHM;
	}
}

クラス実行例

run:
個人鍵
30820276020100300d06092a864886f70d0101010500048202603082025c020100028181008c0d21c5de7898e72f7e790e333d9139a69d68a9499531a42ebf0eb6845511b7f170744b2a30a3f189a3a5c8ac7e0cec4d00c73a24e09ce5843e91c82bdb2a6c64d25e625e9d94926ba889f717e3cb17f53dd69f2d1f1c71eced55f5ecb8c488025313ba064281e93028e1a3e672ff3bbf4828a6280430180e07db94b70aa66702030100010281804693fb981ed441a20802417951834e63723ed356b4b95609fa70d8364c9c1e50c780b76a85b97b7526baecba238b6671d320784629fd73b40aa0099189e06a10f33b7b61e99bc0c25ef1cb18d06f3ae191944c6a75b7f7ba2c831d68de925d785c70d827c5c18908b9265967152c1b728dcd6d17aa6440a2fcb735a42010e189024100da43db97ca75e9e9ac3db4618beeb1ad001c072cb5701c6c745fdd700c8f537e06b07a83c0b137e93299a508362a8195375382d4a69a510f574c85f72db943ad024100a443a1148097eacabb3ef24e373a7473299be46e7d76738d6afe54512ad9d80429973315afadf666a1815b96245b3e770f826732091f6f97baa5060bdea6b4e3024100a8e294c9b0d8e833ed1899b858e44b0ac7e8e80c4a20037e4fd5d5abdbac133892c87f23ef37b14179ebb4ecd3acb433d76980f4362d75c75f0f51215f79d8c902404c72e133ee89458fe6c76bf3f506328e2a6e5049100121d44e58619b890aebdb3c140f856746da67778101c405d5a563ba0721ca0aaee3bbc4f4eab4798232ab02405e76bc60582f9bf041302323bdab7ed9cef1b19f59dff49263ce77558122c5c404e8532389987d3aa12ab88d6a2492cee18ef8227b105c735fd86fe38d851390
公開鍵
30819f300d06092a864886f70d010101050003818d00308189028181008c0d21c5de7898e72f7e790e333d9139a69d68a9499531a42ebf0eb6845511b7f170744b2a30a3f189a3a5c8ac7e0cec4d00c73a24e09ce5843e91c82bdb2a6c64d25e625e9d94926ba889f717e3cb17f53dd69f2d1f1c71eced55f5ecb8c488025313ba064281e93028e1a3e672ff3bbf4828a6280430180e07db94b70aa6670203010001
暗号化するコード(String)
暗号化したい.abcabc123123!!
暗号化するコード(byte)
88c38d8689bb82b582bd82a281446162636162633132333132332121
暗号化後データ
521c0da61efce5f181896a6481edc85d1b96ea605ccff48cd7f23004a36454ac0824e5999c417bbbacd740cee33d50e64b6afb4f62b5067acbde8aefb36727f13dff81d220d7a83dc9c5f7c88468db6758bde6e6d258acf3e44b3bc6f499e81855a99d57f84b24e671c568e03fa2ce2dd5beb3b55907d8960e135307317ae49e
復号後データ
88c38d8689bb82b582bd82a281446162636162633132333132332121
構築成功 (合計時間: 2 秒)