ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JSP(사용자 정보 암호화 / 복호화 처리)
    JSP 2020. 6. 18. 15:03

    사용자 정보 암호화 / 복호화 처리

     

     암호화 종류

     

      1. 양방향 암호화

     

     1.1 대칭키 암호화 : 송,수신 평문을 암호화하고 복호화를 진행하면서 암호화시 활용된 보안키값을 복호화하여 평문으로


                              변경시에도 활용하는것을 의미함.


           1.1.1 특징 : 공개키 암호화에비해 암호화/복호화를 통한 송,수신 속도가 빠름.


                              암호화되어 송신되는 전송 데이타의 길이가 공개키에비해 짧음.


           1.1.2 암호화 알고리즘: SEED(KISA 권장), ARIA, DES, MISTY
                       
       1.2 공개키 암호화 : 수신 측에서는 암호화 송신을위해 비밀키와 공개키를 생성하고 송신측에게 

     

                                공개키(public)를 제공해 (비대칭키 암호화)송신측에서는 제공된 공개키를 이용해 

     

                                평문을 암호화해 전송하고, 수신측에서는 비밀키(private)를 활용해 수신 데이타를 

     

                                평문으로 변경함.


           1.2.1 특징 : 암호화 속도가 대칭키 암호화에비해 느림.


           1.2.2 암호화 알고리즘 : RSA(KISA 권장), KCDSA, ECC

     

       1.3 해쉬 암호화 : 해쉬함수(송신 정보를 작은 데이타[해쉬코드]로 재가공하며, 난수를 활용함.)

     

                             를 이용해 암호화한 평문을 송신. 
                             

                            해쉬함수를 이용해 암호화된 데이타는 복호화될수 없음. 
                            

                            수신측에서는 실 수신문 대상의 검증을위한 데이타 지문으로 활용됨. 


           1.3.1 암호화 알고리즘 : SHA1|2|SHA256(KISA 권장)|SHA512, MD5

     


      2. 단방향 암호화

    2. 암호화 알고리즘
       
       MD5(Message Digest Algorithm 5) : 128bit hashcode를 제공하는 단방향(암호화) 알고리즘 기법으로
                                         2006년도 복호화되는 결함이 발견되어 더이상 암호화 알고리즘으로
                                                           사용되지 않음.(위변조가 가능함)
                                                    
       Base64Util : 2진 데이터를 64개의 아스키 텍스트로 변환하거나 연변환하는 인코딩 기법으로

     

                      MD5를 통해 암호화 해싱된값을 문자열로 출력시 활용되며, 원본 해싱값보다 33% 값이 커짐.


                      송신 대상의 평문을 아스키 코드로 변환하고 2진화데이타로 변환시키고,

     

                      변환된 2진데이타를 4개의 6bit씩으로 다시 변환처리.  


       SHA[1|2] (Secure Hash Algorithm) : MD5의 위변조 결함에 대안으로 마련된 단방향 암호화 알고리즘.


                                                           한국정보보호협회(KISA의 권유로 SHA1+salt를 권장하고 있음.).


                                         Rainbow Table을 통해 복호화될 가능성이 존재하는 불완전한 알고리즘.


                                         SHA1|SHA2 사용불가. SHA256|SHA512 활용 추천.
                                         
       AES(Advanced Encryption Standard) : 미 연방 표준 차세대 128bit 암호화 알고리즘으로 암/복호화 가능. 

                                      
       AES(Advanced Encryption Standard) : 미 연방 표준 차세대 128bit 암호화 알고리즘으로 암/복호화 가능. 
                                       
       RSA(MIT의 Ronald Rivest, Adi Shamir, Leconard Adleman 3인에의해 개발된 공개키 암호화 알고리즘)


    스탠포드대에서 배포한 javascript 기반 RSA and ECC in JavaScript 라이브러리를 이용한 암호화시 속도비교


       www-cs-students.stanford.edu/~tjw/jsbn/)


                   Chrome  FireFox   IE     Mobile


    RSA public, 512 bit, e=3     0ms     1ms     4ms     40ms 


    RSA public, 512 bit, e=F4    1ms     6ms     20ms    140ms 


    RSA public, 1024 bit, e=3    1ms     3ms     10ms    90ms 


    RSA public, 1024 bit, e=F4   2ms     15ms    70ms    180ms 

     


    공개키 비밀키 만드는 예제

     

    [CryptoGenerator.java]

    package kr.or.ddit.utiles;
    
    import java.io.UnsupportedEncodingException;
    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.RSAPublicKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.servlet.http.HttpSession;
    
    public class CryptoGenerator {
    	
    	// 암, 복호화 : 공개키 + 비밀키 (생성시 동반 생성, 1회 활용하고 폐기)
    	
    	// 반환값 : 공개키(가수부, 지수부 구분)
    	
    	public static Map<String, String> generatePairKey(HttpSession session) {
        
    		// 공개키 + 비밀키 생성
    		KeyPairGenerator keyGenerator = null;
    		
    		// 생성된 공개키 + 비밀키
    		KeyPair keyPair = null;
    		
    		//공개키
    		PublicKey publicKey = null;
    		
    		//비밀키
    		PrivateKey privateKey = null;
    		
    		// 공개키 = 가수부 + 지수부
    		KeyFactory keyFactory = null;
    		
    		Map<String, String> publicKeyMap = new HashMap<String, String>();
    		
    		try{
    			keyGenerator = KeyPairGenerator.getInstance("RSA");
                
    			// 공개키, 비밀키 생성시 사이즈 설정 : byte 단위
    			// 사이즈를 결정하는데 반드시 짝수이어야 함
    			keyGenerator.initialize(2048);
    			
    			//생성된 공개키, 비밀키 취득
    			keyPair = keyGenerator.generateKeyPair();
    			
    			//공개키 취득
    			publicKey = keyPair.getPublic();
    			
    			//비밀키 취득
    			privateKey = keyPair.getPrivate();
    			
    			session.setAttribute("privateKey", privateKey);
    			
    			// 공개키를 가수부와 지수부로 나눠야함
    			// 공개키(Double Type) : 가수부 + 지수부 => 클라이언트에 제공
    			// ex) -143.12344556
    			// float(32bit 단정도 소수) : 부호비트 1bit(양수 0 | 음수 1) + 지수 8bit(소숫점 자리수) + 가수 23bit(실수 표현) 
    			// double(64bit 배정도 소수) : 부호비트 1bit(양수 0 | 음수 1) + 지수 11bit(소숫점 자리수) + 가수 52bit(실수 표현)
    			
    			// 공개키가 어떤 알고리즘으로 되어있는지 설정
    			keyFactory = KeyFactory.getInstance("RSA");
    			
    			RSAPublicKeySpec publicKeySpec = (RSAPublicKeySpec)keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
    			
    			
    			// 공개키 가수부
    			String publicModulus = publicKeySpec.getModulus().toString(16);
    			
    			// 공개키 지수부
    			String publicExponent = publicKeySpec.getPublicExponent().toString(16);
    			
    			publicKeyMap.put("publicModulus", publicModulus);
    			publicKeyMap.put("publicExponent", publicExponent);
    					
    			
    			
    		}catch(NoSuchAlgorithmException e1){
    			e1.printStackTrace();
    		}catch(InvalidKeySpecException e2){
    			e2.printStackTrace();
    		}
    		return publicKeyMap;
    	}
    	
    	//암호문을 평문으로 복호화
    	public static String decryptRSA(HttpSession session, String secureValue){
    		
    		String returnValue = "";
    		PrivateKey privateKey = (PrivateKey) session.getAttribute("pirvateKey");
    		try{
    			// 평문으로 바꿀 때?
    			Cipher cipher = Cipher.getInstance("RSA"); //암호문이 어떤 암호화 방식으로 전달되었는지
    			cipher.init(Cipher.DECRYPT_MODE, privateKey);
    			
    			// 암호문은 짝수 단위로 바이너리 코드로 존재
    			// hextoByteArray라는 메소드는 직접 만들어야함
    			byte[] targetByte = hextoByteArray(secureValue);
    			
    			byte[] beforeString = cipher.doFinal(targetByte);
    			
    			returnValue = new String(beforeString, "UTF-8");
    			
    		  } catch (NoSuchAlgorithmException e) {
    		         e.printStackTrace();
    		      } catch (NoSuchPaddingException e) {
    		         e.printStackTrace();
    		      } catch (InvalidKeyException e) {
    		         e.printStackTrace();
    		      } catch (IllegalBlockSizeException e) {
    		         e.printStackTrace();
    		      } catch (BadPaddingException e) {
    		         e.printStackTrace();
    		      } catch (UnsupportedEncodingException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    
    		return returnValue;
    	}
    
    	private static byte[] hextoByteArray(String secureValue) {
    		
    		// 암호문이 null이거나 짝수가 아니면 암호문이 암호화 에러.
    		if(secureValue == null || secureValue.length()%2 != 0){
    			return new byte[]{};
    		}
    		
    		byte[] bytes = new byte[secureValue.length()/2];
    		
    		for(int i = 0; i < secureValue.length(); i+=2){
    			byte value = (byte)Integer.parseInt(secureValue.substring(i,i+2), 16);
    			bytes[(int)Math.floor(i/2)] = value;
    			
    		}
    		return bytes;
    	}
    
    }
    

    jsp에서 사용 예제

     

    필요 js 넣기

     

    www-cs-students.stanford.edu/~tjw/jsbn/

     


    [loginForm.jsp]

    <%@page import="java.util.Map"%>
    <%@page import="kr.or.ddit.utiles.CryptoGenerator"%>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%
    	// 요청할 때마다 공개키, 비밀키가 새로 만들어짐                                                                              세션에 계속 갱신
    	Map<String, String> publicKeyMap = CryptoGenerator.generatePairKey(session);
    	
    	//pageContext.setAttribute("publicKeyMap", publicKeyMap); 한거나 마찬가지?
    	
    	
    %>
    
    <c:url var ="loginCheckURL" value="/12/loginCheck.jsp"></c:url>
    <c:set var="publicKeyMap" value ="<%=publicKeyMap %>"></c:set> 
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" href="${pageContext.request.contextPath }/css/admin.css" type="text/css">
    <script type='text/javascript' src='http://code.jquery.com/jquery-latest.js'></script>
    <script type = "text/javascript" src ="${pageContext.request.contextPath}/js/common/validation.js "></script>
    <script type='text/javascript' src="${pageContext.request.contextPath }/js/common/cookieControl.js"></script>
     <script type ="text/javascript" src ="${pageContext.request.contextPath }/js/crypto/jsbn.js"></script>
     <script type ="text/javascript" src ="${pageContext.request.contextPath }/js/crypto/rsa.js"></script>
     <script type ="text/javascript" src ="${pageContext.request.contextPath }/js/crypto/prng4.js"></script>
     <script type ="text/javascript" src ="${pageContext.request.contextPath }/js/crypto/rng.js"></script>
    <title>회원관리 관리자 로그인</title>
    </head>
    <!-- 
    	자바스크립트 : RSA 암호화 알고리즘 처리
    				1. js 라이브러리
    					http://www-cs-students.stanford.edu/~tjw/jsbn/
    					jsbn.js, prng4.jg, rng.js, rsa,js 다운로드
    				2. WebContext 하위에 배치
    				3. 취득한 js파일 import 우선순위 (순서대로)
    				   3.1 jsbn.js
    				   3.2 rsa.js
    				   3.3 prng4.js
    				   3.4 rng.js
     -->
    
    <body>
    	<table width="770" border="0" align="center" cellpadding="0"
    		cellspacing="0" style="margin: 90px;">
    		<tr>
    			<td height="150" align="center"><img src="${pageContext.request.contextPath }/image/p_login.gif" /></td>
    		</tr>
    		<tr>
    			<td height="174"
    				style="background: url(${pageContext.request.contextPath }/image/login_bg.jpg); border: 1px solid #e3e3e3;">
    				<table width="100%" border="0" cellpadding="0" cellspacing="0">
    					<tr>
    						<td width="260" height="110" align="center"
    							style="border-right: 1px dotted #736357;">
    							<img src="${pageContext.request.contextPath }/image/logo.jpg" />
    						</td>
    						<td>
    							<table border="0" align="center" cellpadding="5"
    								cellspacing="0">
    								<tr>
    									<td><b>아이디</b></td>
    									<td><input type="text" name="mem_id" class="box" tabindex="3" height="18" /></td>
    									<td rowspan="2">
    										<img src="${pageContext.request.contextPath }/image/login.gif" class="loginBtn"/>
    									</td>
    								</tr>
    								<tr>
    									<td><b>패스워드</b></td>
    									<td><input type="password" name="mem_pass" class="box" tabindex="3" height="18" /></td>
    								</tr>
    								<tr>
    									<td colspan="3" align="right"><a href="">회원가입을 원하세요??</a></td>
    								</tr>
    							</table>
    						</td>
    					</tr>
    				</table>
    			</td>
    		</tr>
    	</table>
    </body>
    <script type = "text/javascript">
    	$(function(){
    		if('${!empty param.message}'){
    			alert("${param.message}");
    		}
    		
    		$('.loginBtn').click(function(){
    			var mem_id = $('input[name=mem_id]').val();
    			var mem_pass = $('input[name=mem_pass]').val();
    			
    			if(!mem_id.validationID()){
    				alert("아이디를 바르게 입력해주세요");
    				$('input[name=mem_id]').focus();
    				return false;
    			}
    			
    			if(!mem_pass.validationPWD()){
    				alert("비밀번호를 바르게 입력해주세요");
    				$('input[name=mem_pass]').focus();
    				return false;
    			}
    			 
    			var modulus = '${publicKeyMap["publicModulus"]}';
    			var exponent = '${publicKeyMap["publicExponent"]}';
    			
    			var rsaObject = new RSAKey();
    			rsaObject.setPublic(modulus,exponent);
    			
    			//평문을 암호문으로 바꾸기
    			var encryptID = rsaObject.encrypt($('input[name_mem_id]').val());
    			var encryptPWD = rsaObject.encrypt($('input[name_mem_pass]').val());
    			
       
                var $frm = $('<form action="${loginCheckURL}" method="post"></form>');
                var $inputID = $('<input type="hidden" value="' +encryptID+ '" name="mem_id" />');
                var $inputPWD = $('<input type="hidden" value="' +encryptPWD+ '" name="mem_pass" />');
                $frm.append($inputID);
                $frm.append($inputPWD);
                $(document.body).append($frm);
                $frm.submit();
    
    		});
    	});
    </script>
    </html>
    

     

    댓글

Designed by Tistory.