AES obtiene resultados diferentes en iOS (Obj-C) y Android (Java)

Soy un novato completo a este tipo de cosas de cifrado, pero tengo una aplicación Java y un iOS, y quiero que ambos sean capaces de ecrypt un texto para un mismo resultado. Yo uso AES. Encontré estos códigos, con una pequeña modificación por supuesto, pero devuelven resultado diferente

Código iOS:

- (NSData *)AESEncryptionWithKey:(NSString *)key { unsigned char keyPtr[kCCKeySizeAES128] = { 'T', 'h', 'e', 'B', 'e', 's', 't', 'S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' }; size_t bufferSize = 16; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; const char iv2[16] = { 65, 1, 2, 23, 4, 5, 6, 7, 32, 21, 10, 11, 12, 13, 84, 45 }; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode | kCCOptionPKCS7Padding,, keyPtr, kCCKeySizeAES128, iv2, @"kayvan", 6, dataInLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } 

y el código Java es:

 public static void main(String[] args) throws Exception { String password = "kayvan"; String key = "TheBestSecretKey"; String newPasswordEnc = AESencrp.newEncrypt(password, key); System.out.println("Encrypted Text : " + newPasswordEnc); } 

y en otra clase java ( AESencrp.class ) tengo:

 public static final byte[] IV = { 65, 1, 2, 23, 4, 5, 6, 7, 32, 21, 10, 11, 12, 13, 84, 45 }; public static String newEncrypt(String text, String key) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] keyBytes= new byte[16]; byte[] b= key.getBytes("UTF-8"); int len = 16; System.arraycopy(b, 0, keyBytes, 0, len); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(IV); System.out.println(ivSpec); cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec); byte[] results = cipher.doFinal(text.getBytes("UTF-8")); String result = DatatypeConverter.printBase64Binary(results); return result; } 

La cadena que quería cifrar es kayvan con la clave TheBestSecretKey . y los resultados después de la codificación Base64 son:

para iOS: 9wXUiV+ChoLHmF6KraVtDQ==

para Java: /s5YyKb3tDlUXt7pqA5OFA==

¿Qué debería hacer ahora?

Y aquí está la Versión de Android que está generando la Cadena para descifrar / encriptar Mensajes, usa Cifrado y genera el vector correcto para hacer el mismo resultado que iOS. Esto corresponde a la versión iOS de @ 亚历山大 aquí en este hilo.

 public class MyCrypter { private static String TAG = "MyCrypter"; public MyCrypter() { } /** * Encodes a String in AES-128 with a given key * * @param context * @param password * @param text * @return String Base64 and AES encoded String * @throws NoPassGivenException * @throws NoTextGivenException */ public String encode(Context context, String password, String text) throws NoPassGivenException, NoTextGivenException { if (password.length() == 0 || password == null) { throw new NoPassGivenException("Please give Password"); } if (text.length() == 0 || text == null) { throw new NoTextGivenException("Please give text"); } try { SecretKeySpec skeySpec = getKey(password); byte[] clearText = text.getBytes("UTF8"); //IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID final byte[] iv = new byte[16]; Arrays.fill(iv, (byte) 0x00); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); // Cipher is not thread safe Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec); String encrypedValue = Base64.encodeToString( cipher.doFinal(clearText), Base64.DEFAULT); Log.d(TAG, "Encrypted: " + text + " -> " + encrypedValue); return encrypedValue; } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return ""; } /** * Decodes a String using AES-128 and Base64 * * @param context * @param password * @param text * @return desoded String * @throws NoPassGivenException * @throws NoTextGivenException */ public String decode(Context context, String password, String text) throws NoPassGivenException, NoTextGivenException { if (password.length() == 0 || password == null) { throw new NoPassGivenException("Please give Password"); } if (text.length() == 0 || text == null) { throw new NoTextGivenException("Please give text"); } try { SecretKey key = getKey(password); //IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID final byte[] iv = new byte[16]; Arrays.fill(iv, (byte) 0x00); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); byte[] encrypedPwdBytes = Base64.decode(text, Base64.DEFAULT); // cipher is not thread safe Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); byte[] decrypedValueBytes = (cipher.doFinal(encrypedPwdBytes)); String decrypedValue = new String(decrypedValueBytes); Log.d(TAG, "Decrypted: " + text + " -> " + decrypedValue); return decrypedValue; } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return ""; } /** * Generates a SecretKeySpec for given password * @param password * @return SecretKeySpec * @throws UnsupportedEncodingException */ public SecretKeySpec getKey(String password) throws UnsupportedEncodingException { int keyLength = 128; byte[] keyBytes = new byte[keyLength / 8]; // explicitly fill with zeros Arrays.fill(keyBytes, (byte) 0x0); // if password is shorter then key length, it will be zero-padded // to key length byte[] passwordBytes = password.getBytes("UTF-8"); int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length; System.arraycopy(passwordBytes, 0, keyBytes, 0, length); SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); return key; } public class NoTextGivenException extends Exception { public NoTextGivenException(String message) { super(message); } } public class NoPassGivenException extends Exception { public NoPassGivenException(String message) { super(message); } } } 

Hice una idea con iOS / Android / Node.js AES256 misma codificación de resultados, https://gist.github.com/m1entus/f70d4d1465b90d9ee024

Un amigo mío y yo creamos una aplicación de iOS y Android que puede cifrar mensajes. Para usarlo, debe crear una extensión de NSData con el siguiente fragmento de código de este sitio web :

 - (NSData *)AES128EncryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, // 16 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES128 + [key length]]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // insert key in char array [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; // the encryption method, use always same attributes in android and iPhone (fe PKCS7Padding) CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES128, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } - (NSData *)AES128DecryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES128 + [key length]]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // insert key in char array [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES128, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesDecrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); return nil; } + (NSData *)base64DataFromString: (NSString *)string { unsigned long ixtext, lentext; unsigned char ch, inbuf[4], outbuf[3]; short i, ixinbuf; Boolean flignore, flendtext = false; const unsigned char *tempcstring; NSMutableData *theData; if (string == nil){ return [NSData data]; } ixtext = 0; tempcstring = (const unsigned char *)[string UTF8String]; lentext = [string length]; theData = [NSMutableData dataWithCapacity: lentext]; ixinbuf = 0; while (true){ if (ixtext >= lentext){ break; } ch = tempcstring [ixtext++]; flignore = false; if ((ch >= 'A') && (ch <= 'Z')){ ch = ch - 'A'; } else if ((ch >= 'a') && (ch <= 'z')){ ch = ch - 'a' + 26; } else if ((ch >= '0') && (ch <= '9')){ ch = ch - '0' + 52; } else if (ch == '+'){ ch = 62; } else if (ch == '=') { flendtext = true; } else if (ch == '/') { ch = 63; } else { flignore = true; } if (!flignore){ short ctcharsinbuf = 3; Boolean flbreak = false; if (flendtext){ if (ixinbuf == 0){ break; } if ((ixinbuf == 1) || (ixinbuf == 2)) { ctcharsinbuf = 1; } else { ctcharsinbuf = 2; } ixinbuf = 3; flbreak = true; } inbuf [ixinbuf++] = ch; if (ixinbuf == 4){ ixinbuf = 0; outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4); outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2); outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F); for (i = 0; i < ctcharsinbuf; i++) { [theData appendBytes: &outbuf[i] length: 1]; } } if (flbreak) { break; } } } return theData; } 

A continuación, dentro de la clase que desea utilizar los métodos de cripta insertar en la parte superior:

 #import "NSData+Crypt.h" 

Y que encriptar tus cadenas así:

  NSData *value = [aString dataUsingEncoding:NSUTF8StringEncoding]; NSData *encryptedData = [value AES128EncryptWithKey:myKey]; NSString *myString = [encryptedData base64Encoding]; 

Y descifrar los datos como este:

 NSData *myData = [NSData base64DataFromString:_textView.text]; NSData *decryptedData = [myData AES128DecryptWithKey:_textField.text]; NSString *myString2 = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]; 

He utilizado el método base64DataFromString desde el sitio web de Matt Gallagher de lo contrario si usted utiliza

 [[NSData alloc] base64EncodedDataWithOptions:NSUTF8StringEncoding]; 

el método solo está disponible en> = iOS 7.0

Algunas cosas importantes a tener en cuenta al implementar el cifrado AES:
1. Nunca utilice texto sin formato como clave de cifrado. Siempre hash la llave de texto llano y luego utilizar para el cifrado.
2. Utilice siempre Random IV (vector de inicialización) para cifrar y descifrar. La aleatorización verdadera es importante. En los ejemplos anteriores, no se establece ningún vector de inicialización. Esta es una falla de seguridad.
Hace poco escribí la plataforma de cifrado AES y la biblioteca de descifrado para C #, iOS y Android que he publicado en Github. Puedes verlo aquí – https://github.com/Pakhee/Cross-platform-AES-encryption

  • Cómo amortiguar solamente la última emisión de rx.Observable durante contrapresión
  • Maven se niega a descargar una dependencia empacada desde un repositorio remoto
  • Android Múltiples secuencias de clics en textview
  • Principiante Desarrollador: Desconocido Error: java.lang.nullPointerException
  • Cómo convertir una hora de GMT a EST
  • Cómo comprobar si la configuración de la pantalla de giro automático está activada / desactivada en Android 4.0+
  • SLF4J varargs interpreta la primera cadena como marcador
  • Cómo consultar el SpeechRecognizer predeterminado
  • ¿Qué significa esta declaración de retorno de Java?
  • Enviar la imagen capturada al servidor web en android
  • Cómo obtener memcpy en Java?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.