2010-08-10 21 views
71

Chcę zaszyfrować ciąg za pomocą AES z moim własnym kluczem. Ale mam problem z długością klucza. Czy możesz przejrzeć mój kod i zobaczyć, co muszę naprawić/zmienić.Java AES i używanie mojego własnego klucza

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

Teraz otrzymuję wyjątek "Nieprawidłowy klucz AES Długość: 86 bajtów". Czy muszę podeprzeć mój klucz? Jak mam to zrobić?

Czy muszę ustawić cokolwiek dla EBC lub CBC?

Dzięki

+5

[znajdę swój brak losowej soli niepokojące] (http://d37nnnqwv9amwr.cloudfront.net/photos/images/newsfeed/000/065/003/Darth-Vader-I-FIND- TWOJE-BRAKU-WIARA-DISTURBING.jpg). Teraz poważnie: w kontekście kryptografii [SALT powinna być losowa] (http://en.wikipedia.org/wiki/Salt_ (kryptografia)) –

+13

Haha, zabawne. Właściwie to mam losową sól, ale wyczyściłem kod, aby moje pytanie było bardziej przejrzyste. Dlatego zmienna nazywa się SALT2. Ale dobre referencje dla innych, którzy napotykają ten sam problem i lubią kopiować/wklejać kod. –

Odpowiedz

109

Należy użyć SHA-1, aby wygenerować skrót z klucza i przyciąć wynik do 128 bitów (16 bajtów).

Dodatkowo nie generuj tablic bajtowych z ciągów znaków przez getBytes() używa on domyślnego zestawu znaków platformy. Tak więc hasło "blaöä" daje w wyniku różne tablice bajtów na różnych platformach.

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"); 

Edit: Jeśli potrzebujesz 256 bit jako kluczowych rozmiarach, które trzeba pobrać "Pliki Java Cryptography Extension (JCE) Nieograniczona Polityka Siła jurysdykcji" Oracle download link używać SHA-256 jako hash i usunąć tablic. linia copyOf. "ECB" jest domyślnym trybem szyfrowania, a "PKCS5Padding" domyślnym dopełnieniem. Można stosować różne tryby szyfr i tryby wyściółka przez Cipher.getInstance napisu za pomocą następującego formatu: "Cipher/MODE/wypełniania"

AES z użyciem CTS i PKCS5Padding ciąg jest: "AES/CTS/PKCS5Padding"

+0

To zadziała, ale będzie mieszać moje hasło, a następnie używać tylko kilku pierwszych bitów. Nie ma lepszego sposobu na zrobienie tego? –

+4

Nie ma lepszego sposobu na wygenerowanie klucza, ponieważ AES potrzebuje klucza 128/192/256. Jeśli nie mieszasz klucza i tylko przycinasz wejście, używałbyś tylko pierwszych 16/24/32 bajtów. Zatem generowanie skrótu jest jedynym rozsądnym sposobem. – mknjc

+1

Awesome, dziękuję za wskazówkę na getBytes() i link do pobrania do plików zasad jurysdykcji nieograniczonej siły. –

13

należy użyć KeyGenerator do wygenerowania klucza,

długości klucza AES są 128, 192, i 256 bit w zależności od szyfru, którego chcesz użyć.

Spójrz na samouczku here

Oto kod na podstawie haseł szyfrowania, hasło to ma być wprowadzony przez System.in można zmienić użyć przechowywanego hasła, jeśli chcesz.

 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

Jak wygenerować mój klucz za pomocą hasła za pomocą KeyGenerator? Chcę wygenerować ten sam klucz na podstawie hasła. Więc mogę odszyfrować ciąg później. –

+0

To, o czym mówisz, to szyfrowanie oparte na hasłach, a nie AES.Zaktualizowałem swoją odpowiedź za pomocą przykładowego programu dla PBE – Keibosh

+1

Zamiast tego spróbuj użyć generatora kluczy PBEKDF2, używając ciągu "PBKDF2WithHmacSHA1" dla 'SecretKeyFactory', aby uzyskać bardziej aktualne szyfrowanie. –

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

Może dodać więcej tekstu wyjaśniającego. – DaGardner

+1

Nie jest zalecane, aby mieć klucz zakodowany na stałe – sashank

+0

Pytanie, jaki jest sens posiadania 'keyValue', z tablicą bajtów? Widzę, że używa się go do stworzenia Klucza, dlaczego? Czy można coś zrobić używając np. 'SecretKey' zamiast? Jeśli tak to jak? – Austin

2

Ta praca będzie działać.

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