java 如何修复无效的AES密钥长度?

y4ekin9u  于 2023-06-04  发布在  Java
关注(0)|答案(4)|浏览(630)

我正在做一个文本加密和解密项目(遵循Struts 2)
每当我输入密码和纯文本时,我都会得到一个无效的AES密钥长度错误。

服务类

package com.anoncrypt.services;

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class SymAES
{
    private static final String ALGORITHM = "AES";
    private static byte[] keyValue= new byte[] { 'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' };

     public  String encode(String valueToEnc) throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGORITHM);
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encValue = c.doFinal(valueToEnc.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encValue);
        return encryptedValue;
    }

    public  String decode(String encryptedValue) throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGORITHM);
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    public  void start(String passcode)throws Exception
    {
        keyValue = passcode.getBytes();
    }
}

这就是错误

java.security.InvalidKeyException: Invalid AES key length: 6 bytes
    com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
    com.sun.crypto.provider.ElectronicCodeBook.init(ElectronicCodeBook.java:93)
    com.sun.crypto.provider.CipherCore.init(CipherCore.java:582)
    com.sun.crypto.provider.CipherCore.init(CipherCore.java:458)
    com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:307)
    javax.crypto.Cipher.implInit(Cipher.java:797)
    javax.crypto.Cipher.chooseProvider(Cipher.java:859)
    javax.crypto.Cipher.init(Cipher.java:1229)
    javax.crypto.Cipher.init(Cipher.java:1166)
    com.anoncrypt.services.SymAES.encode(SymAES.java:35)
    com.anoncrypt.actions.SymEncrypt.execute(SymEncrypt.java:24)
zqry0prt

zqry0prt1#

一般须知:

1.Key!=密码

  • SecretKeySpec需要密钥,而不是密码。见下文

1.这可能是由于禁止使用32字节密钥的策略限制。查看其他答案

您的情况

问题是第一个:您正在传递密码而不是密钥。
AES仅支持16、24或32字节的密钥大小。您要么需要提供确切的金额,要么从键入的内容中导出密钥。
有不同的方法可以从密码短语中派生密钥。Java为此提供了PBKDF 2实现。
我使用erickson的answer来描绘一个完整的画面(只有加密,因为解密是类似的,但包括分裂密文):

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

KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 1000000, 256); // AES-256
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = f.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encValue = c.doFinal(valueToEnc.getBytes());

byte[] finalCiphertext = new byte[encValue.length+2*16];
System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);

return finalCiphertext;

其他要记住的事项:

  • 始终使用完全限定的密码名称。AES在这种情况下并不合适,因为不同的JVM/JCE提供者可能使用不同的默认操作模式和填充。使用AES/CBC/PKCS5Padding。不要使用ECB模式,因为它在语义上不安全。
  • 如果您不使用ECB模式,则需要将IV与密文一起发送。这通常是通过在密文字节数组前面加上IV来实现的。IV会自动为您创建,您可以通过cipherInstance.getIV()获取。
  • 无论何时发送内容,都需要确保它在发送过程中没有被更改。用MAC实现加密是很困难的。我建议您使用认证模式,如CCM或GCM。
yquaqz18

yquaqz182#

我遇到了同样的问题,然后我把我的密钥设置为16字节,现在它工作正常。创建一个16字节的密钥。它肯定会工作。

7uhlpewt

7uhlpewt3#

您可以验证密钥长度限制:

int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
System.out.println("MaxAllowedKeyLength=[" + maxKeyLen + "].");
k4aesqcs

k4aesqcs4#

您可以使用此代码,此代码用于AES-256-CBC,或者您可以将其用于其他AES加密。密钥长度错误主要出现在256位加密中。
此错误是由于我们在SecretKeySpec中传递的编码或字符集名称引起的。假设,在我的例子中,我有一个长度为44的密钥,但是我不能用这个长密钥加密我的文本; Java抛出无效密钥长度的错误。因此,我在函数中传递我的密钥作为BASE64,它将我的44长度密钥转换为32字节,这是256位加密所必需的。

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Base64;

public class Encrypt {

    static byte [] arr = {1,2,3,4,5,6,7,8,9};

    // static byte [] arr = new byte[16];

      public static void main(String...args) {
        try {
         //   System.out.println(Cipher.getMaxAllowedKeyLength("AES"));
            Base64.Decoder decoder = Base64.getDecoder();
            // static byte [] arr = new byte[16];
            Security.setProperty("crypto.policy", "unlimited");
            String key = "Your key";
       //     System.out.println("-------" + key);

            String value = "Hey, i am adnan";
            String IV = "0123456789abcdef";
       //     System.out.println(value);
            // log.info(value);
          IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
            //    IvParameterSpec iv = new IvParameterSpec(arr);

        //    System.out.println(key);
            SecretKeySpec skeySpec = new SecretKeySpec(decoder.decode(key), "AES");
         //   System.out.println(skeySpec);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //    System.out.println("ddddddddd"+IV);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
       //     System.out.println(cipher.getIV());

            byte[] encrypted = cipher.doFinal(value.getBytes());
            String encryptedString = Base64.getEncoder().encodeToString(encrypted);

            System.out.println("encrypted string,,,,,,,,,,,,,,,,,,,: " + encryptedString);
            // vars.put("input-1",encryptedString);
            //  log.info("beanshell");
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

相关问题