如何修复无效的 AES 密钥长度? [英] How to fix Invalid AES key length?

查看:59
本文介绍了如何修复无效的 AES 密钥长度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从事一个文本加密和解密项目(遵循 Struts 2)

I am working on a text encryption and decryption project (following Struts 2)

每当我输入密码和纯文本时,我都会收到无效的 AES 密钥长度错误.

Whenever I enter the password and the plain text I get a Invalid AES Key Length error.

服务类

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();
    }
}

<小时>

这是错误


And this is the error

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)

推荐答案

一般须知:

  1. 密钥 != 密码
    • SecretKeySpec 需要密钥,而不是密码.见下文
  1. Key != Password
    • SecretKeySpec expects a key, not a password. See below

就你而言

问题是第 1 点:您传递的是密码而不是密钥.

In your case

The problem is number 1: you are passing the password instead of the key.

AES 仅支持 16、24 或 32 字节的密钥大小.您要么需要提供准确的金额,要么从您输入的内容中推导出密钥.

AES only supports key sizes of 16, 24 or 32 bytes. You either need to provide exactly that amount or you derive the key from what you type in.

有多种方法可以从密码短语中导出密钥.为此,Java 提供了 PBKDF2 实现.

There are different ways to derive the key from a passphrase. Java provides a PBKDF2 implementation for such a purpose.

我使用了erickson的答案来描绘一个完整的画面(只有加密,因为解密是相似的,但包括拆分密文):

I used erickson's answer to paint a complete picture (only encryption, since the decryption is similar, but includes splitting the ciphertext):

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

KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 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;

<小时>

其他注意事项:


Other things to keep in mind:

  • 始终使用完全限定的密码名称.AES 在这种情况下是不合适的,因为不同的 JVM/JCE 提供者可能使用不同的默认操作模式和填充.使用 AES/CBC/PKCS5Padding.不要使用 ECB 模式,因为它在语义上不安全.
  • 如果您不使用 ECB 模式,则需要将 IV 与密文一起发送.这通常是通过在密文字节数组中添加 IV 前缀来完成的.IV 是自动为您创建的,您可以通过 cipherInstance.getIV() 获取它.
  • 无论何时发送某些东西,您都需要确保它在发送过程中没有被更改.很难用 MAC 正确实现加密.我建议您使用 CCM 或 GCM 等身份验证模式.
  • Always use a fully qualified Cipher name. AES is not appropriate in such a case, because different JVMs/JCE providers may use different defaults for mode of operation and padding. Use AES/CBC/PKCS5Padding. Don't use ECB mode, because it is not semantically secure.
  • If you don't use ECB mode then you need to send the IV along with the ciphertext. This is usually done by prefixing the IV to the ciphertext byte array. The IV is automatically created for you and you can get it through cipherInstance.getIV().
  • Whenever you send something, you need to be sure that it wasn't altered along the way. It is hard to implement a encryption with MAC correctly. I recommend you to use an authenticated mode like CCM or GCM.

这篇关于如何修复无效的 AES 密钥长度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆