开发者社区 问答 正文

如何安全的存储用户密码三:hash源代码(java)

java PBKDF2 密码hash代码:


代码下载
  1. /*  
  2. * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
  3. * Copyright (c) 2013, Taylor Hornby
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without  
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice,  
  10. * this list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation  
  14. * and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE  
  20. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
  21. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
  22. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
  23. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
  24. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
  25. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
  26. * POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. import java.security.SecureRandom;
  29. import javax.crypto.spec.PBEKeySpec;
  30. import javax.crypto.SecretKeyFactory;
  31. import java.math.BigInteger;
  32. import java.security.NoSuchAlgorithmException;
  33. import java.security.spec.InvalidKeySpecException;
  34. /*
  35. * PBKDF2 salted password hashing.
  36. * Author: havoc AT defuse.ca
  37. * www: http://crackstation.net/hashing-security.htm
  38. */
  39. public class PasswordHash
  40. {
  41.     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
  42.     // The following constants may be changed without breaking existing hashes.
  43.     public static final int SALT_BYTE_SIZE = 24;
  44.     public static final int HASH_BYTE_SIZE = 24;
  45.     public static final int PBKDF2_ITERATIONS = 1000;
  46.     public static final int ITERATION_INDEX = 0;
  47.     public static final int SALT_INDEX = 1;
  48.     public static final int PBKDF2_INDEX = 2;
  49.     /**
  50.      * Returns a salted PBKDF2 hash of the password.
  51.      *
  52.      * @param   password    the password to hash
  53.      * @return              a salted PBKDF2 hash of the password
  54.      */
  55.     public static String createHash(String password)
  56.         throws NoSuchAlgorithmException, InvalidKeySpecException
  57.     {
  58.         return createHash(password.toCharArray());
  59.     }
  60.     /**
  61.      * Returns a salted PBKDF2 hash of the password.
  62.      *
  63.      * @param   password    the password to hash
  64.      * @return              a salted PBKDF2 hash of the password
  65.      */
  66.     public static String createHash(char[] password)
  67.         throws NoSuchAlgorithmException, InvalidKeySpecException
  68.     {
  69.         // Generate a random salt
  70.         SecureRandom random = new SecureRandom();
  71.         byte[] salt = new byte[SALT_BYTE_SIZE];
  72.         random.nextBytes(salt);
  73.         // Hash the password
  74.         byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
  75.         // format iterations:salt:hash
  76.         return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" +  toHex(hash);
  77.     }
  78.     /**
  79.      * Validates a password using a hash.
  80.      *
  81.      * @param   password        the password to check
  82.      * @param   correctHash     the hash of the valid password
  83.      * @return                  true if the password is correct, false if not
  84.      */
  85.     public static boolean validatePassword(String password, String correctHash)
  86.         throws NoSuchAlgorithmException, InvalidKeySpecException
  87.     {
  88.         return validatePassword(password.toCharArray(), correctHash);
  89.     }
  90.     /**
  91.      * Validates a password using a hash.
  92.      *
  93.      * @param   password        the password to check
  94.      * @param   correctHash     the hash of the valid password
  95.      * @return                  true if the password is correct, false if not
  96.      */
  97.     public static boolean validatePassword(char[] password, String correctHash)
  98.         throws NoSuchAlgorithmException, InvalidKeySpecException
  99.     {
  100.         // Decode the hash into its parameters
  101.         String[] params = correctHash.split(":");
  102.         int iterations = Integer.parseInt(params[ITERATION_INDEX]);
  103.         byte[] salt = fromHex(params[SALT_INDEX]);
  104.         byte[] hash = fromHex(params[PBKDF2_INDEX]);
  105.         // Compute the hash of the provided password, using the same salt,  
  106.         // iteration count, and hash length
  107.         byte[] testHash = pbkdf2(password, salt, iterations, hash.length);
  108.         // Compare the hashes in constant time. The password is correct if
  109.         // both hashes match.
  110.         return slowEquals(hash, testHash);
  111.     }
  112.     /**
  113.      * Compares two byte arrays in length-constant time. This comparison method
  114.      * is used so that password hashes cannot be extracted from an on-line  
  115.      * system using a timing attack and then attacked off-line.
  116.      *  
  117.      * @param   a       the first byte array
  118.      * @param   b       the second byte array  
  119.      * @return          true if both byte arrays are the same, false if not
  120.      */
  121.     private static boolean slowEquals(byte[] a, byte[] b)
  122.     {
  123.         int diff = a.length ^ b.length;
  124.         for(int i = 0; i < a.length && i < b.length; i++)
  125.             diff |= a ^ b;
  126.         return diff == 0;
  127.     }
  128.     /**
  129.      *  Computes the PBKDF2 hash of a password.
  130.      *
  131.      * @param   password    the password to hash.
  132.      * @param   salt        the salt
  133.      * @param   iterations  the iteration count (slowness factor)
  134.      * @param   bytes       the length of the hash to compute in bytes
  135.      * @return              the PBDKF2 hash of the password
  136.      */
  137.     private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
  138.         throws NoSuchAlgorithmException, InvalidKeySpecException
  139.     {
  140.         PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
  141.         SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
  142.         return skf.generateSecret(spec).getEncoded();
  143.     }
  144.     /**
  145.      * Converts a string of hexadecimal characters into a byte array.
  146.      *
  147.      * @param   hex         the hex string
  148.      * @return              the hex string decoded into a byte array
  149.      */
  150.     private static byte[] fromHex(String hex)
  151.     {
  152.         byte[] binary = new byte[hex.length() / 2];
  153.         for(int i = 0; i < binary.length; i++)
  154.         {
  155.             binary = (byte)Integer.parseInt(hex.substring(2*i, 2*i+2), 16);
  156.         }
  157.         return binary;
  158.     }
  159.     /**
  160.      * Converts a byte array into a hexadecimal string.
  161.      *
  162.      * @param   array       the byte array to convert
  163.      * @return              a length*2 character string encoding the byte array
  164.      */
  165.     private static String toHex(byte[] array)
  166.     {
  167.         BigInteger bi = new BigInteger(1, array);
  168.         String hex = bi.toString(16);
  169.         int paddingLength = (array.length * 2) - hex.length();
  170.         if(paddingLength > 0)
  171.             return String.format("%0" + paddingLength + "d", 0) + hex;
  172.         else
  173.             return hex;
  174.     }
  175.     /**
  176.      * Tests the basic functionality of the PasswordHash class
  177.      *
  178.      * @param   args        ignored
  179.      */
  180.     public static void main(String[] args)
  181.     {
  182.         try
  183.         {
  184.             // Print out 10 hashes
  185.             for(int i = 0; i < 10; i++)
  186.                 System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));
  187.             // Test password validation
  188.             boolean failure = false;
  189.             System.out.println("Running tests...");
  190.             for(int i = 0; i < 100; i++)
  191.             {
  192.                 String password = ""+i;
  193.                 String hash = createHash(password);
  194.                 String secondHash = createHash(password);
  195.                 if(hash.equals(secondHash)) {
  196.                     System.out.println("FAILURE: TWO HASHES ARE EQUAL!");
  197.                     failure = true;
  198.                 }
  199.                 String wrongPassword = ""+(i+1);
  200.                 if(validatePassword(wrongPassword, hash)) {
  201.                     System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");
  202.                     failure = true;
  203.                 }
  204.                 if(!validatePassword(password, hash)) {
  205.                     System.out.println("FAILURE: GOOD PASSWORD NOT ACCEPTED!");
  206.                     failure = true;
  207.                 }
  208.             }
  209.             if(failure)
  210.                 System.out.println("TESTS FAILED!");
  211.             else
  212.                 System.out.println("TESTS PASSED!");
  213.         }
  214.         catch(Exception ex)
  215.         {
  216.             System.out.println("ERROR: " + ex);
  217.         }
  218.     }
  219. }


附Php,Java,C#的Hash代码:



如何安全的存储用户的密码一:常见攻击方法




如何安全的存储用户密码二:加密源代码(php)



如何安全的存储用户的密码四:hash源代码(c#)



展开
收起
千鸟 2014-07-02 15:59:19 11047 分享 版权
1 条回答
写回答
取消 提交回答
  • 您的帖子很精彩!希望很快能再分享您的下一帖!
    2014-07-03 14:02:20
    赞同 展开评论