2010-12-29 13 views
10

chcę przekonwertować ciąg na tajny kluczW jaki sposób można przekonwertować ciąg na tajny klucz

public void generateCode(String keyStr){ 
KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
kgen.init(128); // 192 and 256 bits may not be available 
// Generate the secret key specs. 
secretKey skey=keyStr; //How can I make the casting here 
//SecretKey skey = kgen.generateKey(); 
byte[] raw = skey.getEncoded(); 
} 

próbuję użyć BASE64Decoder zamiast tajny klucz, ale w obliczu problemu, który jest nie mogę podać długość klucza.

EDIT: Chcę wywołać tę funkcję z innego miejsca

static public String encrypt(String message , String key , int keyLength) throws Exception { 
    // Get the KeyGenerator 
    KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
    kgen.init(keyLength); // 192 and 256 bits may not be available 
    // Generate the secret key specs. 
    SecretKey skey = key; //here is the error 
    byte[] raw = skey.getEncoded(); 
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
    // Instantiate the cipher 
    Cipher cipher = Cipher.getInstance("AES"); 

    cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 
    System.out.println("msg is" + message + "\n raw is" + raw); 
    byte[] encrypted = cipher.doFinal(message.getBytes()); 
    String cryptedValue = new String(encrypted); 
    System.out.println("encrypted string: " + cryptedValue); 
    return cryptedValue; 
} 

Jeśli ktoś mógłby pomóc, byłbym bardzo wdzięczny.

+0

"KeyGenerator kgen" nigdy nie jest używany. Co tam się dzieje? 'KeyGenerator' służy do wyboru nowego losowego klucza. Ale wygląda na to, że chcesz ponownie użyć istniejącego klucza, który jest w jakiś sposób przechowywany w 'String' (kodowanie Base-64, być może?) – erickson

Odpowiedz

37

Brak kontroli integralności, dla tych szczególnych powodów

  1. Potrzeba nie wynika z przypadku użycia. Tryb
  2. "AES/GCM/NoPadding" jest dostępny tylko z Javy 7
  3. Zależy od użytkownika, jeśli chce wdrożyć, np. HMAC i/lub AESCMAC (zalecane).
  4. Wymagałoby to co najmniej dodatkowego klucza i dwóch pełnych przejść.

Jeśli masz implementację trybu GCM po obu stronach - np. używając Bouncy Castle na Java 6 - proszę, idźcie na to, bo jest o wiele bezpieczniej (o ile "IV" jest naprawdę wyjątkowy). Zmiana implementacji powinna być naprawdę łatwa.

notatki wdrożeniowe dotyczące szyfrowania

  1. Ta implementacja nie jest bezpieczny, gdy stosuje się w nieograniczonym roli klient/serwer z powodu ataków oracle przekładki (wymagają one 128 prób na bajt lub niższym średnio niezależnych od algorytm lub wielkość klucza). Będziesz musiał użyć MAC, HMAC lub Signature na zaszyfrowanych danych i zweryfikować je przed odszyfrowaniem, aby wdrożyć go w trybie klient/serwer.
  2. Decrypt zwróci wartość null, jeśli odszyfrowanie się nie powiedzie. Może to tylko oznaczać wyjątek wypełnienia, który powinien być odpowiednio obsługiwany (czy ostrzegałem przed wyskakującymi atakami oracle?)
  3. Nieprawidłowe klucze zostaną zwrócone jako InvalidArgumentException.
  4. Wszystkie inne wyjątki związane z bezpieczeństwem są "usuwane pod tabelą", ponieważ oznaczają, że środowisko wykonawcze Java jest niepoprawne. Na przykład obsługa "UTF-8" i "AES/CBC/PKCS5Padding" wymaga wymaganej dla każdej implementacji Java SE.

Niektóre inne notatki

  1. Proszę nie próbować przeciwieństwem i wstawić bajtów bezpośrednio do ciągu wejściowego metody szyfrowanie (używając new String(byte[]) na przykład). Metoda może nie działać w trybie cichym!
  2. Zoptymalizowany pod kątem czytelności. Przejdź do implementacji Base64 i implementacji CipherStream, jeśli wolisz prędkość i lepsze wykorzystanie pamięci.
  3. Potrzebujesz co najmniej Java 6 SE lub zgodnej do uruchomienia tego kodu.
  4. szyfrowanie/deszyfrowanie może nie dla AES kluczowych rozmiarach ponad 128 bit jak może potrzebne pliki strategii dla nieograniczonego szyfrowania (dostępne z Oracle)
  5. Beware of regulacjami rządowymi podczas eksportowania szyfrowania.
  6. Ta implementacja używa kluczy hex zamiast kluczy base64, ponieważ są one wystarczająco małe, a hex jest po prostu łatwiejszy do edycji/weryfikacji ręcznie.
  7. Używane kodowanie/dekodowanie hex i base64 pobrane z JDK, nie są potrzebne żadne biblioteki zewnętrzne.
  8. Uber jest prosty w użyciu, ale oczywiście niezbyt zorientowany obiektowo, bez buforowania instancji obiektów używanych w szyfrowaniu/odszyfrowywaniu. Refaktor do woli.

OK, tutaj jest trochę kodu ...

public static String encrypt(final String plainMessage, 
      final String symKeyHex) { 
     final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex); 

     final byte[] encodedMessage = plainMessage.getBytes(Charset 
       .forName("UTF-8")); 
     try { 
      final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      final int blockSize = cipher.getBlockSize(); 

      // create the key 
      final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES"); 

      // generate random IV using block size (possibly create a method for 
      // this) 
      final byte[] ivData = new byte[blockSize]; 
      final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG"); 
      rnd.nextBytes(ivData); 
      final IvParameterSpec iv = new IvParameterSpec(ivData); 

      cipher.init(Cipher.ENCRYPT_MODE, symKey, iv); 

      final byte[] encryptedMessage = cipher.doFinal(encodedMessage); 

      // concatenate IV and encrypted message 
      final byte[] ivAndEncryptedMessage = new byte[ivData.length 
        + encryptedMessage.length]; 
      System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize); 
      System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage, 
        blockSize, encryptedMessage.length); 

      final String ivAndEncryptedMessageBase64 = DatatypeConverter 
        .printBase64Binary(ivAndEncryptedMessage); 

      return ivAndEncryptedMessageBase64; 
     } catch (InvalidKeyException e) { 
      throw new IllegalArgumentException(
        "key argument does not contain a valid AES key"); 
     } catch (GeneralSecurityException e) { 
      throw new IllegalStateException(
        "Unexpected exception during encryption", e); 
     } 
    } 

    public static String decrypt(final String ivAndEncryptedMessageBase64, 
      final String symKeyHex) { 
     final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex); 

     final byte[] ivAndEncryptedMessage = DatatypeConverter 
       .parseBase64Binary(ivAndEncryptedMessageBase64); 
     try { 
      final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      final int blockSize = cipher.getBlockSize(); 

      // create the key 
      final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES"); 

      // retrieve random IV from start of the received message 
      final byte[] ivData = new byte[blockSize]; 
      System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize); 
      final IvParameterSpec iv = new IvParameterSpec(ivData); 

      // retrieve the encrypted message itself 
      final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length 
        - blockSize]; 
      System.arraycopy(ivAndEncryptedMessage, blockSize, 
        encryptedMessage, 0, encryptedMessage.length); 

      cipher.init(Cipher.DECRYPT_MODE, symKey, iv); 

      final byte[] encodedMessage = cipher.doFinal(encryptedMessage); 

      // concatenate IV and encrypted message 
      final String message = new String(encodedMessage, 
        Charset.forName("UTF-8")); 

      return message; 
     } catch (InvalidKeyException e) { 
      throw new IllegalArgumentException(
        "key argument does not contain a valid AES key"); 
     } catch (BadPaddingException e) { 
      // you'd better know about padding oracle attacks 
      return null; 
     } catch (GeneralSecurityException e) { 
      throw new IllegalStateException(
        "Unexpected exception during decryption", e); 
     } 
    } 

Zastosowanie:

String plain = "Zaphod's just zis guy, ya knöw?"; 
    String encrypted = encrypt(plain, "000102030405060708090A0B0C0D0E0F"); 
    System.out.println(encrypted); 
    String decrypted = decrypt(encrypted, "000102030405060708090A0B0C0D0E0F"); 
    if (decrypted != null && decrypted.equals(plain)) { 
     System.out.println("Hey! " + decrypted); 
    } else { 
     System.out.println("Bummer!"); 
    } 
+2

Aby użyć szyfrowania w trybie' 'AES/GCM/NoPadding" 'w Java 7, zamień kod dla 'IvParameterSpec' z ['Parametry GCMParameterSpec = new GCMParameterSpec (blockSize * Byte.SIZE, ivData);'] (http://docs.oracle.com/javase/7/docs/api/javax/crypto/spec/ GCMParameterSpec.html) i nie zapomnij obsłużyć ['AEADBadTagException'] (http://docs.oracle.com/javase/7/docs/api/javax/crypto'/AEADBadTagException.html), aby wychwycić wyjątki integralności. Bouncy działa po prostu używając '" AES/GCM/NoPadding "' i rzuci wyjątek BadPaddingException, zwracając wartość null. –

+0

Ah, AEADBadTagException faktycznie rozszerza BadPaddingException, więc obsługa wyjątków powinna być nadal dobra. –

+0

Muszę powiedzieć ... to było wspaniałe ogłoszenie! :] – Kounavi

3

Oto wersja z użyciem klasy Base64 Util zamiast DatatypeConverter

public static String encrypt(final String plainMessage, 
          final String symKeyHex) { 
    final byte[] symKeyData = Base64.decode(symKeyHex,Base64.DEFAULT); 

    final byte[] encodedMessage = plainMessage.getBytes(Charset 
      .forName("UTF-8")); 
    try { 
     final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     final int blockSize = cipher.getBlockSize(); 

     // create the key 
     final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES"); 

     // generate random IV using block size (possibly create a method for 
     // this) 
     final byte[] ivData = new byte[blockSize]; 
     final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG"); 
     rnd.nextBytes(ivData); 
     final IvParameterSpec iv = new IvParameterSpec(ivData); 

     cipher.init(Cipher.ENCRYPT_MODE, symKey, iv); 

     final byte[] encryptedMessage = cipher.doFinal(encodedMessage); 

     // concatenate IV and encrypted message 
     final byte[] ivAndEncryptedMessage = new byte[ivData.length 
       + encryptedMessage.length]; 
     System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize); 
     System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage, 
       blockSize, encryptedMessage.length); 

     final String ivAndEncryptedMessageBase64 = Base64.encodeToString(ivAndEncryptedMessage,Base64.DEFAULT); 

     return ivAndEncryptedMessageBase64; 
    } catch (InvalidKeyException e) { 
     throw new IllegalArgumentException(
       "key argument does not contain a valid AES key"); 
    } catch (GeneralSecurityException e) { 
     throw new IllegalStateException(
       "Unexpected exception during encryption", e); 
    } 
} 

public static String decrypt(final String ivAndEncryptedMessageBase64, 
          final String symKeyHex) { 
    final byte[] symKeyData = Base64.decode((symKeyHex),Base64.DEFAULT); 

    final byte[] ivAndEncryptedMessage = Base64.decode(ivAndEncryptedMessageBase64,Base64.DEFAULT); 
    try { 
     final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     final int blockSize = cipher.getBlockSize(); 

     // create the key 
     final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES"); 

     // retrieve random IV from start of the received message 
     final byte[] ivData = new byte[blockSize]; 
     System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize); 
     final IvParameterSpec iv = new IvParameterSpec(ivData); 

     // retrieve the encrypted message itself 
     final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length 
       - blockSize]; 
     System.arraycopy(ivAndEncryptedMessage, blockSize, 
       encryptedMessage, 0, encryptedMessage.length); 

     cipher.init(Cipher.DECRYPT_MODE, symKey, iv); 

     final byte[] encodedMessage = cipher.doFinal(encryptedMessage); 

     // concatenate IV and encrypted message 
     final String message = new String(encodedMessage, 
       Charset.forName("UTF-8")); 

     return message; 
    } catch (InvalidKeyException e) { 
     throw new IllegalArgumentException(
       "key argument does not contain a valid AES key"); 
    } catch (BadPaddingException e) { 
     // you'd better know about padding oracle attacks 
     return null; 
    } catch (GeneralSecurityException e) { 
     throw new IllegalStateException(
       "Unexpected exception during decryption", e); 
    } 
} 

tylko przypomnienie dla tych, którzy otrzymają wyjątek Wypełnienie. Upewnij się, że używasz prawidłowej długości klucza. Podpowiedź: spójrz na post Maarten: jego sześciokąt jest dokładnie 32;) To nie jest zbieg okoliczności :)

Powiązane problemy