Java AES 和使用我自己的密钥编辑:旧答案

2022-08-31 10:55:17

我想使用自己的密钥使用 AES 加密字符串。但是我在密钥的位长度方面遇到了问题。你能检查我的代码,看看我需要修复/更改什么。

public static void main(String[] args) throws Exception {
    String username = "bob@google.org";
    String password = "Password1";
    String secretID = "BlahBlahBlah";
    String SALT2 = "deliciously salty";

    // Get the Key
    byte[] key = (SALT2 + username + password).getBytes();
    System.out.println((SALT2 + username + password).getBytes().length);

    // Need to pad key for AES
    // TODO: Best way?

    // Generate the secret key specs.
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    // Instantiate the cipher
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

    byte[] encrypted = cipher.doFinal((secrectID).getBytes());
    System.out.println("encrypted string: " + asHex(encrypted));

    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] original = cipher.doFinal(encrypted);
    String originalString = new String(original);
    System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " + asHex(original));
}

现在我得到一个例外“无效的AES密钥长度:86字节”。我需要垫钥匙吗?我该怎么做?

另外,我需要为欧洲央行或CBC设置任何东西吗?

谢谢


答案 1

编辑:

正如注释中所写的那样,旧代码不是“最佳实践”。您应该使用具有高迭代计数的密钥生成算法,如 PBKDF2。您还应该至少部分使用非静态(意味着每个“身份”独占)盐。如果可能的话,随机生成并与密文一起存储。

    SecureRandom sr = SecureRandom.getInstanceStrong();
    byte[] salt = new byte[16];
    sr.nextBytes(salt);

    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 128 * 8);
    SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);
    Cipher aes = Cipher.getInstance("AES");
    aes.init(Cipher.ENCRYPT_MODE, key);

===========

旧答案

应使用 SHA-1 从密钥生成哈希,并将结果修剪为 128 位(16 字节)。

此外,不要通过getBytes()从字符串生成字节数组,它使用平台默认字符集。因此,密码“blaöä”在不同的平台上产生不同的字节数组。

byte[] key = (SALT2 + username + password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

编辑:如果您需要256位作为密钥大小,则需要下载“Java加密扩展(JCE)无限强度管辖权策略文件”Oracle下载链接,使用SHA-256作为哈希并删除Arrays.copyOf行。“ECB”是默认的密码模式,“PKCS5填充”是默认的填充。您可以使用以下格式通过 Cipher.getInstance 字符串使用不同的密码模式和填充模式:“密码/模式/填充”

对于使用CTS和PKCS5填充的AES,字符串为:“AES /CTS / PKCS5Padding”


答案 2

您应该使用密钥生成器来生成密钥,

AES 密钥长度为 128、192 和 256 位,具体取决于要使用的密码。

在这里查看教程

这是基于密码的加密的代码,它具有通过 System.in 输入密码,您可以根据需要将其更改为使用存储的密码。

        PBEKeySpec pbeKeySpec;
        PBEParameterSpec pbeParamSpec;
        SecretKeyFactory keyFac;

        // Salt
        byte[] salt = {
            (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
            (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
        };

        // Iteration count
        int count = 20;

        // Create PBE parameter set
        pbeParamSpec = new PBEParameterSpec(salt, count);

        // Prompt user for encryption password.
        // Collect user password as char array (using the
        // "readPassword" method from above), and convert
        // it into a SecretKey object, using a PBE key
        // factory.
        System.out.print("Enter encryption password:  ");
        System.out.flush();
        pbeKeySpec = new PBEKeySpec(readPassword(System.in));
        keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

        // Create PBE Cipher
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

        // Initialize PBE Cipher with key and parameters
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

        // Our cleartext
        byte[] cleartext = "This is another example".getBytes();

        // Encrypt the cleartext
        byte[] ciphertext = pbeCipher.doFinal(cleartext);