Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Cifrado utilizando AES-128 en Android e IPhone (Resultado diferente)

Estoy tratando de cifrar un texto utilizando el algoritmo AES en las plataformas Android y IPhone. Mi problema es que, incluso usando el mismo algoritmo de cifrado / descifrado (AES-128) y las mismas variables fijas (clave, modo IV,) obtengo resultados diferentes en ambas plataformas. Estoy incluyendo muestras de código de ambas plataformas, que estoy usando para probar el cifrado / descifrado. Apreciaría una cierta ayuda en la determinación de lo que estoy haciendo mal.

  • Clave: "123456789abcdefg"
  • IV: "1111111111111111"
  • Texto sin formato: "HelloThere"
  • Modo: "AES / CBC / NoPadding"

Android Código:

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 (Objetivo-C) Código:

 - (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]; } 

Algunas de mis referencias:

  • Http://code.google.com/p/aes-encryption-samples/wiki/HowToEncryptWithJava
  • Http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iphone/
  • Interoperabilidad AES entre .Net y iPhone?

  • Android Vision Barcode API - leer código QR personalizado con datos binarios
  • SSL Broken Pipe
  • Java mmap falla en Android con "mmap failed: ENOMEM (Fuera de memoria)"
  • IOException durante la lectura de InputStream
  • Android: ¿Cómo crear un TextView circular?
  • ¿Qué es la imagen del sistema MIPS en el gestor de Android SDK?
  • ¿Cómo puedo hacer que una celda en un ListView en Android se expanda y contraiga verticalmente cuando se toca?
  • Cómo configurar la imagen de fondo del botón a través del código
  • 5 Solutions collect form web for “Cifrado utilizando AES-128 en Android e IPhone (Resultado diferente)”

    Para iPhone usé AESCrypt-ObjC , y para Android utilice este código:

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

    No me hace ninguna maravilla que usted consigue diversos resultados.

    Su problema es que utiliza un uso incorrecto de SHA1PRNG para la derivación clave. AFAIK no hay un estándar común como un SHA1PRNG trabaja internamente. AFAIR incluso la implementación de J2SE y Bouncycaste producen resultados diferentes usando la misma semilla.

    Por lo tanto su implementación de su getRawKey(byte[] seed) le generará una clave aleatoria. Si utiliza la clave para el cifrado, obtiene un resultado que depende de esa clave. Como la clave es aleatoria, no obtendrá la misma clave en iOS y, por lo tanto, obtendrá un resultado diferente.

    Si desea una función de derivación clave utilice una función como PBKDF2 con está casi totalmente estandarizada con respecto a la derivación clave.

    En Android, está utilizando getBytes() . Se trata de un error, ya que significa que está utilizando el conjunto de caracteres predeterminado en lugar de un conjunto de caracteres conocido. Use getBytes("UTF-8") lugar para que sepa exactamente qué bytes va a obtener.

    No conozco el equivalente de Objective-C, pero no confío en el valor predeterminado. Especificar explícitamente UTF-8 al convertir cadenas a bytes. De esta manera obtendrá los mismos bytes en ambos lados.

    También observo que está utilizando MD5 en el código Objective-C pero no en el código de Android. ¿Es esto deliberado?

    Vea mi respuesta para el cifrado AES basado en contraseña, ya que, efectivamente, está utilizando su "semilla" como contraseña. (Sólo cambia la longitud de la clave de 256 a 128, si eso es lo que quieres.)

    Tratar de generar la misma clave mediante la siembra de un DRBG con el mismo valor no es fiable.

    A continuación, no está utilizando CBC o la IV en su cifrado de Android. Mi ejemplo muestra cómo hacerlo correctamente también. Por cierto, necesitas generar una nueva IV para cada mensaje que cifras, como muestra mi ejemplo, y enviarlo junto con el texto cifrado. De lo contrario, no tiene sentido utilizar CBC.

    Si desea un ejemplo de código compatible para Android e iPhone, consulte la biblioteca RNCryptor para iOS y la biblioteca JNCryptor para Java / Android.

    Ambos proyectos son de código abierto y comparten un formato de datos común. En estas bibliotecas, AES de 256 bits se utiliza, sin embargo sería trivial para adaptar el código si es necesario para soportar 128-bit AES.

    Según la respuesta aceptada, ambas bibliotecas usan PBKDF2.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.