Java 256 位 AES 基于密码的加密

标签 java encryption cryptography passwords aes

我需要实现 256 位 AES 加密,但是我在网上找到的所有示例都使用“KeyGenerator”来生成 256 位 key ,但我想使用自己的密码。如何创建自己的 key ?我尝试将其填充为 256 位,但随后我收到一条错误消息,提示 key 太长。我确实安装了无限权限补丁,所以这不是问题:)

即。 KeyGenerator 看起来像这样...

// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available

// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();

Code taken from here

编辑

我实际上是将密码填充到 256 个字节,而不是位,这太长了。以下是我现在使用的一些代码,我对此有更多经验。

byte[] key = null; // TODO
byte[] input = null; // TODO
byte[] output = null;
SecretKeySpec keySpec = null;
keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(input)

你需要自己做的“TODO”位:-)

最佳答案

共享password(一个char[])和salt(一个byte[]——8个字节由 SecureRandom 选择的盐是带外接收者的好盐(不需要保密)。然后从这些信息中推导出一个好的 key :

/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

魔数(Magic Number)(可以在某处定义为常量)65536 和 256 分别是 key 派生迭代次数和 key 大小。

迭代 key 派生函数需要大量的计算工作,这可以防止攻击者快速尝试许多不同的密码。可以根据可用的计算资源更改迭代次数。

key 大小可以减少到 128 位,这仍然被认为是“强”加密,但如果发现削弱 AES 的攻击,它不会提供太多安全余量。

与适当的 block 链接模式一起使用,相同的派生 key 可用于加密许多消息。在 Cipher Block Chaining (CBC) ,为每条消息生成一个随机初始化 vector (IV),即使明文相同,也会产生不同的密文。 CBC 可能不是您可以使用的最安全的模式(请参阅下面的 AEAD);还有许多其他具有不同安全属性的模式,但它们都使用类似的随机输入。在任何情况下,每个加密操作的输出都是密文初始化 vector :

/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes(StandardCharsets.UTF_8));

存储 ciphertextiv。解密时,SecretKey 以完全相同的方式重新生成,使用具有相同盐和迭代参数的密码。使用此 key 初始化密码与消息一起存储的初始化 vector :

/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), StandardCharsets.UTF_8);
System.out.println(plaintext);

Java 7 包含的 API support for AEAD cipher modes ,并且 OpenJDK 和 Oracle 发行版中包含的“SunJCE”提供程序从 Java 8 开始实现这些。强烈建议使用其中一种模式代替 CBC;它将保护数据的完整性及其隐私。


带有“非法 key 大小或默认参数”消息的java.security.InvalidKeyException 表示加密强度受到限制;无限强度管辖权政策文件不在正确的位置。在 JDK 中,它们应该放在 ${jdk}/jre/lib/security

根据问题描述,听起来策略文件没有正确安装。系统可以很容易地拥有多个 Java 运行时;仔细检查以确保使用了正确的位置。

关于Java 256 位 AES 基于密码的加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/992019/

相关文章:

javascript - Math.random 可以替换为生成具有相同参数的数字的 CSPRNG 吗?

java - 使用 Maven 依赖项的轻量级方法?

java - Golang中的AES加密和Java中的解密

go - 如何在 Go 中为 SSH 生成 ECDSA key 对?

Java AES-128 ECB 加密

php openssl - RSA_padding_check_PKCS1_type_2 和 RSA_EAY_PRIVATE_DECRYPT :padding check failed:rsa_eay. c:602:

cryptography - RSA 密码系统的蒙哥马利模乘法的最终减法

Java 文本字段错误检查

java - Hibernate session 在初始提交失败后未刷新数据库中的数据

java - Android Studio Ble Gatt 连接将数据写入自定义服务特征