[java] RSA 로그인 암호화, 복호화

Yuni·2023년 2월 22일
0

RSA

목록 보기
1/1

3일을 고생한 RSA !! -> 간단한 원리를 알면 고생할 필요가 없었다 ^^....

LoginController

@Controller
public class LoginController {
	// 아이디 암호화
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String Login(HttpSession session, HttpServletRequest request, HttpServletResponse response, Model model)
			throws Exception, NoSuchAlgorithmException {
		
		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
		generator.initialize(2048); 

		KeyPair keyPair = generator.genKeyPair();
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");

		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();

		// 개인 키 생성 후 세션에 저장
		session.setAttribute("__rsaPrivateKey__", privateKey);

		// 공개키를 문자열로 변환
		RSAPublicKeySpec publicSpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);

		String publicKeyModulus = publicSpec.getModulus().toString(16);
		String publicKeyExponent = publicSpec.getPublicExponent().toString(16);

		// 로그인 폼 Input hidden 값 설정
		request.setAttribute("publicKeyModulus", publicKeyModulus);
		request.setAttribute("publicKeyExponent", publicKeyExponent);
		
		System.out.println("publicKeyModulus: "+publicKeyModulus);
		System.out.println("publicKeyExponent: "+publicKeyExponent);

		return "login/login"; // jsp
	}

	// 복호화 함수 정의
	private String decryptRsa(PrivateKey privateKey, String securedValue) throws Exception {
		logger.info("decryptRsa :");
		System.out.println("will decrypt : " + securedValue);
		Cipher cipher = Cipher.getInstance("RSA");
		byte[] encryptedBytes = hexToByteArray(securedValue);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
		String decryptedValue = new String(decryptedBytes, "utf-8"); // 문자 인코딩
		return decryptedValue;
	}

	// 16진수 문자열을 바이트 배열로 변환
	public static 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;
	}

	
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws Exception {
		logger.info("login start:");
		
		String securedUser_Id = (String) request.getParameter("securedUser_Id");
        String securedUser_Pwd = (String) request.getParameter("securedUser_Pwd");
        
        System.out.println("securedUser_Id: "+securedUser_Id.toString());
        System.out.println("securedUser_Pwd: "+securedUser_Pwd.toString());
 
		//세션에 저장된 개인키를 불러온다.
		PrivateKey privateKey = (PrivateKey) session.getAttribute("__rsaPrivateKey__");
		session.removeAttribute("__rsaPrivateKey__"); // 키 재사용 방지

		if (privateKey == null) {
			throw new RuntimeException("암호화 비밀키 정보를 찾을 수 없습니다.");
		}

		try {
			// 개인키로 데이터를 복호화한다.
			String id = decryptRsa(privateKey, securedUser_Id);
			String pwd = decryptRsa(privateKey, securedUser_Pwd);
			
			request.setAttribute("id", id);
			request.setAttribute("pwd", pwd);
			
			System.out.println("id: "+id);
			System.out.println("pwd: "+pwd);
			
		} catch (Exception ex) {
			throw new ServletException(ex.getMessage(), ex);

		}

		return "redirect:/"; //
	}
	
	
}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8" />
<title>로그인</title>
<!-- jquery + bootstrap-->
<script type="text/javascript" src="plugins/jquery/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="plugins/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="plugins/bootstrap/js/bootstrap.min.js">
<!-- css -->
<link rel="stylesheet" href="/css/login/login.css">
<!-- js -->
<script src="/js/login/login.js"></script>
<!-- 순서에 유의 -->
<script type="text/javascript" src="plugins/rsa/jsbn.js"></script>
<script type="text/javascript" src="plugins/rsa/rsa.js"></script>
<script type="text/javascript" src="plugins/rsa/prng4.js"></script>
<script type="text/javascript" src="plugins/rsa/rng.js"></script>
</head>
<body>
	<div class="login_all">
		<div class="login_menu">
        <a href="/"><img alt="logo" src="/images/logo.png" height="50" width="100"></a>
					<!-- 서버에서 전달받은 공개키를 hidden에 설정한다.  -->
					<input type="hidden" id="rsaPublicKeyModulus" value="${publicKeyModulus}" />
					<input type="hidden" id="rsaPublicKeyExponent" value="${publicKeyExponent}" />
					 
					<div>
						<label>ID</label>
						<input type="text" id="id" name="id" autocomplete="off" class="id_inp">
					</div>
					<div>
						<label>PW</label>
						<input type="password" id="pwd" name="pwd" autocomplete="off" class="pw_inp">
					</div>
					<div>
						<a class="btn btn-secondary" href="/login" onclick="validateRSA(); return false;">로그인</a>
						<!-- <button class="btn btn-secondary" type="button" onclick="callFuntion(login)">로그인</button> -->
					</div>
					
				<form id="frm" name="frm" method="post" action="/login">
					<input type="hidden" name="securedUser_Id" id="securedUser_Id"value="" />
					<input type="hidden" name="securedUser_Pwd" id="securedUser_Pwd" value="" />
				</form>
		</div>
	</div>
</body>
</html>

login.js

function validateRSA() {
		
			var id = document.getElementById("id").value;
			var pwd = document.getElementById("pwd").value;
			
			try {

			    var rsa = new RSAKey();
				rsa.setPublic($('#rsaPublicKeyModulus').val(), $('#rsaPublicKeyExponent').val());
			
			    // 사용자ID, 비밀번호를 RSA로 암호화
			    var securedUser_Id = rsa.encrypt(id);
			    var securedUser_Pwd = rsa.encrypt(pwd);
			
			    var frm = document.getElementById("frm");
			    frm.securedUser_Id.value = securedUser_Id;
			    frm.securedUser_Pwd.value = securedUser_Pwd;
			    frm.submit();           
			    
			} catch(e) {
			    alert(e);
			}
		}

login.css

.login_all {
	display: flex;
	justify-content: center;
	align-items: center;
	min-height: 100vh;
}

.login_menu {
	text-align: center;
	margin-bottom: 12%;
}

.id_inp {
	margin-left: 18px;
	width: 86%;
	text-align: center;
}

.pw_inp {
	margin-left: 9px;
	width: 86%;
	text-align: center;
}

.btn-secondary {
	width: 100%;
	margin-top: 3px;
	margin-bottom: 1px;
}

.user_bt {
	margin-right: 5px;
}

.user_bt>button {
	background: none;
	border: none;
}

.user_bt>button:hover {
	color: #8d8d8d;
}

.user_bt>button:active {
	color: #4e4e4e;
}

git code
https://github.com/yunsser/RSA-example

출처:
https://mylife365.tistory.com/501
https://jdh5202.tistory.com/766#google_vignette

profile
backend developers

0개의 댓글