如何安全的存储用户密码?(下)代码实现pbkdf2算法加密

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

本文以java为例,进行实际加解密操作:

1       密码加盐hash

使用salt+password进行哈希算法加密!哈希算法选择:PBKDF2!

1.1    生成salt

使用随机函数java.security.SecureRandom生成24位随机数作为salt:

本文参考的依据是:JDK API 1.6.0 中文版,下载地址:http://down.51cto.com/data/2300228

 

1.2    PBKDF2代码详解

可以直接copy到代码中

package com.demo.encrypt;

 

/*

 *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 "ASIS"

 *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.math.BigInteger;

importjava.security.NoSuchAlgorithmException;

import java.security.SecureRandom;

import java.security.spec.InvalidKeySpecException;

 

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.PBEKeySpec;

 

/*

 *PBKDF2 salted password hashing.

 *Author: havoc AT defuse.ca

 *www: http://crackstation.net/hashing-security.htm

 */

public class HashEncrypt {

         //PBKDF2.PBKDF2WithHmacSHA1, PBKDF2.PBKDF2WithHmacSHA224,PBKDF2.PBKDF2WithHmacSHA256,

         //PBKDF2.PBKDF2WithHmacSHA384,//PBKDF2.PBKDF2WithHmacSHA512

         //pbkdf2算法API链接:http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs5/PBKDF2.html

         publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

         //publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";

         //注意jdk1.8以下版本不支持SHA224以及SHA224以上算法,会报错:(项目环境为JDK1.7)

         //ERROR:java.security.NoSuchAlgorithmException: PBKDF2WithHmacSHA224 SecretKeyFactorynot available

         //The following constants may be changed without breaking existing hashes.

         publicstatic final int SALT_BYTE_SIZE = 16;//=32/2,生成字符长度为32的salt值

         publicstatic final int HASH_BYTE_SIZE = 24;

         publicstatic final int PBKDF2_ITERATIONS = 1000;

 

         publicstatic final int ITERATION_INDEX = 0;

         publicstatic final int SALT_INDEX = 1;

         publicstatic final int PBKDF2_INDEX = 2;

 

         /**

          * Returns a salted PBKDF2 hash of thepassword.(返回使用PBKDF2对password进行加盐hash生成的字符串)

          *

          * @param  password    the password to hash

          * @return              a salted PBKDF2 hash of thepassword

          */

         publicstatic String createHash(String password)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   returncreateHash(password.toCharArray());

         }

 

         /**

          * Returns a salted PBKDF2 hash of thepassword.(返回使用PBKDF2对password字节数组进行加盐hash生成的字符串)

          *

          * @param  password    the password to hash

          * @return              a salted PBKDF2 hash of thepassword

          */

         publicstatic String createHash(char[] password)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   LongstartTime = System.currentTimeMillis();

                   //Generate a random salt:创建一个随机16位盐

                   SecureRandomrandom = 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);

                   LongendTime = System.currentTimeMillis();

                   System.out.println("生成加盐hash密码时间是:"+ String.valueOf(endTime - startTime));

                   //format iterations:salt:hash:对字节数组进行hash返回字符串,字符串结构:(迭代次数:salt盐:加盐hash密码)

                   returnPBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);

         }

 

         /**

          * Validates a password using a hash.(校验密码是否正确)

          *

          * @param  password        the password tocheck

          * @param  correctHash     the hash of thevalid password

          * @return                  true if the password iscorrect, false if not

          */

         publicstatic boolean validatePassword(String password, String correctHash)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   returnvalidatePassword(password.toCharArray(), correctHash);

         }

 

         /**

          * Validates a password using a hash.(校验密码是否正确实现)

          *

          * @param  password        the password tocheck

          * @param  correctHash     the hash of thevalid password

          * @return                  true if the password iscorrect, false if not:校验密码是否正确

          */

         publicstatic boolean validatePassword(char[] password, String correctHash)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   //correctHash字符串的结构为(迭代次数:salt盐:加盐hash密码)

                   //Decode the hash into its parameters:冒号分隔correctHash

                   String[]params = correctHash.split(":");

                   //params[0]:迭代次数

                   intiterations = Integer.parseInt(params[ITERATION_INDEX]);

                   //params[1]:salt盐 ,再转换为字节数组

                   byte[]salt = fromHex(params[SALT_INDEX]);

                   ////params[2]:加盐hash密码字符串,再转换为字节数组

                   byte[]hash = fromHex(params[PBKDF2_INDEX]);

                   //Compute the hash of the provided password, using the same salt,

                   //iteration count, and hash length :使用password生成密钥

                   byte[]testHash = pbkdf2(password, salt, iterations, hash.length);

                   //Compare the hashes in constant time. The password is correct if

                   //both hashes match.:比较密钥是否相等

                   returnslowEquals(hash, testHash);

         }

 

         /**

          * Compares two byte arrays in length-constanttime. This comparison method

          * is used so that password hashes cannot beextracted from an on-line

          * system using a timing attack and thenattacked off-line.

          * 这段代码使用了异或(XOR)操作符”^”来比较整数是否相等,而没有使用”==”操作符。原因在于如果两个数完全一致,异或之后的值为零。

          * 
因为 0 XOR 0 = 0, 1 XOR1 = 0, 0 XOR 1 = 1, 1 XOR 0 = 1。

          * 
所以,第一行代码如果a.length等于b.length,变量diff等于0,否则的话diff就是一个非零的值。

          * 
然后,让a,b的每一个字节XOR之后再跟diff OR。这样,只有diff一开始是0,并且,a,b的每一个字节XOR的结果也是零,

          * 
最后循环完成后diff的值才是0,这种情况是a,b完全一样。否则最后diff是一个非零的值。

          *

          * @param  a       the first byte array

          * @param  b       the second byte array

          * @return          true if both byte arrays are thesame, false if not:比较两个字节数组是否相等。0相等;1不等

          */

         privatestatic boolean slowEquals(byte[] a, byte[] b) {

                   intdiff = a.length ^ b.length;

                   for(int i = 0; i < a.length && i < b.length; i++)

                            diff|= a[i] ^ b[i];

                   returndiff == 0;

         }

 

         /**

          * Computes the PBKDF2 hash of a password.(使用pbkdf2算法生成加盐hash字节数组)

          *

          * @param  password    the password to hash.

          * @param  salt        the salt

          * @param  iterations  the iteration count(slowness factor)

          * @param  bytes       the length of the hashto compute in bytes

          * @return              the PBDKF2 hash of the password:使用pbkdf2进行加盐hash生成密钥

          */

         privatestatic byte[] pbkdf2(char[] password, byte[] salt, int iterations,

                            intbytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

                   //PBEKeySpec:可随同基于密码的加密法 (PBE)

                   //使用的供用户选择的密码。可以将密码视为某种原始密钥内容,由此加密机制使用其导出一个密钥。

                   //带有生成可变密钥大小的 PBE 密码的 PBEKey 时使用的一个密码、salt、迭代计数以及导出密钥长度的构造方法。如果指定

                   //password 为 null,则使用一个空 char[]。

                   //注:在将 password 和 salt 存储进新的 PBEKeySpec 对象前将其复制。

                   //参数:

                   //password - 密码。

                   //salt - salt。

                   //iterationCount - 迭代计数。

                   //keyLength - 要导出的密钥长度。

                   PBEKeySpecspec = new PBEKeySpec(password, salt, iterations, bytes * 8);

                   //SecretKeyFactory此类表示秘密密钥的工厂。

                   //getInstance(String PBKDF2_ALGORITHM)返回转换指定算法的秘密密钥的SecretKeyFactory

                   //对象。

                   //PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

                   SecretKeyFactoryskf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

                   //skf.generateSecret(spec)根据提供的密钥规范(密钥材料)生成 SecretKey 对象。

                   //SecretKey.getEncoded()返回基本编码格式的密钥,如果此密钥不支持编码,则返回 null。

                   returnskf.generateSecret(spec).getEncoded();

         }

 

         /**

          * Converts a string of hexadecimal charactersinto a byte array.(将十六进制字符串转换为字节数组)

          *

          * @param  hex         the hex string

          * @return              the hex string decoded into abyte array:字符串转换为字节数组

          */

         privatestatic 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);

                   }

                   returnbinary;

         }

 

         /**

          * Converts a byte array into a hexadecimalstring.(将字节数组转换为十六进制字符串)

          *

          * @param  array       the byte array toconvert

          * @return              a length*2 character stringencoding the byte array::字节数组转换为字符串

          */

         privatestatic String toHex(byte[] array) {

                   BigIntegerbi = new BigInteger(1, array);

                   Stringhex = bi.toString(16);

                   intpaddingLength = (array.length * 2) - hex.length();

                   if(paddingLength > 0)

                            returnString.format("%0" + paddingLength + "d", 0) + hex;

                   else

                            returnhex;

         }

 

         /**

          * Tests the basic functionality of thePasswordHash class

          *

          * @param  args        ignored

          */

         publicstatic void main(String[] args) {

                   try{

                            //Print out 10 hashes

                            for(int i = 0; i < 10; i++) {

                                     //System.out.println(HashEncrypt.createHash("p\\r\\nassw0Rd!"));

                                     System.out.println("生成加盐hash后密钥:第" +i + "次:hashPWd:"

                                                        +HashEncrypt.createHash("p\\r\\nassw0Rd!"));

                            }

 

                            //Test password validation

                            booleanfailure = false;

                            System.out.println("Runningtests...");

                            for(int i = 0; i < 2; i++) {

                                     Stringpassword = "" + i;

                                     Stringhash = createHash(password);

                                     System.out.println("password第一次加盐hash:"+ hash);

                                     StringsecondHash = createHash(password);

                                     System.out.println("password第二次加盐hash:"+ secondHash);

                                     if(hash.equals(secondHash)) {

                                               //System.out.println("FAILURE: TWO HASHES ARE EQUAL!");

                                               System.out.println("password="+ i

                                                                 +",加盐hash后生成的两个密钥相等!就不可用!");

                                               failure= true;

                                     }

                                     StringwrongPassword = "" + (i + 1);

                                     if(validatePassword(wrongPassword, hash)) {

                                               //System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");

                                               System.out.println("hash="+ hash + ",wrongPassword="

                                                                 +wrongPassword + ",校验密钥匹配!就不可用!");

                                               failure= true;

                                     }

                                     if(!validatePassword(password, hash)) {

                                               System.out.println("FAILURE:GOOD PASSWORD NOT ACCEPTED!");

                                              System.out.println("hash=" +hash + ",password=" + password

                                                                 +",校验密钥不匹配,hash就是password生成的!就不可用!");

                                               failure= true;

                                     }

                            }

                            if(failure)

                                     System.out.println("TESTSFAILED!");

                            else

                                     System.out.println("TESTSPASSED!");

                   }catch (Exception ex) {

                            System.out.println("ERROR:" + ex);

                   }

         }

 

}

1.3    PBKDF2项目实践

1,  用户注册,使用PBKDF2对密码进行加盐hash加密;

2,  将salt盐和生成的hash密码存入数据库中;

3,  用户登录对密码进行加盐hash;

4,  校验密码;

5,  用户每次登录,重复3/4步骤。

如果想保存32位固定长度密码,可以在后面再进行一次MD5加密

 

工具类:

package com. common.utils;

 

import java.math.BigInteger;

import java.security.NoSuchAlgorithmException;

import java.security.SecureRandom;

importjava.security.spec.InvalidKeySpecException;

 

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.PBEKeySpec;

 

/**

 *

 * @项目名称:common

 * @类名称:HashEncrypt

 * @类描述:使用PBKDF2对密码进行加密处理

 * @创建人:wyait

 * @创建时间:2017年4月24日 上午9:53:15

 *@version:

 */

public class HashEncrypt {

         //pbkdf2 SHA1算法(由于JDK1.8以下只能使用SHA1,so....这将会是个历史遗留问题)

         publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

         //=32/2,生成字符长度为32的salt值

         publicstatic final int SALT_BYTE_SIZE = 16;

         //48/2,生成字符长度为48的hash密码

         publicstatic final int HASH_BYTE_SIZE = 24;

         //加密迭代次数

         publicstatic final int PBKDF2_ITERATIONS = 1000;

 

         /**

          *

          * @描述:返回使用SecureRandom生成salt盐

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:40:14

          * @return

          */

         publicstatic String createSalt() {

                   //Generate a random salt:创建一个随机16位盐

                   SecureRandomrandom = new SecureRandom();

                   byte[]salt = new byte[SALT_BYTE_SIZE];

                   random.nextBytes(salt);

                   //转换为十六进制字符串,字符长度=32

                   returntoHex(salt);

         }

 

         /**

          *

          * @描述:返回使用PBKDF2对password进行加盐hash生成的字符串(字符长度48)

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午9:55:37

          * @param salt 盐

          * @param password  原始密码

          * @return

          * @throws NoSuchAlgorithmException

          * @throws InvalidKeySpecException

          */

         publicstatic String createHash(String salt, String password)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   returncreateHash(fromHex(salt), password.toCharArray());

         }

 

         /**

          *

          * @描述:返回使用PBKDF2对password字节数组进行加盐hash生成的字符串(字符长度48)

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午9:57:35

          * @param salt 盐转换为字节数组

          * @param password 密码转换为字符数组

          * @return

          * @throws NoSuchAlgorithmException

          * @throws InvalidKeySpecException

          */

         publicstatic String createHash(byte[] salt, char[] password)

                            throwsNoSuchAlgorithmException, InvalidKeySpecException {

                   //Hash the password :hash生成字节数组

                   byte[]hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);

                   //对字节数组进行hash返回字符串(加盐hash密码)

                   System.out.println("hash密钥字符串长度:"+ toHex(hash).length());

                   returntoHex(hash);

         }

 

         /**

          *

          * @描述:校验密码是否正确

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:02:49

          * @param salt 盐

          * @param password  密码

          * @param correctHash  加盐hash密码

          * @return

          * @throws NoSuchAlgorithmException

          * @throws InvalidKeySpecException

          */

         publicstatic boolean validatePassword(String salt, String password,

                            StringcorrectHash) throws NoSuchAlgorithmException,

                            InvalidKeySpecException{

                   returnvalidatePassword(fromHex(salt), password.toCharArray(),

                                     correctHash);

         }

 

         /**

          *

          * @描述:校验密码是否正确实现

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:07:14

          * @param salt  盐

          * @param password   密码

          * @param correctHash   加盐hash密码

          * @return

          * @throws NoSuchAlgorithmException

          * @throws InvalidKeySpecException

          */

         publicstatic boolean validatePassword(byte[] salt, char[] password,

                            StringcorrectHash) throws NoSuchAlgorithmException,

                            InvalidKeySpecException{

                   //将correctHash转换为字节数组

                   byte[]hash = fromHex(correctHash);

                   //对passwrod进行:加盐hash生成密码字符串,再比对correctHash

                   byte[]testHash = pbkdf2(password, salt, PBKDF2_ITERATIONS, hash.length);

                   //both hashes match.:比较密钥是否相等

                   returnslowEquals(hash, testHash);

         }

 

         /**

          *

          * @描述:比较两个字节数组的值是否相等

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:07:46

          * @param a

          * @param b

          * @return

          */

         privatestatic boolean slowEquals(byte[] a, byte[] b) {

                   intdiff = a.length ^ b.length;

                   for(int i = 0; i < a.length && i < b.length; i++)

                            diff|= a[i] ^ b[i];

                   returndiff == 0;

         }

 

         /**

          *

          * @描述:使用pbkdf2算法生成加盐hash字节数组

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:11:02

          * @param password

          * @param salt

          * @param iterations

          * @param bytes

          * @return

          * @throws NoSuchAlgorithmException

          * @throws InvalidKeySpecException

          */

         privatestatic byte[] pbkdf2(char[] password, byte[] salt, int iterations,

                            intbytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

                   //PBEKeySpec:

                   //带有生成可变密钥大小的 PBE 密码的 PBEKey 时使用的一个密码、salt、迭代计数以及导出密钥长度的构造方法。如果指定

                   //password 为 null,则使用一个空 char[]。

                   //注:在将 password 和 salt 存储进新的 PBEKeySpec 对象前将其复制。

                   //参数:

                   //password - 密码。

                   //salt - salt。

                   //iterationCount - 迭代计数。

                   //keyLength - 要导出的密钥长度。

                   PBEKeySpecspec = new PBEKeySpec(password, salt, iterations, bytes * 8);

                   //SecretKeyFactory此类表示秘密密钥的工厂。

                   SecretKeyFactoryskf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

                   //skf.generateSecret(spec)根据提供的密钥规范(密钥材料)生成 SecretKey 对象。

                   //SecretKey.getEncoded()返回基本编码格式的密钥,如果此密钥不支持编码,则返回 null。返回字节数组

                   returnskf.generateSecret(spec).getEncoded();

         }

 

         /**

          *

          * @描述:将十六进制字符串转换为字节数组

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:11:15

          * @param hex

          * @return

          */

         privatestatic 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);

                   }

                   returnbinary;

         }

 

         /**

          *

          * @描述:将字节数组转换为十六进制字符串

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:11:22

          * @param array

          * @return

          */

         privatestatic String toHex(byte[] array) {

                   BigIntegerbi = new BigInteger(1, array);

                   Stringhex = bi.toString(16);

                   intpaddingLength = (array.length * 2) - hex.length();

                   if(paddingLength > 0)

                            returnString.format("%0" + paddingLength + "d", 0) + hex;

                   else

                            returnhex;

         }

 

         /**

          *

          * @描述:main方法测试

          * @创建人:wyait

          * @创建时间:2017年4月24日 上午10:23:53

          * @param args

          */

         publicstatic void main(String[] args) {

                   try{

                            //Print out 10 hashes

                            for(int i = 0; i < 10; i++) {

                                     Longs = System.currentTimeMillis();

                                     String salt = HashEncrypt.createSalt();

                                     //System.out.println(HashEncrypt.createHash("p\\r\\nassw0Rd!"));

                                     Longe = System.currentTimeMillis();

                                     System.out.println("生成加盐hash后密钥:第" +i + "次:hashPWd:"

                                                        +HashEncrypt.createHash(salt, "12003p\\r\\nassw0Rd!")

                                                        +",生成密码所用毫秒值:" + (String.valueOf(e - s)));

                            }

                            //Test password validation

                            booleanfailure = false;

                            System.out.println("Runningtests...");

                            for(int i = 0; i < 200; i++) {

                                     Longs = System.currentTimeMillis();

                                     Stringsalt = HashEncrypt.createSalt();

                                     Stringpassword = "" + i;

                                     Stringhash = createHash(salt, password);

                                     Stringsalt1 = HashEncrypt.createSalt();

                                     Longe = System.currentTimeMillis();

                                     System.out.println("password第一次加盐hash:"+ hash + ",生成密码所用毫秒值:"

                                                        +(String.valueOf(e - s)));

                                     StringsecondHash = createHash(salt1, password);

                                     System.out.println("password第二次加盐hash:"+ secondHash);

                                     //两个不同盐的hash密码比较

                                     if(hash.equals(secondHash)) {

                                               //System.out.println("FAILURE: TWO HASHES ARE EQUAL!");

                                               System.out.println("password="+ i

                                                                 +",加盐hash后生成的两个密钥相等!就不可用!");

                                               failure= true;

                                     }

                                     StringwrongPassword = "" + (i + 1);

                                     //使用其他密码是hash比对

                                     if(validatePassword(salt1, wrongPassword, hash)) {

                                               //System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");

                                               System.out.println("hash="+ hash + ",wrongPassword="

                                                                 +wrongPassword + ",校验密钥匹配!就不可用!");

                                               failure= true;

                                     }

                                     //用salt+password和使用它们生成的hash比对是否相等

                                     if(!validatePassword(salt, password, hash)) {

                                               System.out.println("FAILURE:GOOD PASSWORD NOT ACCEPTED!");

                                               System.out.println("hash="+ hash + ",password=" + password

                                                                 +",校验密钥不匹配,hash就是password生成的!就不可用!");

                                               failure= true;

                                     }

                            }

                            if(failure)

                                     System.out.println("TESTSFAILED!");

                            else

                                     System.out.println("TESTSPASSED!");

                   }catch (Exception ex) {

                            System.out.println("ERROR:" + ex);

                   }

         }

 

}

 


本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/1920128,如需转载请自行联系原作者

相关文章
|
2月前
|
存储 Java 数据库
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
这篇文章介绍了如何在Java中通过加盐和加密算法(如MD5和SHA)安全地存储密码,并提供了一个密码工具类PasswordUtils和密码编码类PasswordEncoder的实现示例。
74 10
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
|
2月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
42 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
2月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
211 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
3月前
|
存储 安全 数据安全/隐私保护
安全升级!Python AES加密实战,为你的代码加上一层神秘保护罩
【9月更文挑战第12天】在软件开发中,数据安全至关重要。本文将深入探讨如何使用Python中的AES加密技术保护代码免受非法访问和篡改。AES(高级加密标准)因其高效性和灵活性,已成为全球最广泛使用的对称加密算法之一。通过实战演练,我们将展示如何利用pycryptodome库实现AES加密,包括生成密钥、初始化向量(IV)、加密和解密文本数据等步骤。此外,还将介绍密钥管理和IV随机性等安全注意事项。通过本文的学习,你将掌握使用AES加密保护敏感数据的方法,为代码增添坚实的安全屏障。
157 8
|
3月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
152 5
|
3月前
|
安全 数据安全/隐私保护 Python
情书也能加密?Python AES&RSA,让每一份数据都充满爱的密码
【9月更文挑战第8天】在这个数字化时代,情书不再局限于纸笔,也可能以电子形式在网络中传递。为了确保其安全,Python提供了AES和RSA等加密工具,为情书编织爱的密码。首先,通过安装pycryptodome库,我们可以利用AES对称加密算法高效保护数据;接着,使用RSA非对称加密算法加密AES密钥和IV,进一步增强安全性。即使情书被截获,没有正确密钥也无法解读内容。让我们用Python为爱情编织一张安全的网,守护每份珍贵情感。
55 2
|
4天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
113 80
|
1天前
|
机器学习/深度学习 算法 索引
单目标问题的烟花优化算法求解matlab仿真,对比PSO和GA
本项目使用FW烟花优化算法求解单目标问题,并在MATLAB2022A中实现仿真,对比PSO和GA的性能。核心代码展示了适应度计算、火花生成及位置约束等关键步骤。最终通过收敛曲线对比三种算法的优化效果。烟花优化算法模拟烟花爆炸过程,探索搜索空间,寻找全局最优解,适用于复杂非线性问题。PSO和GA则分别适合快速收敛和大解空间的问题。参数调整和算法特性分析显示了各自的优势与局限。
|
23天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
9天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。