2010-08-10 41 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();