2017-07-14 226 views
0

我有一个可能需要验证密码的应用程序。
此应用程序不处理任何敏感数据,因为这个“密码”是由主机选择,并通过另一个通道(WhatsApp或其他)通知“客户端”。 所以当一个客户端想要认证时,主机会生成一个随机的字符串发送给客户端。
客户端随后使用用户输入的密码加密此随机字符串。
加密的随机字符串是发送回主机。
主机使用由相同密码生成的密钥来解密此加密的字符串。
如果不加密的,原始的字符串匹配,用户登录
这是我想出了这么远。仅基于密码生成AES密钥

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
我应该使用不同的算法,还是应该通过散列密码本身或者完全不同的方法来生成盐? 我想避免必须随随随机字符串一起发送生成的盐

回答

1

您应该给PBEKeySpec它需要为AES密钥生成足够的位。你需要双方对相同的盐,所以你可以这样做:

byte[] salt = new byte[8]; 
System.arraycopy(randomString.getBytes("UTF-8"), 0, salt, 0, 8); 

现在你PBEKeySpecnew PBEKeySpec(password, salt, 10, 128)代替,一切都应该工作。