仅根据密码生成 AES 密钥
Generate AES key based on password only
我有一个应用程序可能需要密码进行身份验证。
此应用程序不处理任何敏感数据,因为此 "password" 由主机选择并通过另一个渠道(WhatsApp 或其他)告知 "clients"。
因此,当客户端想要进行身份验证时,主机会生成一个随机字符串,并将其发送给客户端。
然后客户端用用户输入的密码加密这个随机字符串。
加密的随机字符串被发送回主机。
主机使用相同密码生成的密钥解密此加密字符串。
如果未加密和原始字符串匹配,则用户已登录。
这是我到目前为止想出的:
String base64;
char[] password = "password".toCharArray();
String randomString = new BigInteger(130, new SecureRandom()).toString(32);
try {
//Encrypt Client Side
SecretKey key = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512").generateSecret(new PBEKeySpec(password)).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
base64 = Base64.getEncoder().encodeToString(cipher.doFinal(randomString.getBytes(StandardCharsets.UTF_8)));
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
try {
//Decrypt Server Side
SecretKey key = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512").generateSecret(new PBEKeySpec(password)).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
//Check if both strings match
System.out.println(Arrays.equals(cipher.doFinal(Base64.getDecoder().decode(base64)), randomString.getBytes(StandardCharsets.UTF_8)));
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
不幸的是,这段代码抛出异常:java.security.spec.InvalidKeySpecException: Salt not found
我应该使用不同的算法,还是应该通过散列密码本身或完全不同的方法来生成盐?
我想避免必须将生成的盐与随机字符串
一起发送
您应该提供 PBEKeySpec
为 AES 密钥生成足够位所需的内容。两面都需要相同的盐,所以你可以这样做:
byte[] salt = new byte[8];
System.arraycopy(randomString.getBytes("UTF-8"), 0, salt, 0, 8);
现在将您的 PBEKeySpec
替换为 new PBEKeySpec(password, salt, 10, 128)
,一切正常。
我有一个应用程序可能需要密码进行身份验证。
此应用程序不处理任何敏感数据,因为此 "password" 由主机选择并通过另一个渠道(WhatsApp 或其他)告知 "clients"。
因此,当客户端想要进行身份验证时,主机会生成一个随机字符串,并将其发送给客户端。
然后客户端用用户输入的密码加密这个随机字符串。
加密的随机字符串被发送回主机。
主机使用相同密码生成的密钥解密此加密字符串。
如果未加密和原始字符串匹配,则用户已登录。
这是我到目前为止想出的:
String base64;
char[] password = "password".toCharArray();
String randomString = new BigInteger(130, new SecureRandom()).toString(32);
try {
//Encrypt Client Side
SecretKey key = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512").generateSecret(new PBEKeySpec(password)).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
base64 = Base64.getEncoder().encodeToString(cipher.doFinal(randomString.getBytes(StandardCharsets.UTF_8)));
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
try {
//Decrypt Server Side
SecretKey key = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512").generateSecret(new PBEKeySpec(password)).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
//Check if both strings match
System.out.println(Arrays.equals(cipher.doFinal(Base64.getDecoder().decode(base64)), randomString.getBytes(StandardCharsets.UTF_8)));
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
不幸的是,这段代码抛出异常:java.security.spec.InvalidKeySpecException: Salt not found
我应该使用不同的算法,还是应该通过散列密码本身或完全不同的方法来生成盐?
我想避免必须将生成的盐与随机字符串
您应该提供 PBEKeySpec
为 AES 密钥生成足够位所需的内容。两面都需要相同的盐,所以你可以这样做:
byte[] salt = new byte[8];
System.arraycopy(randomString.getBytes("UTF-8"), 0, salt, 0, 8);
现在将您的 PBEKeySpec
替换为 new PBEKeySpec(password, salt, 10, 128)
,一切正常。