暗号化(一方向、双方向)/復号化

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);
      
      
   }

}
CryptoUtil
package 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");
         
      }
      
}
MemberController
package 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());
            
            }
         }
         
         
         
      
   }
   
   
   

}