我有一个应用程序,需要在配置文件中存储一些秘密密码,如数据库和ftp密码/详细信息。我环顾四周,发现了许多使用AES的加密/解密解决方案,但我似乎不知道如何在不改变密钥的情况下使其工作。这意味着我可以加密和解密(使用相同的秘密密钥),但在重启等过程中保持持久性。我似乎无法让秘密钥匙保持不变。下面的示例显示了我的工作方法:
String secret = Encryptor.encrpytString("This is secret");
String test = Encryptor.decrpytString(secret);
System.out.println(test); //This is secret is printed
到目前为止还不错。然而,如果我运行它一次,我可能会得到'2Vhht/L80UlQ184S3rlAWw=='的值作为我的秘密,下一次它是'MeC4zCf9S5wUUKAu8rvpCQ==',所以大概密钥正在改变。我假设我对这个问题应用了一些反直觉的逻辑,如果有人能解释一下a)我做错了什么,或者b)一个允许我存储密码信息的解决方案,密码信息可以用提供的信息加密和检索。
我的方法如下:
private static final String salt = "SaltySalt";
private static byte [] ivBytes = null;
private static byte[] getSaltBytes() throws Exception {
return salt.getBytes("UTF-8");
}
private static char[] getMasterPassword() {
return "SuperSecretPassword".toCharArray();
}
private static byte[] getIvBytes() throws Exception {
if (ivBytes == null) {
//I don't have the parameters, so I'll generate a dummy encryption to create them
encrpytString("test");
}
return ivBytes;
}
public static String encrpytString (String input) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536,256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(input.getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrpytString (String input) throws Exception {
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(input);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536, 256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(getIvBytes()));
byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}
谢谢你的帮助!
你需要setSeed()
之前
class Encryptor {
static final String salt = "SaltSalt";
public static byte[] encryptString(String input) throws Exception {
byte[] bytes = input.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("AES");
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(salt.getBytes("UTF-8"));
keyGenerator.init(256, secureRandom);
Key key = keyGenerator.generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] a = cipher.doFinal(bytes);
return a;
}
public static String decryptString(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(salt.getBytes("UTF-8"));
keyGenerator.init(256, secureRandom);
Key key = keyGenerator.generateKey();
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(input);
String result = new String(decrypted, "UTF-8");
return result;
}
}
使用静态初始化向量,例如零IV:
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
由于您正在存储密码,您可能希望使用随机IV和/或随机salt并将其与密文一起存储,以便相同的密码不会加密到相同的密文。
好的,看来我已经找到我问题的答案了。我的信息来源于这篇文章。据我所知,IV(初始化向量)用于将熵添加到加密过程中。每次创建新密码时,Java都会创建一个稍有不同的IV。因此,有两种解决方案:
据我所知,选项1不是很好的实践;因此,选择2是正确的。我理解,应该可以简单地将IV附加到加密字符串中(因为仍然需要保密),因此在解密时可以重建IV。
这里是几乎完整的解决方案。我仍然得到一些填充错误的解密(见我的评论)。我现在没有时间花在它上面,所以作为一个临时措施,我立即尝试解密一个加密的字符串,并继续尝试(迭代),直到它工作。它似乎有大约50%的命中率,我加密的频率不够,所以它是一个性能问题。如果有人能提出一个解决方案(只是为了完整起见),那就太好了。
private static final String salt = "SaltySalt";
private static final int IV_LENGTH = 16;
private static byte[] getSaltBytes() throws Exception {
return salt.getBytes("UTF-8");
}
private static char[] getMasterPassword() {
return "SuperSecretPassword".toCharArray();
}
public static String encrpytString (String input) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536,256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(input.getBytes("UTF-8"));
byte[] finalByteArray = new byte[ivBytes.length + encryptedTextBytes.length];
System.arraycopy(ivBytes, 0, finalByteArray, 0, ivBytes.length);
System.arraycopy(encryptedTextBytes, 0, finalByteArray, ivBytes.length, encryptedTextBytes.length);
return DatatypeConverter.printBase64Binary(finalByteArray);
}
public static String decrpytString (String input) throws Exception {
if (input.length() <= IV_LENGTH) {
throw new Exception("The input string is not long enough to contain the initialisation bytes and data.");
}
byte[] byteArray = DatatypeConverter.parseBase64Binary(input);
byte[] ivBytes = new byte[IV_LENGTH];
System.arraycopy(byteArray, 0, ivBytes, 0, 16);
byte[] encryptedTextBytes = new byte[byteArray.length - ivBytes.length];
System.arraycopy(byteArray, IV_LENGTH, encryptedTextBytes, 0, encryptedTextBytes.length);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536, 256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}
这是我的密码 抱歉,如果我的代码一团糟。
本文向大家介绍Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签,包括了Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签的使用技巧和注意事项,需要的朋友参考一下 Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签,具体代码如下所示: ps:Python3 RSA加密
问题内容: 我找到了用Java实施AES加密/解密的指南,并试图理解每一行并将其放入自己的解决方案中。但是,我没有完全理解它,因此出现了问题。最终目标是拥有基于密码的加密/解密。我已经阅读了有关此的其他文章/ stackoverflow帖子,但是大多数文章没有提供足够的解释(我对Java加密非常陌生) 我现在的主要问题是,即使设置了 I,最后还是会得到不同的Base64结果(每次都是随机的,但是我
本文向大家介绍java基于Des对称加密算法实现的加密与解密功能详解,包括了java基于Des对称加密算法实现的加密与解密功能详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java基于Des对称加密算法实现的加密与解密功能。分享给大家供大家参考,具体如下: Des 加密相关类介绍: SecureRandom 这个类是继承自java.util.Random 这个类 SecureRan
本文向大家介绍php基于openssl的rsa加密解密示例,包括了php基于openssl的rsa加密解密示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了php基于openssl的rsa加密解密。分享给大家供大家参考,具体如下: PS:关于加密解密感兴趣的朋友还可以参考本站在线工具: 密码安全性在线检测: http://tools.jb51.net/password/my_passwo
本文向大家介绍java基于AES对称加密算法实现的加密与解密功能示例,包括了java基于AES对称加密算法实现的加密与解密功能示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java基于AES对称加密算法实现的加密与解密功能。分享给大家供大家参考,具体如下: 注:SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解