Android 4.2 ha rotto il codice AES per crittografare / decrittografare

È la prima volta che chiedo aiuto qui, il mio dipartimento (un governo), ho pubblicato un'applicazione sul mercato (Google Play) e la crittografia e la descrizione funzionavano molto bene fino a ieri quando ho ricevuto il Jelly Bean 4.2 sul mio Nexus. La crittografia funziona bene, è in realtà crittografare le informazioni da memorizzare. Anche se decrittografo, ottengo un'exception esattamente come questo: block pad bloccato . Ho controllato la string ed è coerente con altri dispositivi (utilizzando lo stesso tasto per scopi di prova), il che significa che è esattamente lo stesso. Il problema è che abbiamo bisogno di mantenere la compatibilità con le precedenti versioni precedenti, il che significa che se cambio qualcosa nel codice, dovrebbe essere in grado di leggere le vecchie informazioni crittografate. Le informazioni criptate sono memorizzate su SQLite, dovute a che ho bisogno di codificarlo in Base64. L'exception accade su questa linea byte [] decrypted = cipher.doFinal (crittografato);

Ecco la mia class:

  • Navigazione Colore del colore dell'elemento del cassetto per l'elemento selezionato
  • Android getActionBar vs getSupportActionBar?
  • Come submit la richiesta POST HTTP e ricevere la risposta?
  • Come eseguire il mio progetto node.js su android?
  • Android ottiene i dati vCard da Intent
  • In Cordova, come posso specificare nomi di pacchetti diversi per ios e android?
  • import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import android.util.Base64; public class EncodeDecodeAES { private final static String HEX = "0123456789ABCDEF"; public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); String fromHex = toHex(result); String base64 = new String(Base64.encodeToString(fromHex.getBytes(), 0)); return base64; } public static String decrypt(String seed, String encrypted) throws Exception { String base64 = new String(Base64.decode(encrypted, 0)); byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = toByte(base64); byte[] result = decrypt(rawKey, enc); return new String(result); } public static byte[] encryptBytes(String seed, byte[] cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext); return result; } public static byte[] decryptBytes(String seed, byte[] encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = decrypt(rawKey, encrypted); return result; } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); try { kgen.init(256, sr); } catch (Exception e) { // Log.w(LOG, "This device doesn't suppor 256bits, trying 192bits."); try { kgen.init(192, sr); } catch (Exception e1) { // Log.w(LOG, "This device doesn't suppor 192bits, trying 128bits."); kgen.init(128, sr); } } SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length() / 2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2 * buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); } } 

    Vorrei sapere (se qualcuno mi aiuti), cosa faccio male con questo codice, o se è un problema con Android 4.2 e se è un problema con 4.2 se ha qualche soluzione?

    Grazie

  • AES ottiene risultati diversi in iOS (Obj-C) e Android (Java)
  • IllegalBlockSizeException quando si cerca di crittografare e decifrare una string con AES
  • Android AES 256-bit Crittografare i dati
  • Alternative per DatatypeConverter in Android
  • Encrypt / Decrypt string tra Java e PHP
  • crittografia / decrittografia di android AES
  • 2 Solutions collect form web for “Android 4.2 ha rotto il codice AES per crittografare / decrittografare”

    AVVERTENZA Questa risposta utilizza SecureRandom per la derivazione chiave, che è contraria allo scopo. SecureRandom è un generatore di numbers casuali e non è garantito per produrre l'output coerente tra le piattaforms (che è ciò che ha causato il problema nella domanda). Il meccanismo appropriato per la derivazione chiave è SecretKeyFactory . Questo post del blog di nelenkov ha una buona redazione su questo tema. Questa risposta fornisce una soluzione per i casi in cui si è costretti da un requisito di compatibilità all'indietro; tuttavia, dovresti migrare verso una corretta implementazione il più presto ansible.


    Ok, oggi con un po 'più tempo per fare qualche ricerca (e rimuovere il mio vecchio post che in realtà non funzionava, mi dispiace) ho una risposta che funziona bene, in realtà lo ho testato su Android 2.3.6, 2.3.7 (che è sostanzialmente lo stesso), 4.0.4 e 4.2 e ha funzionato. Ho fatto alcune ricerche su questi collegamenti:

    Errore di crittografia su Android 4.2 ,

    Errore BouncyCastle AES quando si aggiorna a 1.45 ,

    http://en.wikipedia.org/wiki/Padding_(cryptography)

    Poi sono arrivato in questa soluzione grazie al contenuto di tali link. Ecco la mia class (e ora funziona bene):

      package au.gov.dhsJobSeeker.main.readwriteprefssettings.util; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import android.util.Base64; public class EncodeDecodeAES { private final static String HEX = "0123456789ABCDEF"; private final static int JELLY_BEAN_4_2 = 17; private final static byte[] key = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // static { // Security.addProvider(new BouncyCastleProvider()); // } public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); String fromHex = toHex(result); String base64 = new String(Base64.encodeToString(fromHex.getBytes(), 0)); return base64; } public static String decrypt(String seed, String encrypted) throws Exception { byte[] seedByte = seed.getBytes(); System.arrayscopy(seedByte, 0, key, 0, ((seedByte.length < 16) ? seedByte.length : 16)); String base64 = new String(Base64.decode(encrypted, 0)); byte[] rawKey = getRawKey(seedByte); byte[] enc = toByte(base64); byte[] result = decrypt(rawKey, enc); return new String(result); } public static byte[] encryptBytes(String seed, byte[] cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext); return result; } public static byte[] decryptBytes(String seed, byte[] encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = decrypt(rawKey, encrypted); return result; } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); // , "SC"); SecureRandom sr = null; if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) { sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); } else { sr = SecureRandom.getInstance("SHA1PRNG"); } sr.setSeed(seed); try { kgen.init(256, sr); // kgen.init(128, sr); } catch (Exception e) { // Log.w(LOG, "This device doesn't suppor 256bits, trying 192bits."); try { kgen.init(192, sr); } catch (Exception e1) { // Log.w(LOG, "This device doesn't suppor 192bits, trying 128bits."); kgen.init(128, sr); } } SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); // /ECB/PKCS7Padding", "SC"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); // /ECB/PKCS7Padding", "SC"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length() / 2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2 * buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); } } 

    Tuttavia la risposta PBrando (sopra, funziona anche perché dovrei segnare come soluzione), anche se stavo cercando un modo per mantenere una dimensione simile di file dell'applicazione con ora, ho scelto di utilizzare questo approccio. Perché non ho bisogno di importre barattoli esterni. Ho messo tutta la class per il caso in cui qualcuno di voi stia avendo lo stesso problema e vuole solo copiare e incollarlo.

    Potresti provare a utilizzare la libreria SpongyCastle. È il BouncyCastle patchato per compilare su Android.

    Poiché è compatibile con BouncyCastle (solo il nome del pacchetto e il provider di servizi sono diversi, "SC" invece di "BC") e Android utilizza un sottoinsieme di BouncyCastle, l'integrazione di SpongyCastle nel codice dovrebbe essere un'operazione banale.

    Potete trovare SpongyCastle qui: http://rtyley.github.com/spongycastle/

    Fare attenzione a registrare SpongyCastle come spiegato nel loro sito web:

     static { Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); } 

    Quando si ottengono istanze di oggetti crypto, specificare anche il provider ("SC").

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.