안녕하세요 가야태자 @talkit 입니다.
지난 번에 Hello World를 찍고 ^^ 당황 스럽긴 하겠지만 ㅋㅋㅋ 지금 하고 있는 프로젝트에서 암호화/복호화 관련 업무가 있어서 ^^ 적어 보도록 하겠습니다.
개요
우선, 암호화는 사람들이 모르도록 이상한 문자열 등으로 바꾸는 것을 이야기 합니다. 그런데 이게 보통은 해독할 수 있는 규칙이 있습니다. 그래야 공통으로 약속되어서 풀어 볼 수 있으니까요.
암호화는 또 단방향 암호화와 양 방향 암호화가 있습니다.
단방향 암호화는 그야말로 복호화가 없는 단방향의 암호화 입니다. 단, 암호화 할때마다 동일한 결과가 나옵니다.
양방향 암호화는 암호화와 복호화가 존재하는 암호화 기법입니다.
일반적으로 단방향 암호화는 비밀번호를 만드는데 쓰입니다. 비밀번호도 양방향 암호화를 해야 할 경우도 있지만, 일반적으로는 단방향 암호화를 진행 합니다.
양방향 암호화는 주로 문서교환을 위해서 사용 합니다. 또는 DB에 바로 저장 되면 안되는 개인 정보 등의 저장을 위해서 사용 합니다.
이번에 제가 만들어 본 암호화는 양방향 암호화 입니다. ^^
개인키, 공개키 생성 프로그램
--
양방향 암호화를 하려면, 개인키와 공개키가 필요 합니다. 이번에 암호화 려는 기법은 RSA 기법입니다. RSA는 다음에 알아보도록 하고 오늘은 JAVA 어떻게 코드를 작성하는지만 보겠습니다. ^^
package com.tistory.talkit;
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;
public class MakeKeyData {
public static void main(String[] args) throws NoSuchAlgorithmException {
// RSA로 암호화 하겠다.
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
// Random 키를 이용해서 키페어 생성 준비
keyPairGenerator.initialize(2048,secureRandom);
// 키페어에 암호화된 내용을 담기
KeyPair pair = keyPairGenerator.generateKeyPair();
// 공개키 획득
PublicKey publicKey = pair.getPublic();
// 공개키를 문자열로 출력
String publicKeyString =
Base64.getEncoder().encodeToString(publicKey.getEncoded());
System.out.println("public key = "+ publicKeyString);
// 개인키 획득
PrivateKey privateKey = pair.getPrivate();
// 개인키를 문자열로 출력
String privateKeyString =
Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println("private key = "+ privateKeyString);
}
}
위 코드를 만들어서 수행하면 아래와 같이 나옵니다.
public key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAppicAq5Xn8+KZFQyP825E4aDPjFpyxhK5WATI4k3HllMxGo8FBOwoDl+lgVEIPEGgfD+t1cmBOpPkT7Mx54UQ+bSSU2T1wDR7QwyGV2iuxe6DCtQfVLuzYd6uxZO3pWoN93q9DkhzbLLOW1bLOieodnhMRq293uoKRWCP+Sp586SVPxwW/hWZjy57NIta1ew+JnRtHsg7reWOjyiCXORXdQvRoGfAz9ZC0aZBqopy84ZtMCK42y0Wprm0Oi4u3bwk2h2EkvGUOIRBHEly//M0Ma4RGlHWU7jpg0CiXcJAdq1DRMd6hzFVxUV4n23575NOKLwEirvqbgZXoaLJSo/1QIDAQAB
private key = MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmmJwCrlefz4pkVDI/zbkThoM+MWnLGErlYBMjiTceWUzEajwUE7CgOX6WBUQg8QaB8P63VyYE6k+RPszHnhRD5tJJTZPXANHtDDIZXaK7F7oMK1B9Uu7Nh3q7Fk7elag33er0OSHNsss5bVss6J6h2eExGrb3e6gpFYI/5KnnzpJU/HBb+FZmPLns0i1rV7D4mdG0eyDut5Y6PKIJc5Fd1C9GgZ8DP1kLRpkGqinLzhm0wIrjbLRamubQ6Li7dvCTaHYSS8ZQ4hEEcSXL/8zQxrhEaUdZTuOmDQKJdwkB2rUNEx3qHMVXFRXifbfnvk04ovASKu+puBlehoslKj/VAgMBAAECggEAXoMdnvfBhkx7usd5anEPmmApfNMTrcCuXMrQkMx7lKAcySFrzAgPoBZ+FiYOrJGQm49ZMjIiw48abNAv5N9tp8f/bM6yHLu+XLkagwF4HKQtTFIWa8Ls73T4z8KsI+LLeEZR0RPIdaYFXSMJIsUlmbS96Nm7C1P/5q7pIc5cBcFg8uyFA13yHUUd5oJaal7RPVIfRQAUZZNj3crSVdQYCfdB42nokQ0z5kv3Qm3eu04Wqli/GyWIKRbxaffTlYvEjzjN4cxptJOPSn6zQlLXIStmwohQLjmx1UQ1cWJWqwF0910QleIJyR1iBKEtbvUORxEc0hv+a/2trwQP973gAQKBgQD55jq7ofNXSsnhyC9IJEyGDfvSRTtMEDwEk4pXQy6RKFrUN3/5AD40EBb2V0txhIwQxPD2YBCkSVXW/swMMA/QSM1lLLMkSqRkQhBucAO2RimgDNVXbzakFAmDgWSUjNz0HrSXJuGmKnErb42I+0yc+hd+Sl+WqRgWZ7SkUPLN1QKBgQCqqcS1XGKLoVyRnIYGivsA2/83RIJVx8Mjzofgg6Ekd5Q1uKMZFowAy3wbqMCRRW8+qufVmElzCMP79Pijh2nrv7QfEBrTbWdDgiMJz+Sq6JGHDyAiGv7v5j/nbl0JlgNKKmx2fiNpITBNQTQWPs3cqxArKz3j0Apy3HphlWiqAQKBgQC8Qbe/QDrMaPf7Ek6kP0wytPgfKK6KF7TPEcLnCCJdkhQSyRisIYW6vOA/hfW8t8i4nVSVljsTOHflNh/Lkq1nEGFDNdBip6R+LtKoD9SMDQEwpFpXut1j8ABWxDRcQF33veX39H+LKXAF88yhBAdsPm9SYX7vRcVyo3+PRbgUXQKBgACIqWnb0R8YsR5ve+fXVXOqPIEiwLmd91lMUxZ7suxXR2pnmnMApA14lXnMrFWH/xIWHMWJRWmLtHk8Se7RBJ7NKbYTKdJRfEo0xQFJ2jBCq/ndLT+OEBAWC0shCD94bag0u8QfHuM8TFdhhdUv+xremh1YdEgbJX04fVWCzyIBAoGBAM4g8t3KCd+fcwn2tQOENr6G4pztm5qvFw1rsXK46K2P0Bggf54f+nrVBHUh1lSVk1uLyzx8QF7Btl++GD64w7MOWPC40osCNaL7uHqwFx1rrZdsuF0EM9lBtvzxBUbQkOh5T8U1cBCHupdETXsKmgAbdoBXyp22Z3En/zpSz8kJ
저 두개의 키가 암호화와 복호화를 위한 키 입니다.
암호화 함수 만들기
공개키와 개인키를 이제 만들었으면 우선 코드를 개별적으로 설명 드리겠습니다.
우선, encode 함수를 만듭니다.
public static String encode(String decodeText) throws GeneralSecurityException, IOException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(2048, secureRandom);
PrivateKey privateKey = (PrivateKey) loadPrivateKey(privateKeyString1);
Cipher encryptionCipher = Cipher.getInstance("RSA");
encryptionCipher.init(Cipher.ENCRYPT_MODE, privateKey);
String message = decodeText;
byte[] encryptedMessage = encryptionCipher.doFinal(message.getBytes());
String encryption = Base64.getEncoder().encodeToString(encryptedMessage);
return encryption;
}
암호화 함수는 내용은 복잡하지만, 사용은 편하도록 encode(복호화된 텍스트) 형식의 함수를 만들었습니다.
나머지는 루틴이라고 생각하시면 되고 ^^ 앞에서 만든키를 키로 변환해 주는 과정이 필요합니다.
위 코드 중에
PrivateKey privateKey = (PrivateKey) loadPrivateKey(privateKeyString1);
이 부분입니다. 이부분은 함수로 다시 작성해서 사용했씁니다.
// 문자열 공개키를 Key 로 변환
public static Key loadPublicKey(String stored)
throws GeneralSecurityException, IOException {
byte[] data = Base64.getDecoder().decode((stored.getBytes()));
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}
// 문자열 개인키를 Private Key로 변환
public static PrivateKey loadPrivateKey(String key64)
throws GeneralSecurityException {
byte[] clear = Base64.getDecoder().decode((key64.getBytes()));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey priv = fact.generatePrivate(keySpec);
Arrays.fill(clear, (byte) 0);
return priv;
}
개인키 공개키를 모두다 할 수 있도록 만들었습니다.
복호화 함수 만들기
다음으로 decode함수의 소스 코드 입니다.
public static String decode(String encodeText) throws GeneralSecurityException, IOException {
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(2048,secureRandom);
PublicKey publicKey = (PublicKey) loadPublicKey(publicKeyString1);
//Decrypt Hello world message
Cipher decryptionCipher = Cipher.getInstance("RSA");
decryptionCipher.init(Cipher.DECRYPT_MODE,publicKey);
byte[] decryptedMessage =
decryptionCipher.doFinal(Base64.getDecoder().decode(encodeText));
String decryption = new String(decryptedMessage);
//System.out.println("decrypted message = "+decryption);
return decryption;
}
위 코드는 암호화된 텍스트를 넣으면, 복호화된 텍스트를 리턴하도록 만들었습니다.
암호화와 마찬가지로 중간에 아래 코드가 중요하고 그 내용은 복호화에 넣어둔 코드를 확인 하십시오.
PublicKey publicKey = (PublicKey) loadPublicKey(publicKeyString1);
메인 함수에서 불러서 암복호화 해보기
public static void main(String[] args) throws GeneralSecurityException, IOException {
String encodeText = encode("Hello World. Welcome to Korea. * ");
System.out.println(encodeText);
System.out.println("encoded Text : " + encodeText);
String decodeText = decode(encodeText);
System.out.println("decoded Text : " + decodeText);
}
Hello World. 으로 시작하는 문자열을 암호화 했다가 복후화 하는 코드 입니다.
실행하면
encoded Text : c8AcbCp4bIARJA3EOW9cf41pRIefVhCvCWyxwcgwifWaDK8AX9RJoe8dOgPzuvauCZZG5ibbOMtvEPh06DUwojFzMngCtT3T6VOyzWDA/CBFN52jXZzqw9M1K1v3vZJ+0uft86TomxZvbWdxv5XPo5keh0HyWyexv3U5c5cXypMwBTDECUiQkUPjZN1aUf7dHGQG0uC+KuyNEKK4NDMddPWoo0gzlWxsxIBkm7oLpuKEcXP9ThM16JQD8rhskJbXwbhUL39xfmDSti8Om9DcrU6KCDakKeT7i72yRjAD5B60Da28jT1DlzwS9p7IlfPXdlybjLKUMUcQsF1rJ1Xvww==
decoded Text : Hello World. Welcome to Korea. *
위와 같이 잘 복호화 되어서 나옵니다.
전체소스코드
package com.tistory.talkit;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
public class RSAEncode {
public static String publicKeyString1 = "만들어진 public key";
public static String privateKeyString1 = "만들어진 private key";
public static void main(String[] args) throws GeneralSecurityException, IOException {
String encodeText = encode("Hello World. Welcome to Korea. * ");
System.out.println(encodeText);
System.out.println("encoded Text : " + encodeText);
String decodeText = decode(encodeText);
System.out.println("decoded Text : " + decodeText);
}
public static String decode(String encodeText) throws GeneralSecurityException, IOException {
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(2048,secureRandom);
PublicKey publicKey = (PublicKey) loadPublicKey(publicKeyString1);
//Decrypt Hello world message
Cipher decryptionCipher = Cipher.getInstance("RSA");
decryptionCipher.init(Cipher.DECRYPT_MODE,publicKey);
byte[] decryptedMessage =
decryptionCipher.doFinal(Base64.getDecoder().decode(encodeText));
String decryption = new String(decryptedMessage);
//System.out.println("decrypted message = "+decryption);
return decryption;
}
public static String encode(String decodeText) throws GeneralSecurityException, IOException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(2048, secureRandom);
PrivateKey privateKey = (PrivateKey) loadPrivateKey(privateKeyString1);
Cipher encryptionCipher = Cipher.getInstance("RSA");
encryptionCipher.init(Cipher.ENCRYPT_MODE, privateKey);
String message = decodeText;
byte[] encryptedMessage = encryptionCipher.doFinal(message.getBytes());
String encryption = Base64.getEncoder().encodeToString(encryptedMessage);
return encryption;
}
// 문자열 공개키를 Key 로 변환
public static Key loadPublicKey(String stored)
throws GeneralSecurityException, IOException {
byte[] data = Base64.getDecoder().decode((stored.getBytes()));
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}
// 문자열 개인키를 Private Key로 변환
public static PrivateKey loadPrivateKey(String key64)
throws GeneralSecurityException {
byte[] clear = Base64.getDecoder().decode((key64.getBytes()));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey priv = fact.generatePrivate(keySpec);
Arrays.fill(clear, (byte) 0);
return priv;
}
}
개인키와 공개키는 제가 만든 저위에 있는 것을 복사하셔도 되고, MakeKeyData를 이용해서 만드셔도 됩니다.
그러나, 되도록이면 만들어서 사용하십시오. 공개된 개인키와 공개키를 사용하면 다음에 해킹 당했을 때 위험할 수 있습니다.
그리고, 주의할 점은 저 공개키와 개인키는 무조건 보관해두고 잃어버리시면 안됩니다. ^^
다음에 복호화가 안될꺼니까요.
감사합니다.