2010-08-10 143 views
71

我想用我自己的密鑰使用AES加密字符串。但是我在密鑰的位長上遇到了問題。你可以檢查我的代碼,看看我需要修復/更改。Java AES和使用我自己的密鑰

public static void main(String[] args) throws Exception { 
    String username = "[email protected]"; 
    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個字節」。我需要填寫我的鑰匙嗎?我應該怎麼做?

我還需要爲ECB或CBC設置任何東西嗎?

感謝

+5

[我覺得你缺乏隨機鹽的干擾(http://d37nnnqwv9amwr.cloudfront.net/photos/images/newsfeed/000/065/003/Darth-Vader-I-FIND-你缺-OF-誠信DISTURBING.jpg)。現在認真:在密碼學的背景下[SALT應該是隨機的](http://en.wikipedia.org/wiki/Salt_(cryptography)) – 2012-01-02 15:40:10

+13

哈哈,好笑。我其實有一個隨機鹽,但我清理了我的代碼,使我的問題更清楚。這就是爲什麼變量名爲SALT2。但對於遇到同樣問題並喜歡複製/粘貼代碼的其他人來說,這是很好的參考。 – 2012-03-23 18:40:53

回答

109

您應該使用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 download link密鑰大小,使用SHA-256散列和刪除陣列。 copyOf一行。 「ECB」是默認的密碼模式,「PKCS5Padding」是默認的填充。 你可以使用以下格式通過Cipher.getInstance字符串中使用不同的密碼模式和填充模式:「密碼/模式/填充」

對於使用CTS AES和PKCS5Padding的字符串:「AES/CTS/PKCS5Padding」

+0

這將起作用,但它會散列我的密碼,然後只使用前幾位。沒有更好的方法來做到這一點? – 2010-08-10 22:46:22

+4

沒有更好的方法來生成AES需要128/192/256位密鑰的關鍵原因。如果你沒有散列你的密鑰,只修剪輸入,它只會使用第一個16/24/32字節。所以生成一個哈希是唯一合理的方法。 – mknjc 2010-08-11 06:26:18

+1

太棒了,感謝getBytes()的提示和下載鏈接到Unlimited Strength Jurisdiction策略文件。 – 2010-08-12 18:03:41

13

您應該使用的KeyGenerator生成密鑰,

AES密鑰長度爲128,192和256位,具體取決於您要使用的密碼。

在本教程here

下面一起來看看是基於密碼的加密代碼,這必須通過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); 
+2

如何使用KeyGenerator使用密碼生成密鑰?我想根據密碼生成相同的密鑰。所以我可以稍後解密字符串。 – 2010-08-10 23:28:41

+0

你說的是基於密碼的加密而不是AES。我使用PBE的示例程序更新了我的答案 – Keibosh 2010-08-12 18:13:14

+1

嘗試使用PBEKDF2密鑰生成器,使用字符串「PBKDF2WithHmacSHA1」作爲「SecretKeyFactory」以獲得更新的加密。 – 2013-01-16 21:57:18

5
import java.security.Key; 
import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 
import sun.misc.*; 
import java.io.BufferedReader; 
import java.io.FileReader; 

public class AESFile 
{ 
private static String algorithm = "AES"; 
private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};// your key 

    // Performs Encryption 
    public static String encrypt(String plainText) throws Exception 
    { 
      Key key = generateKey(); 
      Cipher chiper = Cipher.getInstance(algorithm); 
      chiper.init(Cipher.ENCRYPT_MODE, key); 
      byte[] encVal = chiper.doFinal(plainText.getBytes()); 
      String encryptedValue = new BASE64Encoder().encode(encVal); 
      return encryptedValue; 
    } 

    // Performs decryption 
    public static String decrypt(String encryptedText) throws Exception 
    { 
      // generate key 
      Key key = generateKey(); 
      Cipher chiper = Cipher.getInstance(algorithm); 
      chiper.init(Cipher.DECRYPT_MODE, key); 
      byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedText); 
      byte[] decValue = chiper.doFinal(decordedValue); 
      String decryptedValue = new String(decValue); 
      return decryptedValue; 
    } 

//generateKey() is used to generate a secret key for AES algorithm 
    private static Key generateKey() throws Exception 
    { 
      Key key = new SecretKeySpec(keyValue, algorithm); 
      return key; 
    } 

    // performs encryption & decryption 
    public static void main(String[] args) throws Exception 
    { 
     FileReader file = new FileReader("C://myprograms//plaintext.txt"); 
     BufferedReader reader = new BufferedReader(file); 
     String text = ""; 
     String line = reader.readLine(); 
    while(line!= null) 
     { 
      text += line; 
    line = reader.readLine(); 
     } 
     reader.close(); 
    System.out.println(text); 

      String plainText = text; 
      String encryptedText = AESFile.encrypt(plainText); 
      String decryptedText = AESFile.decrypt(encryptedText); 

      System.out.println("Plain Text : " + plainText); 
      System.out.println("Encrypted Text : " + encryptedText); 
      System.out.println("Decrypted Text : " + decryptedText); 
    } 
} 
+3

也許再添加一些解釋性文字。 – DaGardner 2013-12-24 10:59:27

+1

不建議使用硬編碼密鑰 – sashank 2014-10-01 03:47:02

+0

問題:具有字節數組的keyValue有什麼意義?爲什麼我看到它被用來製作Key?可以用'SecretKey'來代替嗎?如果是這樣,怎麼樣? – Austin 2014-10-28 18:25:16

2

這將工作。

public class CryptoUtils { 

    private final String TRANSFORMATION = "AES"; 
    private final String encodekey = "1234543444555666"; 
    public String encrypt(String inputFile) 
      throws CryptoException { 
     return doEncrypt(encodekey, inputFile); 
    } 


    public String decrypt(String input) 
      throws CryptoException { 
    // return doCrypto(Cipher.DECRYPT_MODE, key, inputFile); 
    return doDecrypt(encodekey,input); 
    } 

    private String doEncrypt(String encodekey, String inputStr) throws CryptoException { 
     try { 

      Cipher cipher = Cipher.getInstance(TRANSFORMATION); 

      byte[] key = encodekey.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"); 

      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 

      byte[] inputBytes = inputStr.getBytes();  
      byte[] outputBytes = cipher.doFinal(inputBytes); 

      return Base64Utils.encodeToString(outputBytes); 

     } catch (NoSuchPaddingException | NoSuchAlgorithmException 
       | InvalidKeyException | BadPaddingException 
       | IllegalBlockSizeException | IOException ex) { 
      throw new CryptoException("Error encrypting/decrypting file", ex); 
     } 
    } 


    public String doDecrypt(String encodekey,String encrptedStr) { 
      try {  

       Cipher dcipher = Cipher.getInstance(TRANSFORMATION); 
       dcipher = Cipher.getInstance("AES"); 
       byte[] key = encodekey.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"); 

       dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 
      // decode with base64 to get bytes 

       byte[] dec = Base64Utils.decode(encrptedStr.getBytes()); 
       byte[] utf8 = dcipher.doFinal(dec); 

       // create new string based on the specified charset 
       return new String(utf8, "UTF8"); 

      } catch (Exception e) { 

      e.printStackTrace(); 

      } 
     return null; 
     } 
} 
0
byte[] seed = (SALT2 + username + password).getBytes(); 
    SecureRandom random = new SecureRandom(seed); 
    KeyGenerator generator; 
    generator = KeyGenerator.getInstance("AES"); 
    generator.init(random); 
    generator.init(256); 
    Key keyObj = generator.generateKey();