java实现常见的密钥派生函数(KDF)
在Java中,常见的密钥派生函数(KDF)也可以使用标准库和第三方库来实现。以下是PBKDF2、HKDF、bcrypt和scrypt的实现示例。
1. PBKDF2
PBKDF2是基于密码的密钥派生函数,使用HMAC进行多次迭代来增加攻击难度。Java标准库提供了对PBKDF2的支持。
Java实现(使用javax.crypto
库)
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;public class PBKDF2Example {public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {String password = "password";byte[] salt = "salt".getBytes();int iterations = 100000;int keyLength = 256;PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keyLength);SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");byte[] derivedKey = skf.generateSecret(spec).getEncoded();System.out.println(Base64.getEncoder().encodeToString(derivedKey));}
}
2. HKDF
HKDF使用HMAC进行两步操作:提取和扩展,从输入密钥材料(IKM)派生出密钥。Java标准库没有直接提供HKDF的实现,但可以手动实现。
Java实现(自定义实现)
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;public class HKDFExample {public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {byte[] ikm = "input key material".getBytes();byte[] salt = "salt".getBytes();byte[] info = "context info".getBytes();int length = 32;byte[] prk = hkdfExtract(salt, ikm);byte[] derivedKey = hkdfExpand(prk, info, length);System.out.println(Base64.getEncoder().encodeToString(derivedKey));}private static byte[] hkdfExtract(byte[] salt, byte[] ikm) throws NoSuchAlgorithmException, InvalidKeyException {Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(salt, "HmacSHA256"));return mac.doFinal(ikm);}private static byte[] hkdfExpand(byte[] prk, byte[] info, int length) throws NoSuchAlgorithmException, InvalidKeyException {Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(prk, "HmacSHA256"));byte[] result = new byte[length];byte[] t = new byte[0];int loc = 0;for (int i = 1; loc < length; i++) {mac.update(t);mac.update(info);mac.update((byte) i);t = mac.doFinal();int copyLength = Math.min(t.length, length - loc);System.arraycopy(t, 0, result, loc, copyLength);loc += copyLength;}return result;}
}
3. bcrypt
bcrypt是一个基于Blowfish加密算法的密钥派生函数,具有内置的盐值和可调的工作因子。可以使用第三方库如 BCrypt
。
Java实现(使用BCrypt
库)
首先,添加依赖项(例如在Maven项目的pom.xml
中):
<dependency><groupId>de.svenkubiak</groupId><artifactId>jBCrypt</artifactId><version>0.4</version>
</dependency>
然后使用以下代码:
import org.mindrot.jbcrypt.BCrypt;public class BCryptExample {public static void main(String[] args) {String password = "password";String hashed = BCrypt.hashpw(password, BCrypt.gensalt(12));System.out.println(hashed);if (BCrypt.checkpw(password, hashed)) {System.out.println("Password matches");} else {System.out.println("Password does not match");}}
}
4. scrypt
scrypt是一个基于内存硬化技术的密钥派生函数,可以使用第三方库如 Scrypt
。
Java实现(使用Scrypt
库)
首先,添加依赖项(例如在Maven项目的pom.xml
中):
<dependency><groupId>com.lambdaworks</groupId><artifactId>scrypt</artifactId><version>1.4.0</version>
</dependency>
然后使用以下代码:
import com.lambdaworks.crypto.SCryptUtil;public class ScryptExample {public static void main(String[] args) {String password = "password";int N = 16384; // CPU/memory cost factorint r = 8; // Block size factorint p = 1; // Parallelization factorString hashed = SCryptUtil.scrypt(password, N, r, p);System.out.println(hashed);if (SCryptUtil.check(password, hashed)) {System.out.println("Password matches");} else {System.out.println("Password does not match");}}
}
总结
以上是四种常见的密钥派生函数(PBKDF2、HKDF、bcrypt和scrypt)的Java实现示例。选择合适的KDF取决于具体的应用需求和安全要求。确保密码和盐值的随机性和保密性,是使用KDF的关键。