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


当前回答

考虑使用Spring安全加密模块

Spring Security Crypto模块提供对对称加密、密钥生成和密码编码的支持。该代码作为核心模块的一部分分发,但不依赖于任何其他Spring Security(或Spring)代码。

它为加密提供了一个简单的抽象,似乎与这里的要求相匹配,

“标准”加密方法是使用PKCS #5的PBKDF2(基于密码的密钥推导函数#2)的256位AES。此方法需要Java 6。用于生成SecretKey的密码应保存在安全的地方,不能被共享。在加密数据被泄露的情况下,salt用于防止针对密钥的字典攻击。还应用了一个16字节的随机初始化向量,因此每个加密消息都是唯一的。

内部结构与埃里克森的答案相似。

正如问题中所指出的,这也需要Java加密扩展(JCE)无限强度管辖策略(否则您将遇到InvalidKeyException:非法密钥大小)。它可以在Java 6、Java 7和Java 8上下载。

示例使用

import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.security.crypto.keygen.KeyGenerators;

public class CryptoExample {
    public static void main(String[] args) {
        final String password = "I AM SHERLOCKED";  
        final String salt = KeyGenerators.string().generateKey();
        
        TextEncryptor encryptor = Encryptors.text(password, salt);      
        System.out.println("Salt: \"" + salt + "\"");
        
        String textToEncrypt = "*royal secrets*";
        System.out.println("Original text: \"" + textToEncrypt + "\"");
        
        String encryptedText = encryptor.encrypt(textToEncrypt);
        System.out.println("Encrypted text: \"" + encryptedText + "\"");
        
        // Could reuse encryptor but wanted to show reconstructing TextEncryptor
        TextEncryptor decryptor = Encryptors.text(password, salt);
        String decryptedText = decryptor.decrypt(encryptedText);
        System.out.println("Decrypted text: \"" + decryptedText + "\"");
        
        if(textToEncrypt.equals(decryptedText)) {
            System.out.println("Success: decrypted text matches");
        } else {
            System.out.println("Failed: decrypted text does not match");
        }       
    }
}

样本输出,

Salt: "feacbc02a3a697b0"
Original text: "*royal secrets*"
Encrypted text: "7c73c5a83fa580b5d6f8208768adc931ef3123291ac8bc335a1277a39d256d9a" 
Decrypted text: "*royal secrets*"
Success: decrypted text matches

其他回答

考虑使用Spring安全加密模块

Spring Security Crypto模块提供对对称加密、密钥生成和密码编码的支持。该代码作为核心模块的一部分分发,但不依赖于任何其他Spring Security(或Spring)代码。

它为加密提供了一个简单的抽象,似乎与这里的要求相匹配,

“标准”加密方法是使用PKCS #5的PBKDF2(基于密码的密钥推导函数#2)的256位AES。此方法需要Java 6。用于生成SecretKey的密码应保存在安全的地方,不能被共享。在加密数据被泄露的情况下,salt用于防止针对密钥的字典攻击。还应用了一个16字节的随机初始化向量,因此每个加密消息都是唯一的。

内部结构与埃里克森的答案相似。

正如问题中所指出的,这也需要Java加密扩展(JCE)无限强度管辖策略(否则您将遇到InvalidKeyException:非法密钥大小)。它可以在Java 6、Java 7和Java 8上下载。

示例使用

import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.security.crypto.keygen.KeyGenerators;

public class CryptoExample {
    public static void main(String[] args) {
        final String password = "I AM SHERLOCKED";  
        final String salt = KeyGenerators.string().generateKey();
        
        TextEncryptor encryptor = Encryptors.text(password, salt);      
        System.out.println("Salt: \"" + salt + "\"");
        
        String textToEncrypt = "*royal secrets*";
        System.out.println("Original text: \"" + textToEncrypt + "\"");
        
        String encryptedText = encryptor.encrypt(textToEncrypt);
        System.out.println("Encrypted text: \"" + encryptedText + "\"");
        
        // Could reuse encryptor but wanted to show reconstructing TextEncryptor
        TextEncryptor decryptor = Encryptors.text(password, salt);
        String decryptedText = decryptor.decrypt(encryptedText);
        System.out.println("Decrypted text: \"" + decryptedText + "\"");
        
        if(textToEncrypt.equals(decryptedText)) {
            System.out.println("Success: decrypted text matches");
        } else {
            System.out.println("Failed: decrypted text does not match");
        }       
    }
}

样本输出,

Salt: "feacbc02a3a697b0"
Original text: "*royal secrets*"
Encrypted text: "7c73c5a83fa580b5d6f8208768adc931ef3123291ac8bc335a1277a39d256d9a" 
Decrypted text: "*royal secrets*"
Success: decrypted text matches

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

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

然后执行以下步骤:

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

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

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

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

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

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

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

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(字符串,提供者)。但这可能是一个复杂的过程。

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