我需要实现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”部分:-)


当前回答

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

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

然后执行以下步骤:

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

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

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

其他回答

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

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

然后执行以下步骤:

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

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

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

与带外的接收者共享密码(一个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运行时;仔细检查以确保使用了正确的位置。

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

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

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

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

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

从字节数组生成你自己的键很简单:

byte[] raw = ...; // 32 bytes in size for a 256 bit key
Key skey = new javax.crypto.spec.SecretKeySpec(raw, "AES");

但是创建一个256位的密钥是不够的。如果密钥生成器不能为您生成256位密钥,那么Cipher类可能也不支持AES 256位。您说您已经安装了无限权限补丁,因此应该支持AES-256密码(但也应该支持256位密钥,因此这可能是一个配置问题)。

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skey);
byte[] encrypted = cipher.doFinal(plainText.getBytes());

缺乏AES-256支持的解决方法是采用一些免费的AES-256实现,并将其用作自定义提供程序。这涉及到创建自己的Provider子类并将其与Cipher一起使用。getInstance(字符串,提供者)。但这可能是一个复杂的过程。