Android 5 上带有 Sha256 的 PBKDF2
PBKDF2 With Sha256 on Android 5
我正在制作一个 android 应用程序,它使用 PBKDF2 和 Hmac Sha256。我实现了该功能,但是当我在 android 5.0 设备上对其进行测试时,它给出了 NoSuchAlgorithmException。我如何为 android 5.0 手动实施 PBKDF2?
我将其用于 PBKDF2 和 AES 256 加密:
@RequiresApi(api = Build.VERSION_CODES.O)
public static String encrypt(String strToEncrypt, String SECRET_KEY, String SALT) {
try {
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec ivspec = new IvParameterSpec(iv);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 100000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
谢谢!
对于 Android SDK < 26 您可以使用 Will Glozer 编写的 PBKDF class,可在此处获取:https://github.com/wg/scrypt/blob/master/src/main/java/com/lambdaworks/crypto/PBKDF.java.
要导出 AES-256 的密钥,您可以这样调用 class:
byte[] secretKey = PBKDF.pbkdf2("HmacSHA256", passphraseByte, salt, PBKDF2_ITERATIONS, 32);
这是完整的 class 代码,以防将来它消失:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import static java.lang.System.arraycopy;
/**
* An implementation of the Password-Based Key Derivation Function as specified
* in RFC 2898.
*
* @author Will Glozer
*/
// source: https://github.com/wg/scrypt/blob/master/src/main/java/com/lambdaworks/crypto/PBKDF.java
// license: Apache License 2.0
public class PBKDF {
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param alg HMAC algorithm to use.
* @param P Password.
* @param S Salt.
* @param c Iteration count.
* @param dkLen Intended length, in octets, of the derived key.
*
* @return The derived key.
*
* @throws GeneralSecurityException
*/
public static byte[] pbkdf2(String alg, byte[] P, byte[] S, int c, int dkLen) throws GeneralSecurityException {
Mac mac = Mac.getInstance(alg);
mac.init(new SecretKeySpec(P, alg));
byte[] DK = new byte[dkLen];
pbkdf2(mac, S, c, DK, dkLen);
return DK;
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac Pre-initialized {@link Mac} instance to use.
* @param S Salt.
* @param c Iteration count.
* @param DK Byte array that derived key will be placed in.
* @param dkLen Intended length, in octets, of the derived key.
*
* @throws GeneralSecurityException
*/
public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[S.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(S, 0, block1, 0, S.length);
for (int i = 1; i <= l; i++) {
block1[S.length + 0] = (byte) (i >> 24 & 0xff);
block1[S.length + 1] = (byte) (i >> 16 & 0xff);
block1[S.length + 2] = (byte) (i >> 8 & 0xff);
block1[S.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
}
}
}
我正在制作一个 android 应用程序,它使用 PBKDF2 和 Hmac Sha256。我实现了该功能,但是当我在 android 5.0 设备上对其进行测试时,它给出了 NoSuchAlgorithmException。我如何为 android 5.0 手动实施 PBKDF2?
我将其用于 PBKDF2 和 AES 256 加密:
@RequiresApi(api = Build.VERSION_CODES.O)
public static String encrypt(String strToEncrypt, String SECRET_KEY, String SALT) {
try {
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec ivspec = new IvParameterSpec(iv);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 100000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
谢谢!
对于 Android SDK < 26 您可以使用 Will Glozer 编写的 PBKDF class,可在此处获取:https://github.com/wg/scrypt/blob/master/src/main/java/com/lambdaworks/crypto/PBKDF.java.
要导出 AES-256 的密钥,您可以这样调用 class:
byte[] secretKey = PBKDF.pbkdf2("HmacSHA256", passphraseByte, salt, PBKDF2_ITERATIONS, 32);
这是完整的 class 代码,以防将来它消失:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import static java.lang.System.arraycopy;
/**
* An implementation of the Password-Based Key Derivation Function as specified
* in RFC 2898.
*
* @author Will Glozer
*/
// source: https://github.com/wg/scrypt/blob/master/src/main/java/com/lambdaworks/crypto/PBKDF.java
// license: Apache License 2.0
public class PBKDF {
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param alg HMAC algorithm to use.
* @param P Password.
* @param S Salt.
* @param c Iteration count.
* @param dkLen Intended length, in octets, of the derived key.
*
* @return The derived key.
*
* @throws GeneralSecurityException
*/
public static byte[] pbkdf2(String alg, byte[] P, byte[] S, int c, int dkLen) throws GeneralSecurityException {
Mac mac = Mac.getInstance(alg);
mac.init(new SecretKeySpec(P, alg));
byte[] DK = new byte[dkLen];
pbkdf2(mac, S, c, DK, dkLen);
return DK;
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac Pre-initialized {@link Mac} instance to use.
* @param S Salt.
* @param c Iteration count.
* @param DK Byte array that derived key will be placed in.
* @param dkLen Intended length, in octets, of the derived key.
*
* @throws GeneralSecurityException
*/
public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[S.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(S, 0, block1, 0, S.length);
for (int i = 1; i <= l; i++) {
block1[S.length + 0] = (byte) (i >> 24 & 0xff);
block1[S.length + 1] = (byte) (i >> 16 & 0xff);
block1[S.length + 2] = (byte) (i >> 8 & 0xff);
block1[S.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
}
}
}