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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
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,如需转载请自行联系原作者

相关文章
|
1月前
|
机器学习/深度学习 存储 算法
解锁文件共享软件背后基于 Python 的二叉搜索树算法密码
文件共享软件在数字化时代扮演着连接全球用户、促进知识与数据交流的重要角色。二叉搜索树作为一种高效的数据结构,通过有序存储和快速检索文件,极大提升了文件共享平台的性能。它依据文件名或时间戳等关键属性排序,支持高效插入、删除和查找操作,显著优化用户体验。本文还展示了用Python实现的简单二叉搜索树代码,帮助理解其工作原理,并展望了该算法在分布式计算和机器学习领域的未来应用前景。
|
2天前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
1月前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
274 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
1月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
121 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
1月前
|
弹性计算 算法 Linux
使用SM4算法加密LUKS格式磁盘
本文介绍了在Anolis 8操作系统使用cryptsetup对磁盘进行分区、加密和挂载的过程。采用SM4加密算法。具体步骤包括:初始化加密卷、解锁加密分区、格式化并挂载设备。最后,展示了如何取消挂载并关闭加密卷以确保数据安全。整个过程确保了磁盘数据的安全性和隐私保护。
71 2
使用SM4算法加密LUKS格式磁盘
|
1月前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
2月前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
24天前
|
存储 算法 测试技术
【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)
【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)
|
24天前
|
算法 安全 调度
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
|
24天前
|
存储 人工智能 算法
【深度优先搜索篇】走迷宫的魔法:算法如何破解迷宫的神秘密码
【深度优先搜索篇】走迷宫的魔法:算法如何破解迷宫的神秘密码