如何安全的存储用户密码?(中)代码篇
PHP PBKDF2?密碼hash代碼
<?php
/*
?*?Password?Hashing?With?PBKDF2?(http://crackstation.net/hashing-security.htm).
?*?Copyright?(c)?2013,?Taylor?Hornby
?*?All?rights?reserved.
?*
?*?Redistribution?and?use?in?source?and?binary?forms,?with?or?without?
?*?modification,?are?permitted?provided?that?the?following?conditions?are?met:
?*
?*?1.?Redistributions?of?source?code?must?retain?the?above?copyright?notice,?
?*?this?list?of?conditions?and?the?following?disclaimer.
?*
?*?2.?Redistributions?in?binary?form?must?reproduce?the?above?copyright?notice,
?*?this?list?of?conditions?and?the?following?disclaimer?in?the?documentation?
?*?and/or?other?materials?provided?with?the?distribution.
?*
?*?THIS?SOFTWARE?IS?PROVIDED?BY?THE?COPYRIGHT?HOLDERS?AND?CONTRIBUTORS?"AS?IS"?
?*?AND?ANY?EXPRESS?OR?IMPLIED?WARRANTIES,?INCLUDING,?BUT?NOT?LIMITED?TO,?THE?
?*?IMPLIED?WARRANTIES?OF?MERCHANTABILITY?AND?FITNESS?FOR?A?PARTICULAR?PURPOSE?
?*?ARE?DISCLAIMED.?IN?NO?EVENT?SHALL?THE?COPYRIGHT?HOLDER?OR?CONTRIBUTORS?BE?
?*?LIABLE?FOR?ANY?DIRECT,?INDIRECT,?INCIDENTAL,?SPECIAL,?EXEMPLARY,?OR?
?*?CONSEQUENTIAL?DAMAGES?(INCLUDING,?BUT?NOT?LIMITED?TO,?PROCUREMENT?OF?
?*?SUBSTITUTE?GOODS?OR?SERVICES;?LOSS?OF?USE,?DATA,?OR?PROFITS;?OR?BUSINESS?
?*?INTERRUPTION)?HOWEVER?CAUSED?AND?ON?ANY?THEORY?OF?LIABILITY,?WHETHER?IN?
?*?CONTRACT,?STRICT?LIABILITY,?OR?TORT?(INCLUDING?NEGLIGENCE?OR?OTHERWISE)?
?*?ARISING?IN?ANY?WAY?OUT?OF?THE?USE?OF?THIS?SOFTWARE,?EVEN?IF?ADVISED?OF?THE?
?*?POSSIBILITY?OF?SUCH?DAMAGE.
?*/
//?These?constants?may?be?changed?without?breaking?existing?hashes.
define("PBKDF2_HASH_ALGORITHM",?"sha256");
define("PBKDF2_ITERATIONS",?1000);
define("PBKDF2_SALT_BYTE_SIZE",?24);
define("PBKDF2_HASH_BYTE_SIZE",?24);
define("HASH_SECTIONS",?4);
define("HASH_ALGORITHM_INDEX",?0);
define("HASH_ITERATION_INDEX",?1);
define("HASH_SALT_INDEX",?2);
define("HASH_PBKDF2_INDEX",?3);
function?create_hash($password)
{
????//?format:?algorithm:iterations:salt:hash
????$salt?=?base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE,?MCRYPT_DEV_URANDOM));
????return?PBKDF2_HASH_ALGORITHM?.?":"?.?PBKDF2_ITERATIONS?.?":"?.??$salt?.?":"?.
????????base64_encode(pbkdf2(
????????????PBKDF2_HASH_ALGORITHM,
????????????$password,
????????????$salt,
????????????PBKDF2_ITERATIONS,
????????????PBKDF2_HASH_BYTE_SIZE,
????????????true
????????));
}
function?validate_password($password,?$correct_hash)
{
????$params?=?explode(":",?$correct_hash);
????if(count($params)?<?HASH_SECTIONS)
???????return?false;
????$pbkdf2?=?base64_decode($params[HASH_PBKDF2_INDEX]);
????return?slow_equals(
????????$pbkdf2,
????????pbkdf2(
????????????$params[HASH_ALGORITHM_INDEX],
????????????$password,
????????????$params[HASH_SALT_INDEX],
????????????(int)$params[HASH_ITERATION_INDEX],
????????????strlen($pbkdf2),
????????????true
????????)
????);
}
//?Compares?two?strings?$a?and?$b?in?length-constant?time.
function?slow_equals($a,?$b)
{
????$diff?=?strlen($a)?^?strlen($b);
????for($i?=?0;?$i?<?strlen($a)?&&?$i?<?strlen($b);?$i++)
????{
????????$diff?|=?ord($a[$i])?^?ord($b[$i]);
????}
????return?$diff?===?0;
}
/*
?*?PBKDF2?key?derivation?function?as?defined?by?RSA's?PKCS?#5:?https://www.ietf.org/rfc/rfc2898.txt
?*?$algorithm?-?The?hash?algorithm?to?use.?Recommended:?SHA256
?*?$password?-?The?password.
?*?$salt?-?A?salt?that?is?unique?to?the?password.
?*?$count?-?Iteration?count.?Higher?is?better,?but?slower.?Recommended:?At?least?1000.
?*?$key_length?-?The?length?of?the?derived?key?in?bytes.
?*?$raw_output?-?If?true,?the?key?is?returned?in?raw?binary?format.?Hex?encoded?otherwise.
?*?Returns:?A?$key_length-byte?key?derived?from?the?password?and?salt.
?*
?*?Test?vectors?can?be?found?here:?https://www.ietf.org/rfc/rfc6070.txt
?*
?*?This?implementation?of?PBKDF2?was?originally?created?by?https://defuse.ca
?*?With?improvements?by?http://www.variations-of-shadow.com
?*/
function?pbkdf2($algorithm,?$password,?$salt,?$count,?$key_length,?$raw_output?=?false)
{
????$algorithm?=?strtolower($algorithm);
????if(!in_array($algorithm,?hash_algos(),?true))
????????trigger_error('PBKDF2?ERROR:?Invalid?hash?algorithm.',?E_USER_ERROR);
????if($count?<=?0?||?$key_length?<=?0)
????????trigger_error('PBKDF2?ERROR:?Invalid?parameters.',?E_USER_ERROR);
????if?(function_exists("hash_pbkdf2"))?{
????????//?The?output?length?is?in?NIBBLES?(4-bits)?if?$raw_output?is?false!
????????if?(!$raw_output)?{
????????????$key_length?=?$key_length?*?2;
????????}
????????return?hash_pbkdf2($algorithm,?$password,?$salt,?$count,?$key_length,?$raw_output);
????}
????$hash_length?=?strlen(hash($algorithm,?"",?true));
????$block_count?=?ceil($key_length?/?$hash_length);
????$output?=?"";
????for($i?=?1;?$i?<=?$block_count;?$i++)?{
????????//?$i?encoded?as?4?bytes,?big?endian.
????????$last?=?$salt?.?pack("N",?$i);
????????//?first?iteration
????????$last?=?$xorsum?=?hash_hmac($algorithm,?$last,?$password,?true);
????????//?perform?the?other?$count?-?1?iterations
????????for?($j?=?1;?$j?<?$count;?$j++)?{
????????????$xorsum?^=?($last?=?hash_hmac($algorithm,?$last,?$password,?true));
????????}
????????$output?.=?$xorsum;
????}
????if($raw_output)
????????return?substr($output,?0,?$key_length);
????else
????????return?bin2hex(substr($output,?0,?$key_length));
}
?>
java PBKDF2?密碼hash代碼
/*?
?*?Password?Hashing?With?PBKDF2?(http://crackstation.net/hashing-security.htm).
?*?Copyright?(c)?2013,?Taylor?Hornby
?*?All?rights?reserved.
?*
?*?Redistribution?and?use?in?source?and?binary?forms,?with?or?without?
?*?modification,?are?permitted?provided?that?the?following?conditions?are?met:
?*
?*?1.?Redistributions?of?source?code?must?retain?the?above?copyright?notice,?
?*?this?list?of?conditions?and?the?following?disclaimer.
?*
?*?2.?Redistributions?in?binary?form?must?reproduce?the?above?copyright?notice,
?*?this?list?of?conditions?and?the?following?disclaimer?in?the?documentation?
?*?and/or?other?materials?provided?with?the?distribution.
?*
?*?THIS?SOFTWARE?IS?PROVIDED?BY?THE?COPYRIGHT?HOLDERS?AND?CONTRIBUTORS?"AS?IS"?
?*?AND?ANY?EXPRESS?OR?IMPLIED?WARRANTIES,?INCLUDING,?BUT?NOT?LIMITED?TO,?THE?
?*?IMPLIED?WARRANTIES?OF?MERCHANTABILITY?AND?FITNESS?FOR?A?PARTICULAR?PURPOSE?
?*?ARE?DISCLAIMED.?IN?NO?EVENT?SHALL?THE?COPYRIGHT?HOLDER?OR?CONTRIBUTORS?BE?
?*?LIABLE?FOR?ANY?DIRECT,?INDIRECT,?INCIDENTAL,?SPECIAL,?EXEMPLARY,?OR?
?*?CONSEQUENTIAL?DAMAGES?(INCLUDING,?BUT?NOT?LIMITED?TO,?PROCUREMENT?OF?
?*?SUBSTITUTE?GOODS?OR?SERVICES;?LOSS?OF?USE,?DATA,?OR?PROFITS;?OR?BUSINESS?
?*?INTERRUPTION)?HOWEVER?CAUSED?AND?ON?ANY?THEORY?OF?LIABILITY,?WHETHER?IN?
?*?CONTRACT,?STRICT?LIABILITY,?OR?TORT?(INCLUDING?NEGLIGENCE?OR?OTHERWISE)?
?*?ARISING?IN?ANY?WAY?OUT?OF?THE?USE?OF?THIS?SOFTWARE,?EVEN?IF?ADVISED?OF?THE?
?*?POSSIBILITY?OF?SUCH?DAMAGE.
?*/
?
import?java.security.SecureRandom;
import?javax.crypto.spec.PBEKeySpec;
import?javax.crypto.SecretKeyFactory;
import?java.math.BigInteger;
import?java.security.NoSuchAlgorithmException;
import?java.security.spec.InvalidKeySpecException;
?
/*
?*?PBKDF2?salted?password?hashing.
?*?Author:?havoc?AT?defuse.ca
?*?www:?http://crackstation.net/hashing-security.htm
?*/
public?class?PasswordHash
{
????public?static?final?String?PBKDF2_ALGORITHM?=?"PBKDF2WithHmacSHA1";
?
????//?The?following?constants?may?be?changed?without?breaking?existing?hashes.
????public?static?final?int?SALT_BYTE_SIZE?=?24;
????public?static?final?int?HASH_BYTE_SIZE?=?24;
????public?static?final?int?PBKDF2_ITERATIONS?=?1000;
?
????public?static?final?int?ITERATION_INDEX?=?0;
????public?static?final?int?SALT_INDEX?=?1;
????public?static?final?int?PBKDF2_INDEX?=?2;
?
????/**
?????*?Returns?a?salted?PBKDF2?hash?of?the?password.
?????*
?????*?@param???password????the?password?to?hash
?????*?@return??????????????a?salted?PBKDF2?hash?of?the?password
?????*/
????public?static?String?createHash(String?password)
????????throws?NoSuchAlgorithmException,?InvalidKeySpecException
????{
????????return?createHash(password.toCharArray());
????}
?
????/**
?????*?Returns?a?salted?PBKDF2?hash?of?the?password.
?????*
?????*?@param???password????the?password?to?hash
?????*?@return??????????????a?salted?PBKDF2?hash?of?the?password
?????*/
????public?static?String?createHash(char[]?password)
????????throws?NoSuchAlgorithmException,?InvalidKeySpecException
????{
????????//?Generate?a?random?salt
????????SecureRandom?random?=?new?SecureRandom();
????????byte[]?salt?=?new?byte[SALT_BYTE_SIZE];
????????random.nextBytes(salt);
?
????????//?Hash?the?password
????????byte[]?hash?=?pbkdf2(password,?salt,?PBKDF2_ITERATIONS,?HASH_BYTE_SIZE);
????????//?format?iterations:salt:hash
????????return?PBKDF2_ITERATIONS?+?":"?+?toHex(salt)?+?":"?+??toHex(hash);
????}
?
????/**
?????*?Validates?a?password?using?a?hash.
?????*
?????*?@param???password????????the?password?to?check
?????*?@param???correctHash?????the?hash?of?the?valid?password
?????*?@return??????????????????true?if?the?password?is?correct,?false?if?not
?????*/
????public?static?boolean?validatePassword(String?password,?String?correctHash)
????????throws?NoSuchAlgorithmException,?InvalidKeySpecException
????{
????????return?validatePassword(password.toCharArray(),?correctHash);
????}
?
????/**
?????*?Validates?a?password?using?a?hash.
?????*
?????*?@param???password????????the?password?to?check
?????*?@param???correctHash?????the?hash?of?the?valid?password
?????*?@return??????????????????true?if?the?password?is?correct,?false?if?not
?????*/
????public?static?boolean?validatePassword(char[]?password,?String?correctHash)
????????throws?NoSuchAlgorithmException,?InvalidKeySpecException
????{
????????//?Decode?the?hash?into?its?parameters
????????String[]?params?=?correctHash.split(":");
????????int?iterations?=?Integer.parseInt(params[ITERATION_INDEX]);
????????byte[]?salt?=?fromHex(params[SALT_INDEX]);
????????byte[]?hash?=?fromHex(params[PBKDF2_INDEX]);
????????//?Compute?the?hash?of?the?provided?password,?using?the?same?salt,?
????????//?iteration?count,?and?hash?length
????????byte[]?testHash?=?pbkdf2(password,?salt,?iterations,?hash.length);
????????//?Compare?the?hashes?in?constant?time.?The?password?is?correct?if
????????//?both?hashes?match.
????????return?slowEquals(hash,?testHash);
????}
?
????/**
?????*?Compares?two?byte?arrays?in?length-constant?time.?This?comparison?method
?????*?is?used?so?that?password?hashes?cannot?be?extracted?from?an?on-line?
?????*?system?using?a?timing?attack?and?then?attacked?off-line.
?????*?
?????*?@param???a???????the?first?byte?array
?????*?@param???b???????the?second?byte?array?
?????*?@return??????????true?if?both?byte?arrays?are?the?same,?false?if?not
?????*/
????private?static?boolean?slowEquals(byte[]?a,?byte[]?b)
????{
????????int?diff?=?a.length?^?b.length;
????????for(int?i?=?0;?i?<?a.length?&&?i?<?b.length;?i++)
????????????diff?|=?a[i]?^?b[i];
????????return?diff?==?0;
????}
?
????/**
?????*??Computes?the?PBKDF2?hash?of?a?password.
?????*
?????*?@param???password????the?password?to?hash.
?????*?@param???salt????????the?salt
?????*?@param???iterations??the?iteration?count?(slowness?factor)
?????*?@param???bytes???????the?length?of?the?hash?to?compute?in?bytes
?????*?@return??????????????the?PBDKF2?hash?of?the?password
?????*/
????private?static?byte[]?pbkdf2(char[]?password,?byte[]?salt,?int?iterations,?int?bytes)
????????throws?NoSuchAlgorithmException,?InvalidKeySpecException
????{
????????PBEKeySpec?spec?=?new?PBEKeySpec(password,?salt,?iterations,?bytes?*?8);
????????SecretKeyFactory?skf?=?SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
????????return?skf.generateSecret(spec).getEncoded();
????}
?
????/**
?????*?Converts?a?string?of?hexadecimal?characters?into?a?byte?array.
?????*
?????*?@param???hex?????????the?hex?string
?????*?@return??????????????the?hex?string?decoded?into?a?byte?array
?????*/
????private?static?byte[]?fromHex(String?hex)
????{
????????byte[]?binary?=?new?byte[hex.length()?/?2];
????????for(int?i?=?0;?i?<?binary.length;?i++)
????????{
????????????binary[i]?=?(byte)Integer.parseInt(hex.substring(2*i,?2*i+2),?16);
????????}
????????return?binary;
????}
?
????/**
?????*?Converts?a?byte?array?into?a?hexadecimal?string.
?????*
?????*?@param???array???????the?byte?array?to?convert
?????*?@return??????????????a?length*2?character?string?encoding?the?byte?array
?????*/
????private?static?String?toHex(byte[]?array)
????{
????????BigInteger?bi?=?new?BigInteger(1,?array);
????????String?hex?=?bi.toString(16);
????????int?paddingLength?=?(array.length?*?2)?-?hex.length();
????????if(paddingLength?>?0)
????????????return?String.format("%0"?+?paddingLength?+?"d",?0)?+?hex;
????????else
????????????return?hex;
????}
?
????/**
?????*?Tests?the?basic?functionality?of?the?PasswordHash?class
?????*
?????*?@param???args????????ignored
?????*/
????public?static?void?main(String[]?args)
????{
????????try
????????{
????????????//?Print?out?10?hashes
????????????for(int?i?=?0;?i?<?10;?i++)
????????????????System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));
?
????????????//?Test?password?validation
????????????boolean?failure?=?false;
????????????System.out.println("Running?tests...");
????????????for(int?i?=?0;?i?<?100;?i++)
????????????{
????????????????String?password?=?""+i;
????????????????String?hash?=?createHash(password);
????????????????String?secondHash?=?createHash(password);
????????????????if(hash.equals(secondHash))?{
????????????????????System.out.println("FAILURE:?TWO?HASHES?ARE?EQUAL!");
????????????????????failure?=?true;
????????????????}
????????????????String?wrongPassword?=?""+(i+1);
????????????????if(validatePassword(wrongPassword,?hash))?{
????????????????????System.out.println("FAILURE:?WRONG?PASSWORD?ACCEPTED!");
????????????????????failure?=?true;
????????????????}
????????????????if(!validatePassword(password,?hash))?{
????????????????????System.out.println("FAILURE:?GOOD?PASSWORD?NOT?ACCEPTED!");
????????????????????failure?=?true;
????????????????}
????????????}
????????????if(failure)
????????????????System.out.println("TESTS?FAILED!");
????????????else
????????????????System.out.println("TESTS?PASSED!");
????????}
????????catch(Exception?ex)
????????{
????????????System.out.println("ERROR:?"?+?ex);
????????}
????}
?
}
ASP.NET (C#)密碼hash代碼
/*?
?*?Password?Hashing?With?PBKDF2?(http://crackstation.net/hashing-security.htm).
?*?Copyright?(c)?2013,?Taylor?Hornby
?*?All?rights?reserved.
?*
?*?Redistribution?and?use?in?source?and?binary?forms,?with?or?without?
?*?modification,?are?permitted?provided?that?the?following?conditions?are?met:
?*
?*?1.?Redistributions?of?source?code?must?retain?the?above?copyright?notice,?
?*?this?list?of?conditions?and?the?following?disclaimer.
?*
?*?2.?Redistributions?in?binary?form?must?reproduce?the?above?copyright?notice,
?*?this?list?of?conditions?and?the?following?disclaimer?in?the?documentation?
?*?and/or?other?materials?provided?with?the?distribution.
?*
?*?THIS?SOFTWARE?IS?PROVIDED?BY?THE?COPYRIGHT?HOLDERS?AND?CONTRIBUTORS?"AS?IS"?
?*?AND?ANY?EXPRESS?OR?IMPLIED?WARRANTIES,?INCLUDING,?BUT?NOT?LIMITED?TO,?THE?
?*?IMPLIED?WARRANTIES?OF?MERCHANTABILITY?AND?FITNESS?FOR?A?PARTICULAR?PURPOSE?
?*?ARE?DISCLAIMED.?IN?NO?EVENT?SHALL?THE?COPYRIGHT?HOLDER?OR?CONTRIBUTORS?BE?
?*?LIABLE?FOR?ANY?DIRECT,?INDIRECT,?INCIDENTAL,?SPECIAL,?EXEMPLARY,?OR?
?*?CONSEQUENTIAL?DAMAGES?(INCLUDING,?BUT?NOT?LIMITED?TO,?PROCUREMENT?OF?
?*?SUBSTITUTE?GOODS?OR?SERVICES;?LOSS?OF?USE,?DATA,?OR?PROFITS;?OR?BUSINESS?
?*?INTERRUPTION)?HOWEVER?CAUSED?AND?ON?ANY?THEORY?OF?LIABILITY,?WHETHER?IN?
?*?CONTRACT,?STRICT?LIABILITY,?OR?TORT?(INCLUDING?NEGLIGENCE?OR?OTHERWISE)?
?*?ARISING?IN?ANY?WAY?OUT?OF?THE?USE?OF?THIS?SOFTWARE,?EVEN?IF?ADVISED?OF?THE?
?*?POSSIBILITY?OF?SUCH?DAMAGE.
?*/
?
using?System;
using?System.Text;
using?System.Security.Cryptography;
?
namespace?PasswordHash
{
????///?<summary>
????///?Salted?password?hashing?with?PBKDF2-SHA1.
????///?Author:?havoc?AT?defuse.ca
????///?www:?http://crackstation.net/hashing-security.htm
????///?Compatibility:?.NET?3.0?and?later.
????///?</summary>
????public?class?PasswordHash
????{
????????//?The?following?constants?may?be?changed?without?breaking?existing?hashes.
????????public?const?int?SALT_BYTE_SIZE?=?24;
????????public?const?int?HASH_BYTE_SIZE?=?24;
????????public?const?int?PBKDF2_ITERATIONS?=?1000;
?
????????public?const?int?ITERATION_INDEX?=?0;
????????public?const?int?SALT_INDEX?=?1;
????????public?const?int?PBKDF2_INDEX?=?2;
?
????????///?<summary>
????????///?Creates?a?salted?PBKDF2?hash?of?the?password.
????????///?</summary>
????????///?<param?name="password">The?password?to?hash.</param>
????????///?<returns>The?hash?of?the?password.</returns>
????????public?static?string?CreateHash(string?password)
????????{
????????????//?Generate?a?random?salt
????????????RNGCryptoServiceProvider?csprng?=?new?RNGCryptoServiceProvider();
????????????byte[]?salt?=?new?byte[SALT_BYTE_SIZE];
????????????csprng.GetBytes(salt);
?
????????????//?Hash?the?password?and?encode?the?parameters
????????????byte[]?hash?=?PBKDF2(password,?salt,?PBKDF2_ITERATIONS,?HASH_BYTE_SIZE);
????????????return?PBKDF2_ITERATIONS?+?":"?+
????????????????Convert.ToBase64String(salt)?+?":"?+
????????????????Convert.ToBase64String(hash);
????????}
?
????????///?<summary>
????????///?Validates?a?password?given?a?hash?of?the?correct?one.
????????///?</summary>
????????///?<param?name="password">The?password?to?check.</param>
????????///?<param?name="correctHash">A?hash?of?the?correct?password.</param>
????????///?<returns>True?if?the?password?is?correct.?False?otherwise.</returns>
????????public?static?bool?ValidatePassword(string?password,?string?correctHash)
????????{
????????????//?Extract?the?parameters?from?the?hash
????????????char[]?delimiter?=?{?':'?};
????????????string[]?split?=?correctHash.Split(delimiter);
????????????int?iterations?=?Int32.Parse(split[ITERATION_INDEX]);
????????????byte[]?salt?=?Convert.FromBase64String(split[SALT_INDEX]);
????????????byte[]?hash?=?Convert.FromBase64String(split[PBKDF2_INDEX]);
?
????????????byte[]?testHash?=?PBKDF2(password,?salt,?iterations,?hash.Length);
????????????return?SlowEquals(hash,?testHash);
????????}
?
????????///?<summary>
????????///?Compares?two?byte?arrays?in?length-constant?time.?This?comparison
????????///?method?is?used?so?that?password?hashes?cannot?be?extracted?from
????????///?on-line?systems?using?a?timing?attack?and?then?attacked?off-line.
????????///?</summary>
????????///?<param?name="a">The?first?byte?array.</param>
????????///?<param?name="b">The?second?byte?array.</param>
????????///?<returns>True?if?both?byte?arrays?are?equal.?False?otherwise.</returns>
????????private?static?bool?SlowEquals(byte[]?a,?byte[]?b)
????????{
????????????uint?diff?=?(uint)a.Length?^?(uint)b.Length;
????????????for?(int?i?=?0;?i?<?a.Length?&&?i?<?b.Length;?i++)
????????????????diff?|=?(uint)(a[i]?^?b[i]);
????????????return?diff?==?0;
????????}
?
????????///?<summary>
????????///?Computes?the?PBKDF2-SHA1?hash?of?a?password.
????????///?</summary>
????????///?<param?name="password">The?password?to?hash.</param>
????????///?<param?name="salt">The?salt.</param>
????????///?<param?name="iterations">The?PBKDF2?iteration?count.</param>
????????///?<param?name="outputBytes">The?length?of?the?hash?to?generate,?in?bytes.</param>
????????///?<returns>A?hash?of?the?password.</returns>
????????private?static?byte[]?PBKDF2(string?password,?byte[]?salt,?int?iterations,?int?outputBytes)
????????{
????????????Rfc2898DeriveBytes?pbkdf2?=?new?Rfc2898DeriveBytes(password,?salt);
????????????pbkdf2.IterationCount?=?iterations;
????????????return?pbkdf2.GetBytes(outputBytes);
????????}
????}
}
Ruby (on Rails)?密碼hash代碼
#?Password?Hashing?With?PBKDF2?(http://crackstation.net/hashing-security.htm).
#?Copyright?(c)?2013,?Taylor?Hornby
#?All?rights?reserved.
#?
#?Redistribution?and?use?in?source?and?binary?forms,?with?or?without?
#?modification,?are?permitted?provided?that?the?following?conditions?are?met:
#?
#?1.?Redistributions?of?source?code?must?retain?the?above?copyright?notice,?
#?this?list?of?conditions?and?the?following?disclaimer.
#?
#?2.?Redistributions?in?binary?form?must?reproduce?the?above?copyright?notice,
#?this?list?of?conditions?and?the?following?disclaimer?in?the?documentation?
#?and/or?other?materials?provided?with?the?distribution.
#?
#?THIS?SOFTWARE?IS?PROVIDED?BY?THE?COPYRIGHT?HOLDERS?AND?CONTRIBUTORS?"AS?IS"?
#?AND?ANY?EXPRESS?OR?IMPLIED?WARRANTIES,?INCLUDING,?BUT?NOT?LIMITED?TO,?THE?
#?IMPLIED?WARRANTIES?OF?MERCHANTABILITY?AND?FITNESS?FOR?A?PARTICULAR?PURPOSE?
#?ARE?DISCLAIMED.?IN?NO?EVENT?SHALL?THE?COPYRIGHT?HOLDER?OR?CONTRIBUTORS?BE?
#?LIABLE?FOR?ANY?DIRECT,?INDIRECT,?INCIDENTAL,?SPECIAL,?EXEMPLARY,?OR?
#?CONSEQUENTIAL?DAMAGES?(INCLUDING,?BUT?NOT?LIMITED?TO,?PROCUREMENT?OF?
#?SUBSTITUTE?GOODS?OR?SERVICES;?LOSS?OF?USE,?DATA,?OR?PROFITS;?OR?BUSINESS?
#?INTERRUPTION)?HOWEVER?CAUSED?AND?ON?ANY?THEORY?OF?LIABILITY,?WHETHER?IN?
#?CONTRACT,?STRICT?LIABILITY,?OR?TORT?(INCLUDING?NEGLIGENCE?OR?OTHERWISE)?
#?ARISING?IN?ANY?WAY?OUT?OF?THE?USE?OF?THIS?SOFTWARE,?EVEN?IF?ADVISED?OF?THE?
#?POSSIBILITY?OF?SUCH?DAMAGE.
?
require?'securerandom'
require?'openssl'
require?'base64'
?
#?Salted?password?hashing?with?PBKDF2-SHA1.
#?Authors:?@RedragonX?(dicesoft.net),?havoc?AT?defuse.ca?
#?www:?http://crackstation.net/hashing-security.htm
module?PasswordHash
?
??#?The?following?constants?can?be?changed?without?breaking?existing?hashes.
??PBKDF2_ITERATIONS?=?1000
??SALT_BYTE_SIZE?=?24
??HASH_BYTE_SIZE?=?24
?
??HASH_SECTIONS?=?4
??SECTION_DELIMITER?=?':'
??ITERATIONS_INDEX?=?1
??SALT_INDEX?=?2
??HASH_INDEX?=?3
?
??#?Returns?a?salted?PBKDF2?hash?of?the?password.
??def?self.createHash(?password?)
????salt?=?SecureRandom.base64(?SALT_BYTE_SIZE?)
????pbkdf2?=?OpenSSL::PKCS5::pbkdf2_hmac_sha1(
??????password,
??????salt,
??????PBKDF2_ITERATIONS,
??????HASH_BYTE_SIZE
????)
????return?["sha1",?PBKDF2_ITERATIONS,?salt,?Base64.encode64(?pbkdf2?)].join(?SECTION_DELIMITER?)
??end
?
??#?Checks?if?a?password?is?correct?given?a?hash?of?the?correct?one.
??#?correctHash?must?be?a?hash?string?generated?with?createHash.
??def?self.validatePassword(?password,?correctHash?)
????params?=?correctHash.split(?SECTION_DELIMITER?)
????return?false?if?params.length?!=?HASH_SECTIONS
?
????pbkdf2?=?Base64.decode64(?params[HASH_INDEX]?)
????testHash?=?OpenSSL::PKCS5::pbkdf2_hmac_sha1(
??????password,
??????params[SALT_INDEX],
??????params[ITERATIONS_INDEX].to_i,
??????pbkdf2.length
????)
?
????return?pbkdf2?==?testHash
??end
?
??#?Run?tests?to?ensure?the?module?is?functioning?properly.
??#?Returns?true?if?all?tests?succeed,?false?if?not.
??def?self.runSelfTests
????puts?"Sample?hashes:"
????3.times?{?puts?createHash("password")?}
?
????puts?"\nRunning?self?tests..."
????@@allPass?=?true
?
????correctPassword?=?'aaaaaaaaaa'
????wrongPassword?=?'aaaaaaaaab'
????hash?=?createHash(correctPassword)
?
????assert(?validatePassword(?correctPassword,?hash?)?==?true,?"correct?password"?)
????assert(?validatePassword(?wrongPassword,?hash?)?==?false,?"wrong?password"?)
?
????h1?=?hash.split(?SECTION_DELIMITER?)
????h2?=?createHash(?correctPassword?).split(?SECTION_DELIMITER?)
????assert(?h1[HASH_INDEX]?!=?h2[HASH_INDEX],?"different?hashes"?)
????assert(?h1[SALT_INDEX]?!=?h2[SALT_INDEX],?"different?salt"?)
?
????if?@@allPass
??????puts?"***?ALL?TESTS?PASS?***"
????else
??????puts?"***?FAILURES?***"
????end
?
????return?@@allPass
??end
?
??def?self.assert(?truth,?msg?)
????if?truth
??????puts?"PASS?[#{msg}]"
????else
??????puts?"FAIL?[#{msg}]"
??????@@allPass?=?false
????end
??end
?
end
?
PasswordHash.runSelfTests
原文出自:http://www.freebuf.com/articles/web/28527.html或http://netsecurity.51cto.com/art/201403/432090.htm
總結
以上是生活随笔為你收集整理的如何安全的存储用户密码?(中)代码篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lua程序设计
- 下一篇: Python第十课 网络管理