LoginSignup
2
7

More than 5 years have passed since last update.

RSAキーペアの作成・暗号化・復号化のサンプル(JAVA)

Last updated at Posted at 2017-06-16

タイトルどおり。
ストアに入れたり、ファイルで渡したり色々あると思うので
キーペアはいったんBase64エンコードをかましてます。

依存性(maven)
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.45</version>
</dependency>
RSAKeyPairSample.java
/**
 * RSAKeyPairの作成、暗号化、復号化のサンプル
 * @author ryutaro_hakozaki
 */
public class RSAKeyPairSample {

    public static void main(String argv[]){

        RSAKeyPairSample sample = new RSAKeyPairSample();

        /**
         * KeyPairの作成
         */
        String[] keyPair = sample.createKeyPairAsBase64();
        System.out.println("公開鍵 == " + keyPair[0]);
        System.out.println("秘密鍵 == " + keyPair[1]);

        /**
         * 秘密鍵で暗号化
         *  RSAなのでどっちで暗号化してもいい
         *  セキュア通信では公開鍵で暗号化するし
         *  電子署名では文書のハッシュを秘密鍵で暗号化する
         */
        final String message = "Qiitaは、プログラマのための技術情報共有サービスです。";
        byte[] encryptBytes = sample.encryptByBase64Key(message.getBytes(), keyPair[1]);
        System.out.println("----------------------------------------");
        System.out.println("【平文】");
        System.out.println(message);
        System.out.println("【暗号化結果】");
        System.out.println(new String(encryptBytes));

        /**
         * 公開鍵で復号化
         *  対になる鍵であれば復号が可能
         */
        byte[] decryptBytes = sample.decryptBtBase64Key(encryptBytes, keyPair[0]);
        System.out.println("【復号化結果】");
        System.out.println(new String(decryptBytes));

    }

    /**
     * RSAキーペアを作成する
     * @return Base64エンコードされた公開鍵と暗号鍵
     */
    public String[] createKeyPairAsBase64(){
        String[] keyPair = new String[2];

        /**
         * KeyPairを作成
         */
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        Cipher cipher;
        KeyPairGenerator generator;
        try {
            cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
            generator = KeyPairGenerator.getInstance("RSA", "BC");
        } catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException ex) {
            return keyPair;
        }
        SecureRandom random = new SecureRandom();
        generator.initialize(2048, random);
        KeyPair pair = generator.generateKeyPair();

        /**
         * KeyPairをBase64エンコードして返却
         */
        keyPair[0] = encodeObjectAsBase64(pair.getPublic());
        keyPair[1] = encodeObjectAsBase64(pair.getPrivate());

        return keyPair;        
    }

    /**
     * 暗号化を行う
     * @param data
     * @param base64Key
     * @return 暗号化されたデータ
     */
    public byte[] encryptByBase64Key(byte[] data, String base64Key){
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        try {
            Key myKey = (Key) decodeObjectFromBase64(base64Key);
            Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, myKey, new SecureRandom());
            return cipher.doFinal(data);
        } catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException  ex) {
            return null;
        }
    }

    /**
     * 復号化を行う
     * @param data
     * @param base64Key
     * @return 復号化されたデータ
     */
    private byte[] decryptBtBase64Key(byte[] data, String base64Key){
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        try {
            Key myKey = (Key) decodeObjectFromBase64(base64Key);
            Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, myKey, new SecureRandom());
            return cipher.doFinal(data);
        } catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException  ex) {
            return null;
        }
    }

    /**
     * ObjectをBase64エンコード
     * @param o
     * @return エンコード結果
     */    
    private static String encodeObjectAsBase64(Object o){
        // 状況に応じてだが、今回はバイトを圧縮して少しでも小さなサイズを返す
        try(ByteArrayOutputStream byteos = new ByteArrayOutputStream();
            GZIPOutputStream gos = new GZIPOutputStream(byteos);) {
            try(ObjectOutputStream objos = new ObjectOutputStream(gos)){
                objos.writeObject(o);
            }
            byte[] retObject = byteos.toByteArray();
            return Base64.getEncoder().encodeToString(retObject);
        } catch (IOException ex) {
            Logger.getLogger(RSAKeyPairSample.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Base64エンコードをObjectに変換
     * @param s
     * @return
     * @throws IOException 
     */
    private static Object decodeObjectFromBase64(String s) throws IOException{
       byte[] bytes = Base64.getDecoder().decode(s);
       try(GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes))) {
           return new ObjectInputStream(gis).readObject();
       } catch (ClassNotFoundException ex) {
           return null;
       }
    }

}
実行結果
公開鍵 == H4sIAAAAAAAAAFvzloG1uIhBN78oXS8pvzQvuTI5sbgkJ1UvKzlVr6AovywzJbVI(省略)
秘密鍵 == H4sIAAAAAAAAAJVVe1QTdxae8AiRhzwiUApUEamAJRBQtx608lBsIArIY4GAOEmGZGJeTiaQAA(省略)
----------------------------------------
【平文】
Qiitaは、プログラマのための技術情報共有サービスです。
【暗号化結果】
(省略)
【復号化結果】
Qiitaは、プログラマのための技術情報共有サービスです。
2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7