RSA 암호화 예제 2
RSA Util
1. Server : RSA키 생성 및 복호화 Util class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | package com.gt.board.util; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.RSAPublicKeySpec; import javax.crypto.Cipher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gt.board.vo.other.RSA; /** Client -> Server 데이터 전송간 암호화 기능을 담당 **/ public class RSAUtil { private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class); private KeyPairGenerator generator; private KeyFactory keyFactory; private KeyPair keyPair; private Cipher cipher; public RSAUtil() { try { generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(1024); keyFactory = KeyFactory.getInstance("RSA"); cipher = Cipher.getInstance("RSA"); } catch (Exception e) { logger.warn("RSAUtil 생성 실패.", e); } } /** 새로운 키값을 가진 RSA 생성 * @return vo.other.RSA **/ public RSA createRSA() { RSA rsa = null; try { keyPair = generator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); RSAPublicKeySpec publicSpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); String modulus = publicSpec.getModulus().toString(16); String exponent = publicSpec.getPublicExponent().toString(16); rsa = new RSA(privateKey, modulus, exponent); } catch (Exception e) { logger.warn("RSAUtil.createRSA()", e); } return rsa; } /** 개인키를 이용한 RSA 복호화 * @param privateKey session에 저장된 PrivateKey * @param encryptedText 암호화된 문자열 **/ public String getDecryptText(PrivateKey privateKey, String encryptedText) throws Exception { cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(hexToByteArray(encryptedText)); return new String(decryptedBytes, "UTF-8"); } // 16진수 문자열을 byte 배열로 변환 private byte[] hexToByteArray(String hex) { if (hex == null || hex.length() % 2 != 0) { return new byte[] {}; } byte[] bytes = new byte[hex.length() / 2]; for (int i = 0; i < hex.length(); i += 2) { byte value = (byte) Integer.parseInt(hex.substring(i, i + 2), 16); bytes[(int) Math.floor(i / 2)] = value; } return bytes; } } |
2. Server : RSA 개인키/공개키를 담는 VO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.gt.board.vo.other; import java.security.PrivateKey; public class RSA { private PrivateKey privateKey; private String modulus; private String exponent; public RSA() { } public RSA(PrivateKey privateKey, String modulus, String exponent) { this.privateKey = privateKey; this.modulus = modulus; this.exponent = exponent; } public PrivateKey getPrivateKey() { return privateKey; } public void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } public String getModulus() { return modulus; } public void setModulus(String modulus) { this.modulus = modulus; } public String getExponent() { return exponent; } public void setExponent(String exponent) { this.exponent = exponent; } } |
3. Server : Client의 로그인 페이지 요청시 키 발급 및 저장/전달
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 로그인 페이지 진입 @RequestMapping(value = "/login", method = RequestMethod.GET) public String loginForm(HttpSession session, Model model) { // RSA 키 생성 PrivateKey key = (PrivateKey) session.getAttribute("RSAprivateKey"); if (key != null) { // 기존 key 파기 session.removeAttribute("RSAprivateKey"); } RSA rsa = rsaUtil.createRSA(); model.addAttribute("modulus", rsa.getModulus()); model.addAttribute("exponent", rsa.getExponent()); session.setAttribute("RSAprivateKey", rsa.getPrivateKey()); return "login"; } |
4. Client : Server로부터 받은 공개키를 이용하여 parameter를 암호화 후 submit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <!-- 유저가 입력하는 form --> <form action="/login" method="post" id="loginForm"> <fieldset> <legend class="screen_out">로그인 폼</legend> <label for="email">이메일</label> <input type="text" id="email" name="email" autofocus autocomplete="off" required /> <label for="password">비밀번호</label> <input type="password" id="password" name="password" autocomplete="off" required /> <button type="submit"> <i class="fa fa-sign-in"></i> 로그인 </button> </fieldset> </form> <!-- 실제 서버로 전송되는 form --> <form action="/login" method="post" id="hiddenForm"> <fieldset> <input type="hidden" name="email" /> <input type="hidden" name="password" /> </fieldset> </form> <!-- javascript lib load --> <script src="/resources/js/jquery.min.js"></script> <script src="/resources/js/rsa/jsbn.js"></script> <script src="/resources/js/rsa/prng4.js"></script> <script src="/resources/js/rsa/rng.js"></script> <script src="/resources/js/rsa/rsa.js"></script> <!-- 유저 입력 form의 submit event 재정의 --> <script> var $email = $("#hiddenForm input[name='email']"); var $password = $("#hiddenForm input[name='password']"); // Server로부터 받은 공개키 입력 var rsa = new RSAKey(); rsa.setPublic("${modulus}", "${exponent}"); $("#loginForm").submit(function(e) { // 실제 유저 입력 form은 event 취소 // javascript가 작동되지 않는 환경에서는 유저 입력 form이 submit 됨 // -> Server 측에서 검증되므로 로그인 불가 e.preventDefault(); // 아이디/비밀번호 암호화 후 hidden form으로 submit var email = $(this).find("#email").val(); var password = $(this).find("#password").val(); $email.val(rsa.encrypt(email)); // 아이디 암호화 $password.val(rsa.encrypt(password)); // 비밀번호 암호화 $("#hiddenForm").submit(); }); </script> |
5. Server : Client로부터 받은 암호화된 아이디/비밀번호 복호화 후 로그인 로직 실행
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 로그인 처리 @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(User user, HttpSession session, RedirectAttributes ra) { // 개인키 취득 PrivateKey key = (PrivateKey) session.getAttribute("RSAprivateKey"); if (key == null) { ra.addFlashAttribute("resultMsg", "비정상 적인 접근 입니다."); return "redirect:/login"; } // session에 저장된 개인키 초기화 session.removeAttribute("RSAprivateKey"); // 아이디/비밀번호 복호화 try { String email = rsaUtil.getDecryptText(key, user.getEmail()); String password = rsaUtil.getDecryptText(key, user.getPassword()); // 복호화된 평문을 재설정 user.setEmail(email); user.setPassword(password); } catch (Exception e) { ra.addFlashAttribute("resultMsg", "비정상 적인 접근 입니다."); return "redirect:/login"; } // 로그인 로직 실행 // userService.login(user); } |
'프로그래밍 > Spring' 카테고리의 다른 글
mybatis 빈설정 (0) | 2018.07.14 |
---|---|
로그인 예제 (0) | 2018.07.13 |
File 읽고 데이터 삽입하기 예제 (0) | 2018.07.05 |
예제 프로젝트 만들기 (0) | 2018.06.27 |
스프링 MVC : 기본기 1.1 메이븐 웹 프로젝트 생성 및 설정 (0) | 2018.01.23 |
TAGS.