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

Ie。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();

这里的代码

EDIT

我实际上是把密码填充到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”部分:-)


当前回答

我过去所做的是通过SHA256之类的东西散列密钥,然后从散列中提取字节到密钥字节[]。

在你有字节[]之后,你可以简单地做:

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());

其他回答

与带外的接收者共享密码(一个char[])和盐(一个字节[]-由securerrandom选择的8个字节构成一个好的盐——不需要保密)。然后从这些信息中推导出一个好的关键字:

/* 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");

魔术数字(可以在某处定义为常数)65536和256分别是密钥派生迭代计数和密钥大小。

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

密钥大小可以减少到128位,这仍然被认为是“强”加密,但如果发现攻击削弱了AES,它并没有提供太多的安全边际。

Used with a proper block-chaining mode, the same derived key can be used to encrypt many messages. In Cipher Block Chaining (CBC), a random initialization vector (IV) is generated for each message, yielding different cipher text even if the plain text is identical. CBC may not be the most secure mode available to you (see AEAD below); there are many other modes with different security properties, but they all use a similar random input. In any case, the outputs of each encryption operation are the cipher text and the initialization 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));

存储密文和iv。在解密时,SecretKey以完全相同的方式重新生成,使用使用具有相同salt和迭代参数的密码。初始化密码与此密钥和初始化向量存储的消息:

/* 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包含了对AEAD密码模式的API支持,OpenJDK和Oracle发行版中包含的“SunJCE”提供者从Java 8开始实现了这些。强烈推荐其中一种模式来代替CBC;它将保护数据的完整性以及他们的隐私。


带有“非法密钥大小或默认参数”消息的java.security.InvalidKeyException意味着加密强度是有限的;无限强度权限策略文件不在正确的位置。在JDK中,它们应该放在${JDK}/jre/lib/security下

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

(可能对其他有类似需求的人有帮助)

我有类似的需求,需要在Java中使用AES-256-CBC加密和解密。

要实现(或指定)256字节加密/解密,Java加密扩展(JCE)策略应该设置为“无限”

可以在java中设置。$JAVA_HOME/jre/lib/security(适用于JDK)或$JAVA_HOME/lib/security(适用于jre)下的安全文件

crypto.policy =无限

或者在代码中

Security.setProperty("crypto.policy", "unlimited");

Java 9及更高版本默认启用此功能。

使用这个类进行加密。它的工作原理。

public class ObjectCrypter {


    public static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] mes) 
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException, IOException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
        return  cipher.doFinal(mes);

    }

    public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] bytes) 
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException, IOException, ClassNotFoundException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return  cipher.doFinal(bytes);

    }
}

这些是ivBytes和一个随机键;

String key = "e8ffc7e56311679f12b6fc91aa77a5eb";

byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
keyBytes = key.getBytes("UTF-8");

我过去所做的是通过SHA256之类的东西散列密钥,然后从散列中提取字节到密钥字节[]。

在你有字节[]之后,你可以简单地做:

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());

考虑使用Encryptor4j,我是它的作者。

首先,确保在继续之前安装了“无限强度管辖策略”文件,以便可以使用256位AES密钥。

然后执行以下步骤:

String password = "mysupersecretpassword"; 
Key key = KeyFactory.AES.keyFromPassword(password.toCharArray());
Encryptor encryptor = new Encryptor(key, "AES/CBC/PKCS7Padding", 16);

您现在可以使用加密器加密您的消息。如果愿意,还可以执行流加密。它会自动生成并预先为您提供安全的静脉注射。

如果这是一个你想要压缩的文件,看看这个答案 使用JAVA使用AES加密大文件是一种更简单的方法。