'SALT'에 해당되는 글 2건

  1. 2015.11.05 MessageDigest
  2. 2015.11.05 패스워드 기반 암호화

MessageDigest

UP!/Crypto 2015. 11. 5. 10:58

자세한 내용을 알고 싶은 분은 다음의 블로그를 참조하세요

http://blog.naver.com/dury00?Redirect=Log&logNo=130044978311

 

     내용

가)    일종의 데이터 지문

나)    데이터가 바뀌지 않았다는 것을 증명

다)    데이터의 길이에 상관없이 보통 16 또는 20byte

라)    FTP파일 검증에 많이 사용

마)    해쉬를 이용

바)    한 방향 변환이고 역으로는 불가능

 

     자바에서의 메시지 다이제스트 사용

가)    java.security.MessageDigest

     getInstance()로 인자 생성

     MD5, SHA-1이 주로 사용됨

 

나)    update()

     데이터를 해쉬 함

 

다)    digest()

     바이트 배열로 해쉬를 반환

     적은 데이터일 경우 digest에 직접 입력 가능

 

라)    파일의 메시지 다이제스트 계산

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.io.IOException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

 

import com.Ostermiller.util.Base64;

 

public class DigestFile {

 

       public static void main(String[] args) throws NoSuchAlgorithmException, IOException {

             MessageDigest md = MessageDigest.getInstance("MD5");

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             int theByte = 0;

             while((theByte = in.read()) != -1)

                    md.update((byte)theByte);

            

             in.close();

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

 

       }

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 마)    실행결과

     test.txt 파일에는 ‘this is a test file’이 들어 있음 : [B@1a758

     ‘this is a test file.’로 수정한 결과 : [B@1b67f74

 

바)    스트림에서의 메시지 다이제스트

     DigestInputStream & DigestOutputStream

MessageDigest messageDigest = MessageDigest.getInstance(“MD5”);

DigestOutputStream output = new

DigestOutputStream(existingOutputStream, messageDigest);

 

     출력에 쓰는 모든 바이트가 자동으로 메시지 다이제스트를 계산할 때 사용됨

     예제

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.security.DigestInputStream;

import java.security.MessageDigest;

 

import com.Ostermiller.util.Base64;

 

public class DigestStreamExample {

 

       public static void main(String[] args) throws Exception{

             MessageDigest md = MessageDigest.getInstance("MD5");

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             //DigestInputStream 생성한다.

             DigestInputStream digestIn = new DigestInputStream(in, md);

             // 모든 데이터를 읽어들인다.

             while(digestIn.read() != -1);

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

       }

}

 

 

     패스워드 인증

가)    의미

     패스워드를 해쉬하여 저장할 경우 복호화는 불가능하지만 모든 가능한 패스워드를 해쉬한 다음 비교해서 추즉하는게 가능함

     이런 공격을 막기 위해 salt와 패스워드를 같이 저장해야 함

     서버가 실제 패스워드를 알 필요 없이 사용자가 정한 패스워드를 검증하는게 목적

 

 

나)    패스워드 저장

     랜덤 salt 생성하여 패스워드 앞에 붙임

     이것을 해쉬함

     패스워드 입력될 때마다 비교를 위해 salt와 해쉬 결과를 붙여서 저장

 

 

다)    패스워드 인증

     저장된 패스워드의 salt와 사용자가 입력한 패스워드를 합친다.

     salt와 패스워드를 해쉬한다.

     결과 해쉬값을 파일에 저장된 것을 비교한다. 같다면 패스워드가 같은 것이다.

 

라)    예제

import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.security.MessageDigest;

import java.security.SecureRandom;

import java.util.Arrays;

 

public class Passwordauthenticator {

 

       public static void main(String[] args) throws Exception{

             createPassword("iloveyou");

             authenticatePassword("iloveyou");

 

       }

      

       private static void createPassword(String password) throws Exception {

             // salt 생성

             SecureRandom random = new SecureRandom();

             byte[] salt = new byte[12];

             random.nextBytes(salt);

            

             // salt 패스워드를 붙여서 해쉬한다.

             MessageDigest md = MessageDigest.getInstance("MD5");

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

             byte[] digest = md.digest();

            

             // salt 해쉬 결과를 파일에 저장한다.

             FileOutputStream fos = new FileOutputStream("c:\\password.txt");

             fos.write(salt);

             fos.write(digest);

             fos.close();

       }

      

       private static void authenticatePassword(String password) throws Exception {

             // 파일을 읽어들인다.

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             FileInputStream fis = new FileInputStream("c:\\password.txt");

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.write(theByte);

             fis.close();

             byte[] hashedPasswordWithSalt = baos.toByteArray();

             baos.reset();

            

             //salt 얻는다.

             byte[] salt = new byte[12];

             System.arraycopy(hashedPasswordWithSalt, 0, salt, 0, 12);

            

             // salt 입력한 패스워드를 붙여서 해쉬한다.

             MessageDigest md = MessageDigest.getInstance("MD5");

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

              byte[] digest = md.digest();

            

             // 파일에 있는 내용과 비교한다.

             byte[] digestInFile = new byte[hashedPasswordWithSalt.length-12];

             System.arraycopy(hashedPasswordWithSalt, 12, digestInFile, 0, hashedPasswordWithSalt.length-12);

            

             if(Arrays.equals(digest, digestInFile))

                    System.out.println("Password matches.");

             else

                    System.out.println("Password does not matches.");

       }

}

 

'UP! > Crypto' 카테고리의 다른 글

MAC  (0) 2015.11.05
Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
Posted by 으랏차
,

패스워드 기반 암호화(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);
 }

}

 

 

'UP! > Crypto' 카테고리의 다른 글

Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
대칭 비대칭 암호화  (0) 2015.11.05
Posted by 으랏차
,