2012-06-08 2 views
1

웹 응용 프로그램이 있는데 원격 데이터베이스에 암호 해시를 저장하고 싶습니다. 암호 해시를 생성하는 간단한 클래스를 작성했습니다. 두 공공 방법을 사용할 수 있습니다 : 1. 암호화는 - 암호를 암호화 및 해시에게 2 checkpassword를을 생성 - 해시를 생성하는 암호화 호출, 두 개의 해시java SecretKeyFactory 암호 해싱이 제대로 작동하지 않습니다.

내가 두 암호 검사와 간단한 테스트를 만들어 비교, 하나는, 통과해야 다른 사람은해서는 안됩니다.

가끔은 효과적 일 때가 있습니다.

올바른 출력 :

password: abcdefg, hash: fd9927e15150bd01713115a761d1dea18b7da4aa 
password: abcdefg, salt: 3595ac1baff6aa5e0097520593c7ac74 
password: abcdefg, hash: fd9927e15150bd01713115a761d1dea18b7da4aa 
password: abcdefg, salt: 3595ac1baff6aa5e0097520593c7ac74 
passwords: abcdefg and abcdefg matched: true 
password: abcdefgh, hash: a64a2958f3999d8ecdeb03326a151e786435ea4 
password: abcdefgh, salt: 3595ac1baff6aa5e0097520593c7ac74 
passwords: abcdefg and abcdefgh matched: false 

잘못된 출력 :

password: abcdefg, hash: 4913fe5cdea3346690463f76f73c1336ae976674 
password: abcdefg, salt: 8e2aa1ec28d84fbaf78a6df260a7c707 
password: abcdefg, hash: 97abd26927bf96076019b932bf6ab5494a8b0979 
password: abcdefg, salt: 8e2aa1ec28d84fbaf78a6df260a7c707 
passwords: abcdefg and abcdefg matched: false 
password: abcdefgh, hash: 70594cd854bd60e07dfe14f72f01aa1f50de9aa2 
password: abcdefgh, salt: 8e2aa1ec28d84fbaf78a6df260a7c707 
passwords: abcdefg and abcdefgh matched: false 

출처 :

import java.math.BigInteger; 
import java.security.NoSuchAlgorithmException; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 
import java.util.Random; 

import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 

public class CryptoUtils { 

    /*************************************************************************** 
    * @param password 
    * 
    * @return String[2] { hashed password, salt } 
    * 
    * @throws NoSuchAlgorithmException 
    * @throws InvalidKeySpecException 
    ***************************************************************************/ 
    public static String[] encrypt(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     byte[] salt = new byte[16]; 
     new Random().nextBytes(salt); 

     return encrypt(password, salt); 
    } 

    private static String[] encrypt(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 2048, 160); 
     SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     byte[] hash = f.generateSecret(spec).getEncoded(); 

     String passHash = new BigInteger(1, hash).toString(16); 
     String saltString = new BigInteger(1, salt).toString(16); 

     System.out.println("password: " + password + ", hash: " + passHash);// DEBUG 
     System.out.println("password: " + password + ", salt: " + saltString); 

     return new String[] { passHash, saltString }; 
    } 

    public static boolean checkPassword(String password, String hash, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     String[] encrypted = encrypt(password, new BigInteger(salt, 16).toByteArray()); 

     return encrypted[0].equals(hash); 
    } 

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     String pass1 = "abcdefg"; 
     String pass2 = pass1; 
     String pass3 = pass1 + "h"; 

     String[] result = encrypt(pass1); 
     String hash = result[0]; 
     String salt = result[1]; 

     System.out.println("passwords: " + pass1 + " and " + pass2 + " matched: " + checkPassword(pass2, hash, salt)); 
     System.out.println("passwords: " + pass1 + " and " + pass3 + " matched: " + checkPassword(pass3, hash, salt)); 
    } 
} 

아무도 도와 드릴까요?

답변

2

문제는 염분 문자열을 BigInteger를 사용하여 바이트로 변환하는 것입니다. 소금 문자열이 음수이고 0 비트로 시작하지 않으면이 코드가 작동합니다. salt 문자열이 양수이면 BigInteger.toByteArray()는 시작 부분에 0 바이트를 더 추가하여 부호를 확장해야하므로 17 바이트 길이가됩니다. 또한 염분 문자열의 최상위 바이트가 0 인 경우 BigInteger.toByteArray()는이를 나타내는 데 16 바이트가 필요하지 않으므로 다시 소금 길이가 잘못됩니다. 항상 16 바이트를 포함하도록 BigInteger의 출력을 다시 포맷하는 로직을 작성할 수는 있지만 바이트 값을 직접 배열에 추가하여 한 번에 2 자의 입력 문자열을 간단히 파싱하는 것이 더 쉽습니다.

+0

덕분에 Base64.encode() 및 Base64.decode() 메소드를 사용 했으므로 도움이되었습니다. – xMichal

0

문제는 문자열에서 바이트 배열로 변환하는 것입니다. 이제 Base64.encode() 및 Base64.decode() 메서드를 사용하고 작동합니다.

import java.security.NoSuchAlgorithmException; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 
import java.util.Random; 

import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; 

public class CryptoUtils { 

    /*************************************************************************** 
    * @param password 
    * 
    * @return String[2] { hashed password, salt } 
    * 
    * @throws NoSuchAlgorithmException 
    * @throws InvalidKeySpecException 
    ***************************************************************************/ 
    public static String[] encrypt(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     byte[] salt = new byte[16]; 
     new Random().nextBytes(salt); 

     return encrypt(password, salt); 
    } 

    private static String[] encrypt(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 2048, 160); 
     SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     byte[] hash = f.generateSecret(spec).getEncoded(); 

     String passHash = Base64.encode(hash); 
     String saltString = Base64.encode(salt); 

     System.out.println("password: " + password + ", hash: " + passHash);// DEBUG 
     System.out.println("password: " + password + ", salt: " + saltString); 

     return new String[] { passHash, saltString }; 
    } 

    public static boolean checkPassword(String password, String hash, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     String[] encrypted = encrypt(password, Base64.decode(salt)); 

     return encrypted[0].equals(hash); 
    } 

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     String pass1 = "abcdefg"; 
     String pass2 = pass1; 
     String pass3 = pass1 + "h"; 

     String[] result = encrypt(pass1); 
     String hash = result[0]; 
     String salt = result[1]; 

     System.out.println("passwords: " + pass1 + " and " + pass2 + " matched: " + checkPassword(pass2, hash, salt)); 
     System.out.println("passwords: " + pass1 + " and " + pass3 + " matched: " + checkPassword(pass3, hash, salt)); 
    } 
} 
관련 문제