Java中hash+salt的加密算法
来源:互联网 发布:柯桥区干部网络学堂 编辑:程序博客网 时间:2024/05/28 15:18
一般我们存储密码的时候,使用hash算法进行存储,但是,这样做是不安全的,虽然不能反向生成密码,但是可以通过彩虹法和反向查表法高效的猜解出密码。
比较安全的做法就是使用hash+salt的加密算法。
这里使用了RFC2898标准。
看代码:
Rfc2898DeriveBytes.java
package com.poreader.common;import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.Random;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.binary.Base64;/** * This implementation follows RFC 2898 recommendations. See * http://www.ietf.org/rfc/Rfc2898.txt */public class Rfc2898DeriveBytes {private static final int BLOCK_SIZE = 20;private static Random random = new Random();private Mac hmacsha1;private byte[] salt;private int iterations;private byte[] buffer = new byte[BLOCK_SIZE];private int startIndex = 0;private int endIndex = 0;private int block = 1;/** * Creates new instance. * * @param password * The password used to derive the key. * @param salt * The key salt used to derive the key. * @param iterations * The number of iterations for the operation. * @throws NoSuchAlgorithmException * HmacSHA1 algorithm cannot be found. * @throws InvalidKeyException * Salt must be 8 bytes or more. -or- Password cannot be null. */public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations) throws NoSuchAlgorithmException,InvalidKeyException {this.salt = salt;this.iterations = iterations;this.hmacsha1 = Mac.getInstance("HmacSHA1");this.hmacsha1.init(new SecretKeySpec(password, "HmacSHA1"));}/** * Creates new instance. * * @param password * The password used to derive the key. * @param salt * The key salt used to derive the key. * @param iterations * The number of iterations for the operation. * @throws NoSuchAlgorithmException * HmacSHA1 algorithm cannot be found. * @throws InvalidKeyException * Salt must be 8 bytes or more. -or- Password cannot be null. * @throws UnsupportedEncodingException */public Rfc2898DeriveBytes(String password, int saltSize, int iterations) throws NoSuchAlgorithmException,InvalidKeyException, UnsupportedEncodingException {this.salt = randomSalt(saltSize);this.iterations = iterations;this.hmacsha1 = Mac.getInstance("HmacSHA1");this.hmacsha1.init(new SecretKeySpec(password.getBytes("UTF-8"), "HmacSHA1"));this.buffer = new byte[BLOCK_SIZE];this.block = 1;this.startIndex = this.endIndex = 1;}/** * Creates new instance. * * @param password * The password used to derive the key. * @param salt * The key salt used to derive the key. * @param iterations * The number of iterations for the operation. * @throws NoSuchAlgorithmException * HmacSHA1 algorithm cannot be found. * @throws InvalidKeyException * Salt must be 8 bytes or more. -or- Password cannot be null. * @throws UnsupportedEncodingException */public Rfc2898DeriveBytes(String password, int saltSize) throws NoSuchAlgorithmException, InvalidKeyException,UnsupportedEncodingException {this(password, saltSize, 1000);}/** * Creates new instance. * * @param password * The password used to derive the key. * @param salt * The key salt used to derive the key. * @param iterations * The number of iterations for the operation. * @throws NoSuchAlgorithmException * HmacSHA1 algorithm cannot be found. * @throws InvalidKeyException * Salt must be 8 bytes or more. -or- Password cannot be null. * @throws UnsupportedEncodingException * UTF-8 encoding is not supported. */public Rfc2898DeriveBytes(String password, byte[] salt, int iterations) throws InvalidKeyException,NoSuchAlgorithmException, UnsupportedEncodingException {this(password.getBytes("UTF8"), salt, iterations);}public byte[] getSalt() {return this.salt;}public String getSaltAsString() {return Base64.encodeBase64String(this.salt);}/** * Returns a pseudo-random key from a data, salt and iteration count. * * @param cb * Number of bytes to return. * @return Byte array. */public byte[] getBytes(int cb) {byte[] result = new byte[cb];int offset = 0;int size = this.endIndex - this.startIndex;if (size > 0) { // if there is some data in bufferif (cb >= size) { // if there is enough data in bufferSystem.arraycopy(this.buffer, this.startIndex, result, 0, size);this.startIndex = this.endIndex = 0;offset += size;} else {System.arraycopy(this.buffer, this.startIndex, result, 0, cb);startIndex += cb;return result;}}while (offset < cb) {byte[] block = this.func();int remainder = cb - offset;if (remainder > BLOCK_SIZE) {System.arraycopy(block, 0, result, offset, BLOCK_SIZE);offset += BLOCK_SIZE;} else {System.arraycopy(block, 0, result, offset, remainder);offset += remainder;System.arraycopy(block, remainder, this.buffer, startIndex, BLOCK_SIZE - remainder);endIndex += (BLOCK_SIZE - remainder);return result;}}return result;}public static byte[] randomSalt(int size) {byte[] salt = new byte[size];random.nextBytes(salt);return salt;}/** * Generate random Salt * * @param size * @return */public static String generateSalt(int size) {byte[] salt = randomSalt(size);return Base64.encodeBase64String(salt);}private byte[] func() {this.hmacsha1.update(this.salt, 0, this.salt.length);byte[] tempHash = this.hmacsha1.doFinal(getBytesFromInt(this.block));this.hmacsha1.reset();byte[] finalHash = tempHash;for (int i = 2; i <= this.iterations; i++) {tempHash = this.hmacsha1.doFinal(tempHash);for (int j = 0; j < 20; j++) {finalHash[j] = (byte) (finalHash[j] ^ tempHash[j]);}}if (this.block == 2147483647) {this.block = -2147483648;} else {this.block += 1;}return finalHash;}private static byte[] getBytesFromInt(int i) {return new byte[] { (byte) (i >>> 24), (byte) (i >>> 16), (byte) (i >>> 8), (byte) i };}}
package com.poreader.common;import org.apache.commons.codec.binary.Base64;public class CryptoUtils {private static int saltSize = 32;private static int iterations = 1000;private static int subKeySize = 32;/** * 获取 Salt * @return */public static String getSalt() {return Rfc2898DeriveBytes.generateSalt(saltSize);}/** * 获取hash后的密码 * @param password * @param salt * @return */public static String getHash(String password, String salt) {Rfc2898DeriveBytes keyGenerator = null;try {keyGenerator = new Rfc2898DeriveBytes(password + salt, saltSize, iterations);} catch (Exception e1) {e1.printStackTrace();}byte[] subKey = keyGenerator.getBytes(subKeySize);byte[] bSalt = keyGenerator.getSalt();byte[] hashPassword = new byte[1 + saltSize + subKeySize];System.arraycopy(bSalt, 0, hashPassword, 1, saltSize);System.arraycopy(subKey, 0, hashPassword, saltSize + 1, subKeySize);return Base64.encodeBase64String(hashPassword);}/** * 验证密码 * @param hashedPassword * @param password * @param salt * @return */public static boolean verify(String hashedPassword, String password, String salt) {byte[] hashedPasswordBytes = Base64.decodeBase64(hashedPassword);if (hashedPasswordBytes.length != (1 + saltSize + subKeySize) || hashedPasswordBytes[0] != 0x00) {return false;}byte[] bSalt = new byte[saltSize];System.arraycopy(hashedPasswordBytes, 1, bSalt, 0, saltSize);byte[] storedSubkey = new byte[subKeySize];System.arraycopy(hashedPasswordBytes, 1 + saltSize, storedSubkey, 0, subKeySize);Rfc2898DeriveBytes deriveBytes = null;try {deriveBytes = new Rfc2898DeriveBytes(password + salt, bSalt, iterations);} catch (Exception e) {e.printStackTrace();}byte[] generatedSubkey = deriveBytes.getBytes(subKeySize);return byteArraysEqual(storedSubkey, generatedSubkey);}private static boolean byteArraysEqual(byte[] storedSubkey, byte[] generatedSubkey) {int size = storedSubkey.length;if (size != generatedSubkey.length) {return false;}for (int i = 0; i < size; i++) {if (storedSubkey[i] != generatedSubkey[i]) {return false;}}return true;}}
验证:
public static void main(String[] args) throws NoSuchAlgorithmException {String salt = CryptoUtils.getSalt();String password = "admin123";String hashPassword = CryptoUtils.getHash(password, salt);System.out.println("hashPassword:" + hashPassword);System.out.println("salt:" + salt);System.out.println("password:" + password);// verifyboolean result = CryptoUtils.verify(hashPassword, password, salt);System.out.println("Verify:" + result);}
2 0
- Java中hash+salt的加密算法
- JAVA中常用的加密算法(Hash、base64、MD5、ASC)
- Java中常用的加密算法
- java中常见的加密算法
- password: salt + hash
- C# salt+hash 加密
- 如何安全的存储密码 - hash、salt 以及更多
- MD5 Hash + Salt的密码存储方式实现
- 关于MD5,SALT与SHA1的部分HASH算法解析
- Java中常用的加密算法应用
- Java中常用的加密算法应用
- java中加密算法的应用一:DES
- java中常用的数据加密算法
- Java中MD5加密算法的实现
- JAVA中常用的加密算法总结
- JAVA开发过程中常用的加密算法
- java中常用的数据加密算法
- Java中一些比较常见的加密算法
- 使用R画桑基图(流程图)
- [shuju]一道简单题 Uva 11991
- Android常见的问题
- 解决MySQL中死进程(一个联合查询耗时32s)
- JSP的内置对象
- Java中hash+salt的加密算法
- Eclipse Android安装APP时覆盖安装问题
- Oracle 行转字符串
- 获取xml字符串中的属性值
- 【LeetCode】Path Sum II
- 转载: hazelcast的坑爹事
- java采集网页数据方法【多线程数据采集之一】
- Eclipse Android开发环境配置
- 三、窗口与消息