La crittografia AES-128 per Android e IPhone (risultato)

Sto cercando di cifrare un testo utilizzando l’algoritmo AES, sia su Android e IPhone piattaforme. Il mio problema è che, anche utilizzando la crittografia/decrittografia algoritmo AES-128) e fissa le variabili (chiave, IV, modalità), ottengo risultati diversi su entrambe le piattaforme. Io sono inclusi esempi di codice da entrambe le piattaforme, che sto usando per testare la crittografia/decrittografia. Gradirei qualche aiuto nel determinare che cosa sto facendo di sbagliato.

  • Chiave: “123456789abcdefg”
  • IV: “1111111111111111”
  • Testo Normale: “HelloThere”
  • Modalità: “AES/CBC/NoPadding”

Il Codice Di Android:

public class Crypto {
    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());
        return toHex(result);
    }

    public static String decrypt(String seed, String encrypted)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("CBC");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
        kgen.init(128, sr); //192 and 256 bits may not be available
        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));
    }
}

IPhone (Objective-C), Codice:

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData { 

    NSData* secretKey = [Cipher md5:cipherKey];

    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;

    uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));

    status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                         [secretKey bytes], kCCKeySizeAES128, iv, &cryptor);

    if (status != kCCSuccess) {
        return nil;
    }

    size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);

    void * buf = malloc(bufsize * sizeof(uint8_t));
    memset(buf, 0x0, bufsize);

    size_t bufused = 0;
    size_t bytesTotal = 0;

    status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
                         buf, bufsize, &bufused);

    if (status != kCCSuccess) {
        free(buf);
        CCCryptorRelease(cryptor);
        return nil;
    }

    bytesTotal += bufused;

    status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);

    if (status != kCCSuccess) {
        free(buf);
        CCCryptorRelease(cryptor);
        return nil;
    }

    bytesTotal += bufused;

    CCCryptorRelease(cryptor);

    return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}

+ (NSData *) md5:(NSString *) stringToHash {

    const char *src = [stringToHash UTF8String];

    unsigned char result[CC_MD5_DIGEST_LENGTH];

    CC_MD5(src, strlen(src), result);

    return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}

Alcuni dei miei riferimenti :

  • Che encrypt() metodo stai usando? La tua domanda è un casino. Solo fornire il codice essenziale.
  • è possibile utilizzare questa soluzione funziona per me : [inserire descrizione del link qui][1] [1]: stackoverflow.com/questions/17535918/…
  • Perché avete bisogno di dati criptati per essere uguale? Probabilmente avrete la possibilità di rendere il codice meno sicuro, senza motivo. Nella maggior parte dei casi di utilizzo decifrati solo i dati devono essere uguali. Vedere crypto.stackexchange.com/q/5094
  • codingaffairs.blogspot.com/2016/06/…



5 Replies
  1. 15

    Per iPhone ho usato AESCrypt-ObjC, e per Android di utilizzare questo codice:

    public class AESCrypt {
    
      private final Cipher cipher;
      private final SecretKeySpec key;
      private AlgorithmParameterSpec spec;
    
    
      public AESCrypt(String password) throws Exception
      {
        //hash password with SHA-256 and crop the output to 128-bit for key
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(password.getBytes("UTF-8"));
        byte[] keyBytes = new byte[32];
        System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
    
        cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        key = new SecretKeySpec(keyBytes, "AES");
        spec = getIV();
      }       
    
      public AlgorithmParameterSpec getIV()
      {
        byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
        IvParameterSpec ivParameterSpec;
        ivParameterSpec = new IvParameterSpec(iv);
    
        return ivParameterSpec;
      }
    
      public String encrypt(String plainText) throws Exception
      {
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
        String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");
    
        return encryptedText;
      }
    
      public String decrypt(String cryptedText) throws Exception
      {
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT);
        byte[] decrypted = cipher.doFinal(bytes);
        String decryptedText = new String(decrypted, "UTF-8");
    
        return decryptedText;
      }
    }
    • -1 non usare un fisso IV. crypto.stackexchange.com/q/5094
    • Questo è stato fatto per allineare il codice di Android con AESCrypt-ObjC iOS Biblioteca. Aggiungere AESCrypt-ObjC non si mantengono da me.
    • Il sopra citato codice di Android e AESCrypt-ObjC iOS codice funziona come oggi. Grazie.
  2. 7

    Mi fa nessuna meraviglia che si ottengono risultati diversi.

    Il problema è che l’uso improprio di un SHA1PRNG per la derivazione della chiave. Per quanto ne so non c’è uno standard comune come un SHA1PRNG lavorare internamente. AFAIR anche la J2SE e Bouncycaste attuazione di output risultati diversi utilizzando lo stesso seme.

    E quindi della realizzazione del vostro getRawKey(byte[] seed) genererà una chiave casuale. Se si utilizza la chiave per la crittografia che si stanno ottenendo un risultato che dipende dalla chiave. La chiave è casuale, non sarà possibile ottenere la stessa chiave su iOS e quindi si ottiene un risultato diverso.

    Se si desidera una funzione chiave di derivazione utilizzare una funzione come PBKDF2 è quasi completamente standardizzati per quanto riguarda la derivazione della chiave.

    • +1 – la chiave è nel nome, pseudo random number generator. Diverse implementazioni non danno lo stesso risultato, anche quando si utilizza lo stesso seme.
    • Prima di tutto voglio ringraziarvi per i vostri commenti, ma apprezzo il tuo sforzo se si può dare maggiori dettagli o per esempio dal momento che il suo po ‘ di confusione per me
    • Vedere il mio aggiornata la risposta getRawKey(..) l’attuazione.
    • Esattamente. Nessuna meraviglia! Cargo-cult di programmazione al suo peggio. Se si desidera che qualsiasi programma di lavoro, sarà utile sapere che cosa si sta facendo, invece di buttare insieme di bit di codice copiato da Internet.
  3. 3

    Su Android, si utilizza getBytes(). Questo è un errore in quanto significa che si utilizza il charset di default, piuttosto che un noto charset. Utilizzare getBytes("UTF-8") invece così si sa esattamente che cosa byte che si sta per ottenere.

    Non so l’equivalente per Objective-C, ma non si basano su predefinito. Specificare in modo esplicito UTF-8 quando la conversione di stringhe di byte. In questo modo si ottiene la stessa byte su entrambi i lati.

    Non posso non notare che si sta utilizzando MD5 in il codice Objective-C, ma non nel codice di Android. Questo è intenzionale?

  4. 2

    Vedere la mia risposta per basato su password, la crittografia AES, dal momento che, si sta effettivamente utilizzando il “seme” come password. (Basta cambiare la lunghezza della chiave di 256 a 128, se è questo che vuoi.)

    Cercando di generare la stessa chiave da semina un DRBG con lo stesso valore non è affidabile.

    Avanti, non si utilizza CBC o IV nel vostro Android di crittografia. Il mio esempio mostra come farlo correttamente troppo. A proposito, è necessario generare un nuovo IV per ogni messaggio di cifratura, come il mio ad esempio spettacoli, e inviarlo insieme con il testo cifrato. In caso contrario, non c’è nessun punto nel usando CBC.

  5. 0

    Se volete un esempio di codice compatibile per Android e iPhone, guarda la RNCryptor biblioteca per iOS e JNCryptor biblioteca per Java/Android.

    Entrambi i progetti sono open source e condividere un formato di dati comune. In queste librerie, AES a 256-bit, tuttavia sarebbe semplice per adattare il codice, se necessario, il supporto AES a 128-bit.

    Come per il accettato risposta, entrambe le librerie di utilizzare PBKDF2.

Lascia un commento