暗号化(一方向、双方向)/復号化
14930 ワード
CryptoTest
package kr.or.ddit.basic;
import kr.or.ddit.util.CryptoUtil;
public class CryptoTest {
public static void main(String[] args) throws Exception {
String sourceText = "Hello, World! 가나다라 12345 !@#$%";
String key = "a1b2c3d4e5f6g7h8"; // 키값은 사용자가 임의로 정해서 사용한다.
System.out.println("단방향 암호화");
System.out.println("SHA-512방식: "+ CryptoUtil.sha512(sourceText));
System.out.println();
System.out.println("양방향 암호화");
String encryStr = CryptoUtil.encryptAES256(sourceText, key);
System.out.println("원본 데이터: " + sourceText);
System.out.println("암호화한 데이터: "+ encryStr);
String decryptStr = CryptoUtil.decryptAES256(encryStr, key);
System.out.println("복호화한 데이터 : "+ decryptStr);
}
}
CryptoUtilpackage kr.or.ddit.util;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoUtil {
/**
* 인수값의 문자열을 SHA-512방식으로 암호화하는 메서드
* (단방향 암호화)
* @param str 암호화할 문자열 데이터
* @return 암호화된 문자열 데이터
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String sha512(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 암호화에 사용할 알고리즘을 지정하여 MessageDigest객체 생성. 예외발생해서 예외처리
// 알고리즘은 문자열로 지정하는데 다음과 같은 종류가 있다.
// "MD5", "SHA-256" 등
MessageDigest md = MessageDigest.getInstance("SHA-512");
// 암호화할 데이터를 byte형 배열로 넣어준다. 예외발생해서 예외처리
md.update(str.getBytes("utf-8"));
// md.digest() : 암호화된 데이터를 byte배열로 반환한다.
return Base64.getEncoder().encodeToString(md.digest());
}
/**
* 양방향 암호화 중 AES-256 알고리즘으로 암호화하는 메서드
*
* @param str 암호화할 문자열
* @param key 암호화에 사용할 암호키 문자열(16자 이상)
* @return 암호화된 문자열
* @throws UnsupportedEncodingException
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String encryptAES256(String str, String key) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
if(key.length()<16) {
System.out.println("암호키는 16자 이상으로 지정하세요");
System.out.println("작업을 마칩니다");
return null;
}
byte[] keyBytes = new byte[16];
System.arraycopy(key.getBytes("utf-8"), 0, keyBytes, 0, keyBytes.length);
//비밀키 생성 (키에 사용할 byte형 배열과 알고리즘 이름을 지정한다.)
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
// Cipher 객체 생성 및 초기화 (예외처리)
/*
알고리즘/모드/패딩 (AES/CBC/PKCS5Padding)
- CBC(Cipher Block Chaining Mode) : 동일한 평문 블록과 암호문 블록의 쌍이 발생하지 않도록 이전단계의 암복호화한 결과를
현 단계에 사용하는 모드를 말한다.
- Padding : CBC에서 작업을할 때 마지막 블록이 블록의 길이가 부족할 때 부족한 부분을 채워넣는 방식을 말한다.
*/
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 초기화 벡터값 작성
// 초기화 벡터(Initial Vector, IV) - 암호문이 패턴화되지 않도록 사용하는 데이터를 말한다.
// 암호화 처리중 첫번째 블록은 암호화할 때 사용되는 값이다.
String iv = key.substring(0, 16);
byte[] ivBytes = new byte[16];
System.arraycopy(iv.getBytes("utf-8"), 0, ivBytes, 0, ivBytes.length);
// 암호를 옵션 종류에 맞게 초기화한다.
// 옵션 종류: ENCRYPT_MODE(암호화모드), DECRYP_MODE(복호화모드)
c.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));
// 암호하할 데이터를 byte형 배열로 공급하여 암호화 작업을 수행한다.
byte[] encryptBytes = c.doFinal(str.getBytes("utf-8"));
String enStr = Base64.getEncoder().encodeToString(encryptBytes);
return enStr;
}
/**
* 암호화된 데이터를 인수값으로 받아서 원래의 내용으로 복호화하는 메서드
* @param str 복원한 암호화된 문자열
* @param key 암호키 문자열
* @return 복원된 원래의 문자열
* @throws UnsupportedEncodingException
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decryptAES256(String str, String key) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
if(key.length()<16) {
System.out.println("암호키는 16자 이상으로 지정하세요");
System.out.println("작업을 마칩니다");
return null;
}
byte[] keyBytes = new byte[16];
System.arraycopy(key.getBytes("utf-8"), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
String iv = key.substring(0, 16);
byte[] ivBytes = new byte[16];
System.arraycopy(iv.getBytes("utf-8"), 0, ivBytes, 0, ivBytes.length);
c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));
// 복원할 암호화된 문자열을 decoding한 byte형 배열을 구한다.
byte[] byteStr = Base64.getDecoder().decode(str);
// 암호화된 byte 배열을 원래의 데이터로 복원한 후 문자열로 변환하여 반환한다.
return new String(c.doFinal(byteStr), "utf-8");
}
}
MemberControllerpackage kr.or.ddit.mvc.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import kr.or.ddit.mvc.service.MemberServiceImpl;
import kr.or.ddit.mvc.vo.MemberVO;
import kr.or.ddit.util.CryptoUtil;
public class MemberController {
private Scanner sc;
/* private IMemberService service; // service 객체 변수 선언
*/ private MemberServiceImpl service;
//생성자
public MemberController() {
sc = new Scanner(System.in);
service = MemberServiceImpl.getInstance();
}
public static void main(String[] args) throws Exception {
new MemberController().memberStart();
}
private int displayMenu() {
System.out.println("==작업선택==");
System.out.println("1.자료추가 2.자료삭제 3.자료수정4.전체자료출력 5. 자료수정2 0.작업끝");
System.out.print("선택>");
int input=sc.nextInt();
sc.nextLine();
return input;
}
public void memberStart() throws Exception{
while(true){
int choice = displayMenu();
switch(choice){
case 1: insertMember(); break; //추가
case 2: deleteMember();break; //삭제
case 3: updateMember(); break; //수정 (아이디제외 전체 항목 수정)
case 4: displayMember(); break; //전체자료 출력
case 5 : updateMember2(); break; // (원하는 항목만 수정)
case 0: System.out.println("프로그램을 종료합니다."); //종료
return;
default : System.out.println("번호를잘못입력했습니다. 다시 입력하세요");
}
}
}
static String key = "a1b2c3d4e5f6g7h8"; // 키값은 사용자가 임의로 정해서 사용한다.
private void insertMember() throws Exception {
System.out.println("추가할 회원 정보를 입력하세요");
int count =0;
String id = ""; //String memId = null;
String sourceText = "";
do{
System.out.println("mem_id를 입력하세요");
id = sc.nextLine();
sourceText = id;
String encryStr = CryptoUtil.encryptAES256(sourceText, key);
id = encryStr;
count = service.getMemberCount(id);
if(count>0){
System.out.println(CryptoUtil.decryptAES256(encryStr, key) + "은(는) 이미 등록된 회원 ID입니다.");
System.out.println("다른 회원 ID를 입력하세요");
}
}while(count>0);
System.out.println("mem_name를 입력해주세요");
String name = sc.nextLine();
System.out.println("mem_pass를 입력해주세요");
String pass = sc.nextLine();
sourceText = pass;
pass = CryptoUtil.sha512(sourceText);
System.out.println("mem_tel를 입력해주세요");
String tel = sc.nextLine();
System.out.println("mem_addr를 입력해주세요");
String addr = sc.nextLine();
// 입력받는 데이터들을 VO객체에 저장한다.
MemberVO memVo = new MemberVO();
memVo.setMem_id(id);
memVo.setMem_name(name);
memVo.setMem_pass(pass);
memVo.setMem_tel(tel);
memVo.setMem_addr(addr);
int cnt = service.insertMember(memVo);
if(cnt>0){
System.out.println("insert 성공");
}else{
System.out.println("insert 실패");
}
}
private void deleteMember() {
System.out.println("삭제할 회원 정보를 입력하세요");
System.out.println("삭제할 mem_id를 입력해주세요 ");
String id = sc.nextLine();
int cnt = service.deleteMember(id);
if(cnt>0){
System.out.println("delete 성공");
}else{
System.out.println("delete 실패");
}
}
private void updateMember() {
System.out.println("수정할 회원 정보를 입력하세요");
System.out.println("수정할 회원id: ");
String id = sc.nextLine();
int count = service.getMemberCount(id);
if(count==0){
System.out.println(id+"는 없는 회원 id");
return ;
}
System.out.println("수정할 mem_name를 입력해주세요");
String name = sc.nextLine();
System.out.println("수정할 mem_pass를 입력해주세요");
String pass = sc.nextLine();
System.out.println("수정할 mem_tel를 입력해주세요");
String tel = sc.nextLine();
System.out.println("수정할 mem_addr를 입력해주세요");
String addr = sc.nextLine();
MemberVO memVo = new MemberVO();
memVo.setMem_id(id);
memVo.setMem_name(name);
memVo.setMem_pass(pass);
memVo.setMem_tel(tel);
memVo.setMem_addr(addr);
int cnt = service.updateMember(memVo);
if(cnt>0){
System.out.println("update 성공");
}else{
System.out.println("update 실패");
}
}
private void updateMember2() {
System.out.println();
System.out.println("수정할 회원 정보를 입력하세요");
System.out.println("수정할 회원 id를 입력하세요");
String memId = sc.next();
int count = service.getMemberCount(memId);
if(count==0){
System.out.println(memId+"는 없는 회원 id");
return ;
}
int num ; // 수정할 컬럼에 대한 선택 값이 저장될 변수
String updateField = null;
String updateTitle = null;
do{
System.out.println();
System.out.println("수정할 항목을 선택하세요.");
System.out.println("1.회원이름 2.회원비밀번호 3.회원 전화번호 4.회원주소");
num = sc.nextInt();
sc.nextLine();
switch(num){
case 1:
updateField = "mem_name";
updateTitle = "회원이름";
break;
case 2:
updateField = "mem_pass";
updateTitle = "비밀번호";
break;
case 3:
updateField = "mem_tel";
updateTitle = "회원전화번호";
break;
case 4:
updateField = "mem_addr";
updateTitle = "회원주소";
break;
default :
System.out.println("수정할 항목을 잘못 선택했습니다.");
System.out.println("다시 선택하세요");
}
}while(num<1 || num>4);
System.out.println("새로운 "+ updateTitle + ":");
String updateData = sc.nextLine();
// 수정 작업에 필요한 데이터들을 Map에 저장한다.
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("field", "updateField");
paramMap.put("data", "updateData");
paramMap.put("memId", "memId");
int cnt = service.updateMember2(paramMap);
if(cnt>0){
System.out.println("개별 정보 수정작업 성공");
}else{
System.out.println("개별 정보 수정 작업 실패");
}
}
private void displayMember() throws Exception {
List<MemberVO> cnt = service.getAllMember();
System.out.println("id name pass tel addr");
if(cnt==null || cnt.size()==0){
System.out.println("출력할 회원정보가 없습니다.");
}else{
for(MemberVO memVo : cnt){
String decryptStr = CryptoUtil.decryptAES256(memVo.getMem_id(), key);
System.out.print(decryptStr+"\t");
System.out.print(memVo.getMem_name()+"\t");
System.out.print(memVo.getMem_pass()+"\t");
System.out.print(memVo.getMem_tel()+"\t");
System.out.println(memVo.getMem_addr());
}
}
}
}
Reference
この問題について(暗号化(一方向、双方向)/復号化), 我々は、より多くの情報をここで見つけました https://velog.io/@susan9905/암호화단방향-양방향-복호화テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol