IT

패스워드 기반 암호화(PBE : Password-Based Encryption)

 

1  설명

   가) 패스워드를 키로 사용하는 방법

   나) 키 스페이스가 TripleDES나 Blowfish보다 훨씬 작아 안전하지 못함

   다) 사전공격에 취약함

   라) 해쉬와 일반적인 대칭 암호화를 사용함

   마) 미리 패스워드 해쉬 목록을 만들어 놓고 복호화 할 수 있음

   바) salting와 iteration counts를 도입하여 보안성 강화

 

2  방법

   가) 패스워를 MD5로 해쉬를 구한 다음 이 값을 암호화 키 값으로 사용한다. 

 

3  Salt

   가) 패스워드를 해쉬하기 전에 랜덤값을 추가하여 키 스페이스를 늘린다.

   나) salt는 암호문과 함께 저장된다.

   다) 복호화할 때는 암호화된 데이터로부터 salt를 분리해야 한다.

   라) salt는 매번 다르게 생성되며 동일한 문장에 대해서도 다른 값이 생성된다.

 

4  Iteration count

   가) 해쉬의 횟수를 의미함

   나) Iteration count가 1000이면 1000번을 해쉬한다는 의미

 

5  암호화/복호화 방법

   가) 패스워드와 salt를 생성하여 보통문서를 암호화하고 생성된salt를 암호문서 앞에 붙인다.

 

   나) 암호화된 데이타를 salt와 암호문서로 나누어 패스워드와 salt로 암호 문서를 복호화 한다.

 

 

6  주요 클래스 사용법

   가) PBEKeySpec : SecretKeyFactory의 인스턴스를 이용해서 패스워드기반 키를 생성한다.

 char[] password = “iloveyou”.toCharArry();

PBEKeySpec keySpec = new PBEKeySpec(password)

 

   나) SecretKeyFactory : PBEKeySpec을 실제 키로 사용하기 위해 generateSecret()를 실행시켜 줘야 한다.

 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(“PBEWithShAAndTwoFish-CBC”);

SecretKey theKey = keyFactory.generateSecret(keySpec);

 

   다) PBEParameterSpec : salt와 interation count를 위한 레퍼런스

 PBEParameterSpec paramSpec = new PBEParameterSpec(salt, iterations);

Cipher cipher = Cipher.getInstance(“PBEWithShAAndTwoFish-CBC”);

Cipher.init(Cipher.ENCRYPT_MODE, theKey, paramSpec);

 

7  PBE 알고리즘

   가) PBEWithMD5AndDES 

   나) PBEWithSHAAndBlowfish

   다) PBEWithSHAAnd128BitRC4

   라) PBEWithSHAAndDEA-CBC

   마) PBEWithSHAAnd3-KeyTripleDES-CBC

 

8  PBE 예제

 

 import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.Ostermiller.util.Base64;

public class PBE {

 private static int ITERATIONS = 1000;
 
 public static void main(String[] args) {
  char[] password = "iloveyou".toCharArray();
  String text = "i love you! but you don't. i sad b.b";
  String output = null;
  
  System.out.println("평문 : " + text);
  try {
   output = encrypt(password, text);
   System.out.println("암호문 : " + output);
   System.out.println("복호문 : " + decrypt(password, output));
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private static String encrypt(char[] password, String plaintext) throws Exception {
  // 1. salt를 8byte 랜덤 생성
  byte[] salt = new byte[8];
  Random random = new Random();
  random.nextBytes(salt);
  
  // 2. 패스워드를 이용하여 PBEKeySpec 생성
  PBEKeySpec keySpec = new PBEKeySpec(password);
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwoFish-CBC");
  
  // 3. 비밀키 생성
  SecretKey key = keyFactory.generateSecret(keySpec);
  
  // 4. salt, iteration count를 위한 PBEParameterSpec 생성
  PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);
  
  // 5. Cipher 생성 및 초기화
  Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwoFish-CBC");
  cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
  
  // 6. 암호문 생성
  byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
  
  // 7. salt와 암호문을 Base64 인코딩 후 결합하여 최종 결과물 생성
  String saltString = Base64.encodeToString(salt);
  String ciphertextString = Base64.encodeToString(ciphertext);
  
  return saltString+ciphertextString;
  
 }
 
 private static String decrypt(char[] password, String text) throws Exception {
  
  // 1. 8byte를 Base64인코딩하면 12byte가 생성된다.
  String salt = text.substring(0, 12);
  String ciphertext = text.substring(12, text.length());
  
  // 2. salt와 암호문을 Base64 디코딩하여 원래 상태로 되돌린다.
  byte[] saltArry = Base64.decodeToBytes(salt);
  byte[] ciphertextArry = Base64.decodeToBytes(ciphertext);
  
  // 3. 패스워드를 이용하여 PBEKeySpec 생성
  PBEKeySpec keySpec = new PBEKeySpec(password);
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwoFish-CBC");
  
  // 4. 비밀 키 생성
  SecretKey key = keyFactory.generateSecret(keySpec);
  
  // 5. salt, iteration count를 위한 PBEParameterSpec 생성
  PBEParameterSpec paramSpec = new PBEParameterSpec(saltArry, ITERATIONS);
  
  // 6. Cipher 생성 및 초기화
  Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwoFish-CBC");
  cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
  
  // 7. 평문생성
  byte[] plaintextArry = cipher.doFinal(ciphertextArry);
  
  return new String(plaintextArry);
 }

}

Posted by sinpk