2015-05-21 40 views
5

Ho una chiave hardcoded con cui voglio crittografare una stringa prima di memorizzarla in SharedPreferences. Questo è il codice che ho finora:IllegalBlockSizeException quando si tenta di crittografare e decodificare una stringa con AES

public class TokenEncryptor { 

    private final static String TOKEN_KEY = "91a29fa7w46d8x41"; 

    public static String encrypt(String plain) { 
     try { 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); 
      SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec); 
      return new String(cipher.doFinal(plain.getBytes())); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    public static String decrypt(String encoded) { 
     try { 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); 
      SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); 
      cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec); 
      return new String(cipher.doFinal(encoded.getBytes())); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 
} 

Sembra essere la cattura un'eccezione alla fine del decrypt metodo:

javax.crypto.IllegalBlockSizeException: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

Qualcuno mi può punto nella giusta direzione? Ho la sensazione che sto facendo qualcosa di sbagliato nella creazione di istanze IvParameterSpec.

+1

La chiave è lunga solo 16 byte, quindi stai parlando di AES-128 e non AES-256. –

+0

@ArtjomB. dovrei semplicemente cambiarlo in 32 byte per renderlo AES-256? Le mie scuse per non essere informato su questo, è la prima volta che devo affrontare la crittografia – Oleksiy

+0

Sì, se aumenti la dimensione della chiave a 24 o 32 byte, AES-192 o AES-256 verranno utilizzati automaticamente. –

risposta

5

Quando si crittografa una stringa con AES, viene restituita una matrice di byte. Provare a convertire quei byte direttamente in una stringa (new String(cipher.doFinal(plaintextBytes))) causerà tutti i tipi di problemi. Se si richiede che l'output del metodo di crittografia sia una stringa, utilizzare Base64 anziché tentare una conversione diretta. Nel metodo di decrittografia, convertire la stringa Base64 in una matrice di byte prima di decrittografare la matrice di byte.

Inoltre, non utilizzare getBytes() poiché l'uscita dipende dalle impostazioni predefinite del sistema. Utilizzare getBytes("utf-8") o qualsiasi altra cosa. Ciò elimina l'ambiguità.

+2

[Q: encoder e decodificatore Base64] (http: // stackoverflow.it/questions/4322182/codificatore-base64 e decodificatore) –

8

Solo nel caso qualcuno è interessato (o si sente troppo pigro per fare le loro ricerche), ecco il codice risultato AES-256 crittografia e la decrittografia che ho messo insieme, con l'aiuto della risposta e commenti accettato:

public class TokenEncryptor { 

    private final static String TOKEN_KEY = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw"; 

    public static String encrypt(String plain) { 
     try { 
      byte[] iv = new byte[16]; 
      new SecureRandom().nextBytes(iv); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); 
      byte[] cipherText = cipher.doFinal(plain.getBytes("utf-8")); 
      byte[] ivAndCipherText = getCombinedArray(iv, cipherText); 
      return Base64.encodeToString(ivAndCipherText, Base64.NO_WRAP); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    public static String decrypt(String encoded) { 
     try { 
      byte[] ivAndCipherText = Base64.decode(encoded, Base64.NO_WRAP); 
      byte[] iv = Arrays.copyOfRange(ivAndCipherText, 0, 16); 
      byte[] cipherText = Arrays.copyOfRange(ivAndCipherText, 16, ivAndCipherText.length); 

      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); 
      return new String(cipher.doFinal(cipherText), "utf-8"); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    private static byte[] getCombinedArray(byte[] one, byte[] two) { 
     byte[] combined = new byte[one.length + two.length]; 
     for (int i = 0; i < combined.length; ++i) { 
      combined[i] = i < one.length ? one[i] : two[i - one.length]; 
     } 
     return combined; 
    } 

} 
+0

Mi dispiace, ma perché abbiamo una riga "nuovo SecureRandom(). nextBytes (iv);" ? Il valore di ritorno non viene utilizzato, giusto? – zkvarz

+1

@zkvarz: il metodo gestisce l'array di byte assegnato -> non esiste un valore di ritorno –

+0

@NinoHandler Ok, grazie. – zkvarz

3

È un'estensione della risposta di Artjom B e funziona per me.

public String encryptMsg(String message, SecretKey secret) 
      throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { 
     Cipher cipher = null; 
     cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secret); 
     byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8")); 
     return Base64.encodeToString(cipherText, Base64.NO_WRAP); 
    } 

public String decryptMsg(String cipherText, SecretKey secret) 
     throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException { 
    Cipher cipher = null; 
    cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secret); 
    byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP); 
    String decryptString = new String(cipher.doFinal(decode), "UTF-8"); 
    return decryptString; 
}