Java AES密钥字符串引发异常

Java AES密钥字符串引发异常,java,cryptography,Java,Cryptography,我正在尝试编写一个类,该类将使用AES加密/解密文本 我想生成一个密钥,将该密钥存储在数据库列中,并使用该密钥加密/解密包含该密钥的数据库行中的相应文本 下面是我编写的用于生成密钥并执行加密和解密任务的类 import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.Key; impor

我正在尝试编写一个类,该类将使用AES加密/解密文本

我想生成一个密钥,将该密钥存储在数据库列中,并使用该密钥加密/解密包含该密钥的数据库行中的相应文本

下面是我编写的用于生成密钥并执行加密和解密任务的类

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class StringDecryptor {

    public static String encrypt(String text, String key) {
        Key aesKey = null;
        Cipher cipher = null;
        byte[] encrypted = null;
        try {
            aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, aesKey);
            encrypted = cipher.doFinal(text.getBytes());
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        }
        return new String(encrypted);
    }

    public static String decrypt(String text, String key) {
        Key aesKey = null;
        Cipher cipher;
        String decrypted = null;
        try {
            aesKey  = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, aesKey);
            decrypted = new String(cipher.doFinal(text.getBytes()));
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        }
        return decrypted;
    }

    public static String generateKey() {
        SecretKey secretKey = null;
        try {
            secretKey = KeyGenerator.getInstance("AES").generateKey();
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        }
        String keyString = bytesToString(secretKey.getEncoded());
        return keyString;
    }

    public static String bytesToString(byte[] b) {
        String decoded = null;
        try {
            decoded = new String(b, "UTF-8");            
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
        }
        return decoded;
    }

    public static void main(String args[]) {
        String key = generateKey();
        System.out.println("key: " + key);
        String str = "This is the original string...";
        String enc = encrypt(str, key);
        System.out.println("enc: " + enc);
        String dec = decrypt(enc, key);
        System.out.println("dec: " + dec);
    }
}
此代码正在引发以下异常

SEVERE: null
java.security.InvalidKeyException: Invalid AES key length: 26 bytes
    at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:372)
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052)
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1010)
    at javax.crypto.Cipher.implInit(Cipher.java:786)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
    at javax.crypto.Cipher.init(Cipher.java:1213)
    at javax.crypto.Cipher.init(Cipher.java:1153)
    at com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:27)
    at com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)

Exception in thread "main" java.lang.NullPointerException
    at java.lang.String.<init>(String.java:556)
    at com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:42)
    at com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)
Java Result: 1
严重:空
java.security.InvalidKeyException:无效AES密钥长度:26字节
在com.sun.crypto.provider.aesciper.engineGetKeySize(aesciper.java:372)上
位于javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052)
位于javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1010)
位于javax.crypto.Cipher.implInit(Cipher.java:786)
在javax.crypto.Cipher.chooseProvider(Cipher.java:849)
位于javax.crypto.Cipher.init(Cipher.java:1213)
位于javax.crypto.Cipher.init(Cipher.java:1153)
位于com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:27)
位于com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)
线程“main”java.lang.NullPointerException中出现异常
位于java.lang.String。(String.java:556)
位于com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:42)
位于com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)
Java结果:1

有没有办法生成不会导致AES密钥转换引发异常的密钥字符串?

AES需要长度为128、192或256位的密钥。尝试使用更长的密钥。

要使用AES算法进行加密,您需要将密钥基于至少128位的字符串。(其他价值观也是合法的,但我脑子里没有)

要将其转换为提供的密钥字符串中所需的字符数,可以取128除以8

128 / 8 = 16 alpha-numeric characters
这应该能解决你的问题

编辑:

关于BASE64的评论回复:
BASE64是一种不同的字符串编码方式。BASE64编码的结果可能是128位字符串,但默认情况下不是。BASE64编码的结果实际上没有默认长度。结果可能是8个字符或512,或其他符合BASE64编码规则的输出,这完全取决于您正在编码的字符串。

以下是生成AES密钥的工作示例:

private static SecretKeySpec key;
private static final int ENCRYPTION_KEY_SIZE = 128;

private static SecretKey generateKey() throws NoSuchAlgorithmException {

KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(ENCRYPTION_KEY_SIZE);

SecretKey key = keyGenerator.generateKey();
return key;
}

public void createNewEncrytionKey() throws NoSuchAlgorithmException, Exception {
SecretKey newKey = generateKey();
saveKey(newKey);
LogUtil.logMessage("createNewEncrytionKey", "New random encryption key was created.", logger);
key = (SecretKeySpec) newKey;
}
然后可以使用该密钥加密\解密代码(在示例中,我将加密值转换为十六进制格式:

/**
     * Encrypt a given text
     * 
     * @param value String to encrypt
     * @return encrypted String value
     */
    public static String encrypt(String value) {

    if (null == key) {
        throw new RuntimeException("Secret encryption key not found!");
    }

    Cipher c;
    String result = null;
    try {
        c = Cipher.getInstance(ENCRYPTION_ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);
        // 1. convert value to byte array
        byte[] bvalue = value.getBytes();
        // 2. convert to encrypted byte array
        byte[] encrypted = c.doFinal(bvalue);
        // 3. convert to hexadecimal representation
        result = toHexString(encrypted);
    } catch (Exception e) {
        LogUtil.logError("encrypt", e, logger);
    }

    return result;
    }


/**
     * Decrypt a given text
     * 
     * @param value encrypted String value
     * @return Decrypted value
     */
    public static String decrypt(String value) {

    if (null == key) {
        throw new RuntimeException("Secret encryption key not found!");
    }

    Cipher c;
    String result = null;
    try {
        // 1. convert hex to encrypted byte array
        byte[] encrypted = hexToByteArray(value);
        // 2. convert to decrypted byte array
        c = Cipher.getInstance(ENCRYPTION_ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decrypted = c.doFinal(encrypted);
        // 3. convert to plain string
        result = bytesToString(decrypted);
    } catch (Exception e) {
        LogUtil.logError("decrypt", e, logger);
    }

    return result;
    }

您的问题与AES或加密无关。但是,您正在尝试将随机字节序列解释为UTF-8编码字符(
b
为AES密钥):

String decoded=新字符串(b,“UTF-8”);


这是行不通的,因为您的字节数组很可能包含多个字节序列,这些字节序列对UTF-8无效。如果您需要字节数组内容的字符串表示,则必须使用base64或hex编码等方式对数据进行编码。

我猜密钥在生成时的长度是正确的,但在加密时变短了发生了错误。Base64是128位字符串吗?问题不在于加密/解密。问题在于生成一个密钥并将该密钥存储在某个位置,以便我可以在以后的加密和解密任务中使用它。