private void decryptMember(MemberVO member) {//디코딩
String encodedRegno1 = member.getMemRegno1();
String encodedRegno2 = member.getMemRegno2();
String regno1 = textEncryptor.decrypt(encodedRegno1);
String regno2 = textEncryptor.decrypt(encodedRegno2);
member.setMemRegno1(regno1);
member.setMemRegno2(regno2);
}
principal을 사용할려면 req을 쓸수있어야하는데 그곳이 controller이다. 그치만 req 안에 어느 메소드도 principal 을 담을 만한데가 없음 -> 그래서 filter를 사용할거 같다.
filter를 이용함으로서 가진값을 대체할수있다. request 만들고 principal 만들수있다. -> 어댑터 패턴 쓸 듯
원본 request를 wrapper할수있어야함
package kr.or.ddit.filter;
import java.io.IOException;
import java.security.Principal;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import kr.or.ddit.vo.MemberVO;
import kr.or.ddit.vo.MemberVOWrapper;
/**
* 이미 인증된 사용자의 Principal(인증객체)를 가진 요청을 생성하기 위한 필터.
* --> 원본요청을 Wrapping하고 있는 요청임
* Principal은 해당 로그인한 유저에 대한 인증 정보를 가지고있음
*(필터에서 해당 로그인 요청에 대한 )
*(요청은 진짜 요청이아님 요청은 클라이언트가 하는거니깐 여긴 서버니깐)
*
*/
public class MakePrincipalFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
MemberVO authMember = (MemberVO)req.getSession().getAttribute("authMember");
// 익명 클래스의 상속 구조(로그인이 되어있을 때 필요한 것)
if(authMember != null) {
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(req) {
@Override
public Principal getUserPrincipal() {
// TODO Auto-generated method stub
return new MemberVOWrapper(authMember);
}
};
chain.doFilter(wrapper, response);
}else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
이거하고 filter web.xml에 등록해야함. 리스너와 서블릿 사이에
package kr.or.ddit.vo;
import java.security.Principal;
public class MemberVOWrapper implements Principal {
private MemberVO realMember;
public MemberVOWrapper(MemberVO adaptee) {
this.realMember = adaptee;
}
@Override
public String getName() {
return realMember.getMemId();
}
public MemberVO getRealMember() {
return realMember;
}
}
어댑티가 없다. ->대신 request가 어댑티다.
https://javaplant.tistory.com/26
암호화 양방향, 단방향, 공개키(비댕칭키), 비공개키(대칭키) 개념/분류 알고리즘 정리
암호화 양방향, 단방향, 대칭키(비공개키), 비대칭키(공개키) 개념/분류 알고리즘 정리 양방향 단방향 알고리즘 우선, 가장먼저 분류되는 방식은 양방향, 단방향 알고리즘이다. 간단하게 말해서
javaplant.tistory.com
암호화(해시함수 - 단방향, 공개키有-양방향)
Encrypt(암호화)/Descrypting(복호화) : 데이터 보호를 목적으로 허가받지 않은 사용자가 읽을 수 있는 표현방식으로 데이터 표현을 바꾸는 과정
* 단방향 암호화(hash 함수) : 비밀번호 암호화에 사용. EX) SHA-512(만들어지는 해쉬값길이)
* hash ?? 입력데이터에 대해 일정길이로 만들어지는 코드값
* 양방향 암호화 : 전송 데이터 보호에 사용. 전자 서명에 사용.(JavaCrytoLibrary - Cipher)
- 대칭키 방식(비밀키 방식) : 하나의 비밀키로 암호화의 복화화를 수행. ex) AES(128)
- 비대칭키 방식(공개키 방식) : 한쌍의 키(공개키/개인키)로 암복호화 수행 ex)RSA(1024, 2048)
* Encode (부호화)/Decoding(복호화) : 데이터를 전송하거나 저장하기 위해 사용할 매체가 인지할 수 있는 표현방식으로 데이터의 표현을 바꾸는 과정.
* ex) URLEncoding(Percent Encoding), Base64
public class EncryptingDesc {
public static void main(String[] args) throws Exception {
String plain = "721020";
encryptAESExample(plain);
}
/**
* SHA-512알고리즘으로 단방향 암호화 후 Base 64로 인코딩함.
*
* @param plain
* @throws Exception
*/
public static String encryptSha512(String plain) throws Exception {
// 입력데이터는 다른데 어떤걸 넣어도 512가 됨, 어떤입력데이터를 넣어도 똑같은게 나오는데 이게 해시값
// 똑같은 길이가 나올때 그게 해쉬( 일정한 길이의 값)
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] encrypted = md.digest(plain.getBytes());// 바이트배열로 쪼갬, 암호의 결과가 되는 해시코드가 됨
System.out.println(encrypted.length * 8);// 64 1바이트 8비트.
String encoded = Base64.getEncoder().encodeToString(encrypted);// 인코딩해서 그결과를 문자열타입으로 반환 -> 인코딩됌 , 64 =
// 대소문자(52)+10개+(/+)2개 = 64개
System.out.printf("평문 :%s , 암호문 : %s", plain, encoded);
return encoded;
}
public static void encryptAESExample(String plain) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
KeyGenerator keyGen = KeyGenerator.getInstance("AES");//secreykey를 사용하기위한 팩토리구조
//전치 암호 치환암호 블럭암호 . aes = 블럭암호화방식을 사용
keyGen.init(256);//128비트 16바이트짜리 키를 만듬
SecretKey key = keyGen.generateKey();//키만들기
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] iv = md.digest("password".getBytes());//초기화벡터만들기
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] input = plain.getBytes();
byte[] encrypted = cipher.doFinal(input);//바이트배열 암화가 된애들
String encoded = Base64.getEncoder().encodeToString(encrypted);
System.out.printf("암호문: %s\n", encoded);
//대칭키에서 ivspec
byte[] decoded = Base64.getDecoder().decode(encoded);//디코딩 인크립티드랑 똑같다.
cipher.init(Cipher.DECRYPT_MODE, key,ivSpec);//딥크리팅
byte[] decryted = cipher.doFinal(decoded);//인크립티드가 넘어가는거랑 똑같다.== input이랑 같음
System.out.printf("복호화된 평문: %s\n", new String(decryted));
}
public static void encryptRSAExample(String plain) throws Exception{
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);//키사이즈,
KeyPair keyPair = keyPairGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate(); //비밀키
PublicKey publicKey = keyPair.getPublic();//공개키
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] input = plain.getBytes();
byte[] encrypted = cipher.doFinal(input);
String encoded = Base64.getEncoder().encodeToString(encrypted);
System.out.printf("암호문 : %s\n", encoded);
byte[] decoded = Base64.getDecoder().decode(encoded);//원문으로 복원하는 decoder
cipher.init(Cipher.DECRYPT_MODE, privateKey);//딥크리팅 사이퍼 초기화
byte[] decryted = cipher.doFinal(decoded);//encoded얘를 넘기는거랑 같음
System.out.printf("복원된 평문: %s\n", new String(decryted));
}
}
Cipher란?
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher
Standard Algorithm Name Documentation
SSL3Padding The padding scheme defined in the SSL Protocol Version 3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher): block-ciphered struct { opaque content[SSLCompressed.length]; opaque MAC[CipherSpec.hash_size]; uint8 padding[ GenericBlockCipher
docs.oracle.com
https://scshim.tistory.com/305
[Java] Cipher, 자바의 암호화&복호화를 담당하는 클래스
아래 홈페이지에 정리된 내용을 의역하여 자바의 Cipher 클래스에 대하여 설명하는 글입니다. www.baeldung.com/java-cipher-class 학습 목표 - Cipher란? - Cipher 객체 인스턴스화하기 - Keys - Cipher 초기화(I..
scshim.tistory.com
암호화는 권한이 있는 사용자만 메세지를 이해하거나 접근할 수 있도록, 메세지를 인코딩하는 과정을 말한다.
여기서 plaintext라고 불리는 메세지는 암호화 알고리즘을 통해 암호화되어 cyphertext를 생성한다. cyphertext는 복호화를 통해 오직 권한이 있는 사용자만 읽을 수 있다.
이 글은 자바에서 암호화, 복호화 기능을 제공하는 Cipher 클래스에 대해 설명한다.
javax.crypto pakage에 위치한 Cipher 클래스는 암호화 및 복호화 기능을 제공하며, JCE framework의 핵심을 구성한다.
- Java Cryptography Extension(JCE): 자바 보안 기능의 핵심을 담당하는 Java Crpytography Architectur(JCA)의 일부분으로, 애플리케이션에서 데이터 암호화, 복호화 그리고 개인 데이터의 해싱을 제공한다.
MessageDigest
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest
Standard Algorithm Name Documentation
SSL3Padding The padding scheme defined in the SSL Protocol Version 3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher): block-ciphered struct { opaque content[SSLCompressed.length]; opaque MAC[CipherSpec.hash_size]; uint8 padding[ GenericBlockCipher
docs.oracle.com
MessageDigest md = MessageDigest.getInstance("MD5");
//MessageDigest 클래스를 사용한 해시값 생성,MD5 형식으로 암호화
public final void init(int opmode,
Key key,
AlgorithmParameterSpec params)
throws InvalidKeyException,
InvalidAlgorithmParameterException
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
cipher.init(Cipher.DECRYPT_MODE, key,ivSpec);//딥크리팅
The cipher is initialized for one of the following four operations: encryption, decryption, key wrapping or key unwrapping, depending on the value of opmode.
If this cipher requires any algorithm parameters and params is null, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values) if it is being initialized for encryption or key wrapping, and raise an InvalidAlgorithmParameterException if it is being initialized for decryption or key unwrapping. The generated parameters can be retrieved using getParameters or getIV (if the parameter is an IV).
If this cipher requires algorithm parameters that cannot be derived from the input parameters, and there are no reasonable provider-specific default values, initialization will necessarily fail.
If this cipher (including its underlying feedback or padding scheme) requires any random bytes (e.g., for parameter generation), it will get them using the SecureRandom implementation of the highest-priority installed provider as the source of randomness. (If none of the installed providers supply an implementation of SecureRandom, a system-provided source of randomness will be used.)
Note that when a Cipher object is initialized, it loses all previously-acquired state. In other words, initializing a Cipher is equivalent to creating a new instance of that Cipher and initializing it.
대칭키 방식으로 주로 암호화한다. ( 비대칭키로하면 망함 (?))
Jasypt: Java simplified encryption - Jasypt: Java simplified encryption - Main
Jasypt 1.9.3 RELEASED! (May 25th, 2019) [DOWNLOAD and ChangeLogs] [WHAT'S NEW IN JASYPT 1.9] Java Simplified Encryption Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and wi
www.jasypt.org
pom.xml에 dependency 추가해준다.
<!-- 암호화지원용 -->
<!-- https://mvnrepository.com/artifact/org.jasypt/jasypt -->
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>
Code examples
Easiest use: the BasicTextEncryptor util class:
...
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
...
More security: the StrongTextEncryptor util class with a much more secure (but slower!) algorithm (you may need to download and install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files to use it):
...
StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
...
More security: the AES256TextEncryptor util class with a much more secure algorithm: PBEWithHMACSHA512AndAES_256, (you need Java 8 at least to use it):
...
AES256TextEncryptor textEncryptor = new AES256TextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
...
String myEncryptedText = textEncryptor.encrypt(myText);
...
String plainText = textEncryptor.decrypt(myEncryptedText);
...
All these util classes are in fact pre-configured, easy-to-use versions of StandardPBEStringEncryptor, so let's use the original class for total control:
...
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt"); // we HAVE TO set a password
encryptor.setAlgorithm("PBEWithHMACSHA512AndAES_256"); // optionally set the algorithm
encryptor.setIvGenerator(new RandomIvGenerator()); // for PBE-AES-based algorithms, the IV generator is MANDATORY
...
String encryptedText = encryptor.encrypt(myText);
...
String plainText = encryptor.decrypt(encryptedText); // myText.equals(plainText)
...
And we can even use a pooled version for higher performance in multi-processor/multi-core systems:
...
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
encryptor.setPoolSize(4); // This would be a good value for a 4-core system
encryptor.setPassword("jasypt");
encryptor.setAlgorithm("PBEWithMD5AndTripleDES");
...
String encryptedText = encryptor.encrypt(myText);
...
주민등록번호 DB에는 암호화 보일때는 복호화
String appPassword = "java";
AES256TextEncryptor textEncryptor;
{
textEncryptor = new AES256TextEncryptor();
textEncryptor.setPassword(appPassword);
}
private void encryptMember(MemberVO member) {//인코딩
String plain = member.getMemPass();
String encoded = new StrongPasswordEncryptor().encryptPassword(plain);
member.setMemPass(encoded);
String regno1 = member.getMemRegno1();
String regno2 = member.getMemRegno2();
String encodedRegno1 = textEncryptor.encrypt(regno1);
String encodedRegno2 = textEncryptor.encrypt(regno2);
member.setMemRegno1(encodedRegno1);
member.setMemRegno2(encodedRegno2);
}
private void decryptMember(MemberVO member) {//디코딩
String encodedRegno1 = member.getMemRegno1();
String encodedRegno2 = member.getMemRegno2();
String regno1 = textEncryptor.decrypt(encodedRegno1);
String regno2 = textEncryptor.decrypt(encodedRegno2);
member.setMemRegno1(regno1);
member.setMemRegno2(regno2);
}
@Override
public ServiceResult createMember(MemberVO member) {
ServiceResult result = null;
if (memberDao.selectMemberForAuth(member) == null) {
// 개인식별데이터 암호화
encryptMember(member);
int rowcnt = memberDao.insertMember(member);
if (rowcnt > 0) {
result = ServiceResult.OK;
} else {
result = ServiceResult.FAIL;
}
} else {
result = ServiceResult.PKDUPLICATED;
}
return result;
}