300x250
반응형
300x250
1. RSA 방식이란
- 공개키와 개인키를 이용한 대표적인 암호화 방식이다.
- 전자 서명이 가능한 최초의 알고리즘이다.
- AES와 DES와 같은 대칭키 암호화 방식의 문제점인 키의 노출 문제를 해결한다.
- Kerckhoff가 만든 암호화 알고리즘이다.
2. 공개키와 비밀키
- 공개키 (Public Key)
: 누구에게나 공개될 수 있으며 메시지를 보내는 발신자는 공개키를 통해 정보를 암호화한다. - 비밀키 (Private Key)
: 수신자는 비밀키를 암호화된 메시지를 복호화하는데 사용한다. 외부에 노출되지 않도록 안전하게 보관해야 한다.
3. 구현방식
- 구현 방식은 Client가 (로그인 시도자)가 평문을 비밀키를 가지고 암호화한 후 공개키를 DB에 저장하고 있는 서버는 사용자 정보 중 공개키를 조회할 수 있는 값으로 공개키를 조회 후 맞는 공개키가 맞는지 확인한다.
- 비밀키(Private Key)로 평문(Plain Text)를 암호화한다.
- 서버에 보낼 데이터에 공개키 조회 유일한 값과 암호화된 signText 문자열을 날린다.
- 서버에서는 받은 공개키 조회를 유일한 값으로 DB에서 공개키(Public Key)를 조회한다.
- 암호화된 signText와 공개키를 이용해 쌍인 비밀키로 암화되었는지 검증(Verify)한다.
- 공개키와 맞는 비밀키로 암호화된 평문이면 true, 아니면 false다.
4. Java를 이용한 전자서명
package daemon;
import javax.crypto.Cipher;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
public class RSA {
static final int KEY_SIZE = 2048;
static String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjNw0K5CD6vrhJfZouF8e+vBE6/oYLa43ntnl1Sz/jI2DaaggWem2KNnHoyu2Y+qn2ncBdWvp3eX2cTVRreZo9kJPtNQLQWDTrM6eum61fsBv9O5aKMarpaBisqk+zazeSZojJFkgpF20382ZQN4NkXlxopt04f8M7XnSMzHEUhlc6MBffYsoJALxv34E71/L3mJbcDGbHr3QdW/pzrOr8DEQ9z+UmBAPxCH1wKkKfSal5lcJAM8vtBLgXjReEQH8Tp6nwDWEZYgKoyQK0hD+bclE8UUeE0IeNITNaL3774mMruHF7f+7nIH0iaMBvLwR4CPo7YHG9FLPQV9ehyb7hQIDAQAB";
static String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCM3DQrkIPq+uEl9mi4Xx768ETr+hgtrjee2eXVLP+MjYNpqCBZ6bYo2cejK7Zj6qfadwF1a+nd5fZxNVGt5mj2Qk+01AtBYNOszp66brV+wG/07looxquloGKyqT7NrN5JmiMkWSCkXbTfzZlA3g2ReXGim3Th/wztedIzMcRSGVzowF99iygkAvG/fgTvX8veYltwMZsevdB1b+nOs6vwMRD3P5SYEA/EIfXAqQp9JqXmVwkAzy+0EuBeNF4RAfxOnqfANYRliAqjJArSEP5tyUTxRR4TQh40hM1ovfvviYyu4cXt/7ucgfSJowG8vBHgI+jtgcb0Us9BX16HJvuFAgMBAAECggEAcZBTS1Au2vK7NKUN1p9x1bSCjJHMjn+n/h0EzDKEMWgiK7vNoU/oedTivC3Q1YtpGpvZhDaljS4K20i2enKJ6wiZRFu0W1haMDdBB2OcVf2GBb1o2Pkbh+PfztTeemnFqSdo77QfugSGf+09gmvEGqYDtKqKuG2tmYQesQGNmvX/V/xJHPmiZPupKnQyiFAZ9A4eTQrCdTZZoOX9DTrtHaDuUsxaMxzFVV8VYDMlDIYZisHvqRhh5AHGtyxPdaG+VkiMUsP73aeFElHZ7RvMpoOGx7pHP3+cUkAY+DGU8WHjkVcB2OoAO0CiSGJvmcIiS/5aUcyAaCZnMOsRXQAXYQKBgQDF/Rsdwif/PqF2JT2r1ecJExhvEBf4pwyfyq5XgVWpNF76oqsEtcznxwNlkP6z8nN4lHg6wNJhWhGlAkbETjnRDGD96MVmIFeyv40NrGOP1xpl+lvXxXQglOuJJyHxdbSaUOMAUPRQmEaAVbIejyMvo3F6rb//nIqqmpUNQ09WyQKBgQC2IfS4eWOFdpt0HwUD4HJg7qXbcOcRoOpEGrQrk1hPqUwywMSU7OIGR+CJoSFIpww9ONpSagX324o2rdHYSrg4FqK4KYCqf6SaQgGlwGvYXXYzjIDKVqrA1TAuL3x5eOSHXzfdlR5nvXI15Rudx+ydxn437NgDBYSYm4T1aBiQ3QKBgFuA9BRX1IZ6GsNwyMTvMj0Wbzd9V6bbBdGgKd1VcBKomrD5l1Kw90ezydUaIy1lg4qaC8sTrOfDad46ZBx8DuqX7wfKmdjuX7nEH9vO7aDgCFpTUDk0D8yzJvyXcm+XN+YONivCPng1OHg9ovnOq7NrtZm+TbtETS42DWc40aVJAoGAJJpwZz6mHKV4mn69cEkEU6zCknZ/SdCwJB3Fxdgn8GKS2MRa/Z8Z0a9SVfaXDNXdpNQvNE7wgh6SCWknejOSEFukOiTFIf7jIslPMXOZePNXlQaQv5lpWbW+qBmNB5CfRQGC5bpZUPoG4QP5Z91NFWxV44Fq7DiIrG7c6sEP5tUCgYEApjG+ROoTq/jCqC1o6rTX5Izr2U9gqTNpBXI6GTLIneM09/sZEgWotVhbnH4YKXnIapSWQu7zM/Kt9IXRlK9vK1T6qDV2iZp2PvoLgnov0tbE3dOVRfRBLrX9pg7luwjWfi5xsQle0yts05NX+FWYjKiTKYJRQcTKaFcE62DjC6k=";
public static void main(String[] args) {
System.out.println("만들어진 공개키:" + publicKey);
System.out.println("만들어진 개인키:" + privateKey);
String plainText = "플레인 텍스트";
System.out.println("평문: " + plainText);
String encryptedText = encode(plainText, publicKey);
System.out.println("암호화: " + encryptedText);
String decryptedText = decode(encryptedText, privateKey);
System.out.println("복호화: " + decryptedText);
String signText = sign(plainText,privateKey);
System.out.println("서명: "+signText);
boolean result = verifySignarue(plainText, signText, publicKey);
System.out.println("인증: " + result);
}
/**
* 암호화
*/
static String encode(String plainData, String stringPublicKey) {
String encryptedData = null;
try {
//평문으로 전달받은 공개키를 공개키객체로 만드는 과정
PublicKey publicKey = getPublicKey(stringPublicKey);
//만들어진 공개키객체를 기반으로 암호화모드로 설정하는 과정
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//평문을 암호화하는 과정
byte[] byteEncryptedData = cipher.doFinal(plainData.getBytes());
encryptedData = Base64.getEncoder().encodeToString(byteEncryptedData);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedData;
}
/**
* 복호화
*/
static String decode(String encryptedData, String stringPrivateKey) {
String decryptedData = null;
try {
//평문으로 전달받은 개인키를 개인키객체로 만드는 과정
PrivateKey privateKey = getPrivateKey(stringPrivateKey);
//만들어진 개인키객체를 기반으로 암호화모드로 설정하는 과정
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//암호문을 평문화하는 과정
byte[] byteEncryptedData = Base64.getDecoder().decode(encryptedData.getBytes());
byte[] byteDecryptedData = cipher.doFinal(byteEncryptedData);
decryptedData = new String(byteDecryptedData);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedData;
}
static PublicKey getPublicKey (String stringPublicKey) {
PublicKey publicKey = null;
try {
//평문으로 전달받은 공개키를 공개키객체로 만드는 과정
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] bytePublicKey = Base64.getDecoder().decode(stringPublicKey.getBytes());
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(bytePublicKey);
publicKey = keyFactory.generatePublic(publicKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return publicKey;
}
static PrivateKey getPrivateKey (String stringPrivateKey) {
PrivateKey privateKey = null;
try {
//평문으로 전달받은 개인키를 개인키객체로 만드는 과정
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] bytePrivateKey = Base64.getDecoder().decode(stringPrivateKey.getBytes());
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(bytePrivateKey);
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return privateKey;
}
public static String sign(String plainText,String strPrivateKey) {
try {
PrivateKey privateKey = getPrivateKey(strPrivateKey);
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes("UTF-8"));
byte[] signature = privateSignature.sign();
return Base64.getEncoder().encodeToString(signature);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException | SignatureException e) {
throw new RuntimeException(e);
}
}
public static boolean verifySignarue(String plainText, String signature, String strPublicKey) {
Signature sig;
try {
PublicKey publicKey = getPublicKey(strPublicKey);
sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(plainText.getBytes());
if (!sig.verify(Base64.getDecoder().decode(signature)));
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
throw new RuntimeException(e);
}
return true;
}
}
출처 : https://juinthyme.tistory.com/59
300x250
반응형
'Back-End > Java' 카테고리의 다른 글
[Java] FTP 파일 전송하는 방법 (Apache commons-net Lib) (0) | 2023.03.21 |
---|---|
[Java] JAVA에서 JSON API parse시 ALLOW_NON_NUMERIC_NUMBERS, Object타입 등의 에러해결 (0) | 2023.03.07 |
[Java] 자바 byte 단위로 문자열 자르기 (0) | 2023.02.10 |
[JAVA]JXLS, POI JAVA에서 Excel 사용하는 구현 방법 및 종류 비교 (0) | 2023.02.09 |
[Java]자바(Java) 한글 초성 검색 (0) | 2023.02.09 |