2014-01-15 78 views
0

我正在嘗試編寫一個使用AES加密/解密文本的類。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 

有沒有什麼辦法可以產生不會導致AES密鑰轉換引發異常的密鑰字符串?

回答

0

AES需要一個長度爲128,192或256位的密鑰。嘗試使用更長的鍵。

+0

我猜測密鑰的長度在生成時是正確的,但在加密發生時變短。 –

1

爲了能夠使用AES算法進行加密,您需要將密鑰基於至少128位字符串。 (其他值也是合法的,但我沒有讓他們在我的頭上)

要轉換成你可以採取128 8

128/8 = 16 alpha-numeric characters 

分在您提供的密鑰字符串所需的字符數這應該可以解決你的問題。

編輯: Base64是編碼字符串的方式不同:關於BASE64評論

答案。 BASE64編碼的結果可能是128位字符串,但不是默認值。 BASE64編碼的結果實際上沒有默認的長度。結果可能是8個字符或512個,或者其他符合BASE64編碼規則的輸出,這一切都取決於您正在編碼的字符串。

+0

Base64是一個128位的字符串嗎? –

0

這裏的工作示例生成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; 
} 

然後你可以使用該密鑰來加密\解密你的代碼(在我轉換加密值hexdecimal的例子格式:

/** 
    * 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; 
    } 
+0

問題不在於加密/解密。這是關於生成密鑰並將該密鑰存儲在某個地方,以便以後可以將其用於未來的加密和解密任務。 –

0

您的問題與AES或加密技術無關,但您試圖將隨機字節序列解釋爲UTF-8編碼字符(b是AES密鑰):

String decoded = new String(b, "UTF-8");

這是不行的,因爲你的字節數組很可能包含幾個字節序列,這些字節序列對於UTF-8是無效的。如果您需要字節數組內容的字符串表示形式,則必須使用例如base64或十六進制編碼。