자바 언어에서 비대칭키 방식의 RSA 암/복호화 방법을 알아봅니다. 키생성과 암호화 복호화를 모두 자바 언어로 수행합니다.
CipherUtil.java 파일을 1024bit 키를 생성하고, 암호화, 복호화를 지원하는 유틸리티 클래스로 작성되었습니다. 키는 SecureRandom 클래스를 사용해서 임의의 키를 생성합니다.
package com.tistory.offbyone.rsa;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
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.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class CipherUtil {
/**
* 1024비트 RSA 키쌍을 생성합니다.
*/
public static KeyPair genRSAKeyPair() throws NoSuchAlgorithmException {
SecureRandom secureRandom = new SecureRandom();
KeyPairGenerator gen;
gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024, secureRandom);
KeyPair keyPair = gen.genKeyPair();
return keyPair;
}
/**
* Public Key로 RSA 암호화를 수행합니다.
* @param plainText 암호화할 평문입니다.
* @param publicKey 공개키 입니다.
* @return
*/
public static String encryptRSA(String plainText, PublicKey publicKey)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytePlain = cipher.doFinal(plainText.getBytes());
String encrypted = Base64.getEncoder().encodeToString(bytePlain);
return encrypted;
}
/**
* Private Key로 RAS 복호화를 수행합니다.
*
* @param encrypted 암호화된 이진데이터를 base64 인코딩한 문자열 입니다.
* @param privateKey 복호화를 위한 개인키 입니다.
* @return
* @throws Exception
*/
public static String decryptRSA(String encrypted, PrivateKey privateKey)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance("RSA");
byte[] byteEncrypted = Base64.getDecoder().decode(encrypted.getBytes());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] bytePlain = cipher.doFinal(byteEncrypted);
String decrypted = new String(bytePlain, "utf-8");
return decrypted;
}
/**
* Base64 엔코딩된 개인키 문자열로부터 PrivateKey객체를 얻는다.
* @param keyString
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKeyFromBase64String(final String keyString)
throws NoSuchAlgorithmException, InvalidKeySpecException {
final String privateKeyString =
keyString.replaceAll("\\n", "").replaceAll("-{5}[ a-zA-Z]*-{5}", "");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpecPKCS8 =
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));
return keyFactory.generatePrivate(keySpecPKCS8);
}
/**
* Base64 엔코딩된 공용키키 문자열로부터 PublicKey객체를 얻는다.
* @param keyString
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PublicKey getPublicKeyFromBase64String(final String keyString)
throws NoSuchAlgorithmException, InvalidKeySpecException {
final String publicKeyString =
keyString.replaceAll("\\n", "").replaceAll("-{5}[ a-zA-Z]*-{5}", "");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpecX509 =
new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString));
return keyFactory.generatePublic(keySpecX509);
}
}
위에서 작성한 유틸리티 클래스를 사용해서 평문을 개인키로 암호화 하고, 공개키로 복호화하는 예제입니다.
package com.tistroy.offbyone.rsa;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
public class RSATest {
public static void main(String[] args) throws Exception {
// RSA 키쌍을 생성합니다.
KeyPair keyPair = CipherUtil.genRSAKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String plainText = "암호화 할 문자열 입니다.";
// Base64 인코딩된 암호화 문자열 입니다.
String encrypted = CipherUtil.encryptRSA(plainText, publicKey);
System.out.println("encrypted : " + encrypted);
// 복호화 합니다.
String decrypted = CipherUtil.decryptRSA(encrypted, privateKey);
System.out.println("decrypted : " + decrypted);
// 공개키를 Base64 인코딩한 문자일을 만듭니다.
byte[] bytePublicKey = publicKey.getEncoded();
String base64PublicKey = Base64.getEncoder().encodeToString(bytePublicKey);
System.out.println("Base64 Public Key : " + base64PublicKey);
// 개인키를 Base64 인코딩한 문자열을 만듭니다.
byte[] bytePrivateKey = privateKey.getEncoded();
String base64PrivateKey = Base64.getEncoder().encodeToString(bytePrivateKey);
System.out.println("Base64 Private Key : " + base64PrivateKey);
// 문자열로부터 PrivateKey와 PublicKey를 얻습니다.
PrivateKey prKey = CipherUtil.getPrivateKeyFromBase64String(base64PrivateKey);
PublicKey puKey = CipherUtil.getPublicKeyFromBase64String(base64PublicKey);
// 공개키로 암호화 합니다.
String encrypted2 = CipherUtil.encryptRSA(plainText, puKey);
System.out.println("encrypted : " + encrypted2);
// 복호화 합니다.
String decrypted2 = CipherUtil.decryptRSA(encrypted, prKey);
System.out.println("decrypted : " + decrypted2);
}
}
실행한 결과 입니다.
※ 개인키와 공개키를 Base64로 인코딩된 문자열로 만드는 방법도 추가 되어있습니다.
※ Base64 인코딩된 개인키와 공개키 문자열을 PrivateKey, PublicKey 객체로 만드는 기능을 추가했습니다.
반응형
'프로그래밍 > 네트워크, 보안' 카테고리의 다른 글
PHP 암호화 SHA-256, SHA-512, AES-256, RSA (0) | 2018.10.26 |
---|---|
자바스크립트 RSA 암호화 라이브러리 JSEncrypt (10) | 2018.10.04 |
Windows에서 TOMCAT에 개발용으로 SSL 적용하기 (28) | 2018.04.21 |
SSL 동작 방식을 간단히 알아보기 (0) | 2018.04.21 |
Tomcat SSL 적용시 https로 자동 리다이렉트 설정하기 (8) | 2018.04.20 |