Descifrado AES en Android demasiado lento para ser utilizable. ¿NDK será más rápido? ¿Otras ideas?

He implementado AES / CTR en Android usando la clase de cifrado incorporada. El descifrado parece ser demasiado lento para mis propósitos, con un bloque de 128KB que tarda aproximadamente 6 segundos en descifrarse en el emulador y 2,6 segundos en el hardware de Samsung Galaxy.

Me pregunto si construir OpenSSL usando el NDK y llamar a sus métodos sería más rápido. ¿Alguien tiene alguna experiencia con esto? Una parte de mí quiere creer que los métodos Cipher ("AES / CTR / NoPadding") son sólo un envoltorio alrededor de las llamadas OpenSSL nativas, ya que el sistema operativo Linux que respalda Android debería tener instalado libcrypto. Si ese fuera el caso, entonces tratar de usar el NDK sería sólo una pérdida de tiempo ya que no se podía esperar ganancia de rendimiento.

No me he molestado en tiempo esto en iOS, pero incluso el hardware de 3G descifra tan rápido que un descifrado de 10MB parece ser instantáneo para el usuario final. Me resulta difícil creer que la implementación de Android es realmente orden de magnitudes peor, pero tal vez esa es la realidad.

Si esto es realmente lo que me enfrento, ¿alguien tiene alguna idea sobre otras estrategias de implementación que proporcionen una respuesta imperceptible (en los archivos de 10Mb) para los usuarios finales? Otro desarrollador en mi oficina sugirió de una manera irónica que sólo uso el cifrado XOR que me hace querer enfrentarme a mí mismo, pero creo que (preocupaciones de seguridad a un lado) que si lo hiciera funcionaría.

¡Gracias!

He aquí un código simplificado de referencia:

public class ResourceDecryptor { private static ThreadLocal<Cipher> mCipher; private byte[] mIV = new byte[ 8 ]; private SecretKeySpec mKey; private String mResourcePath; private static final int kAESBlockSize = 16; public ResourceDecryptor( String resourcePath, String decryptionKey ) throws UnsupportedOperationException { // initialization of mKey, mIV, & mResourcePath, elided // store mCipher as a thread local because Cipher.getInstance() is so slow, // ResourceDecryptor is a static object that persists for the app lifetime // so this leak is intentional and ok. mCipher = new ThreadLocal<Cipher>() { protected Cipher initialValue() { try { return Cipher.getInstance( "AES/CTR/NoPadding" ); } catch ( Exception e ) { } return null; } }; } public ByteBuffer read( long offset, int length ) throws GeneralSecurityException, IOException { Cipher cipher; byte[] data, iv; FileInputStream input; int prefix, readLength; input = null; prefix = (int)( offset % kAESBlockSize ); readLength = ( prefix + length + kAESBlockSize - 1 ) / kAESBlockSize * kAESBlockSize; data = new byte[ readLength ]; iv = new byte[ 16 ]; try { input = new FileInputStream( mResourcePath ); input.skip( offset -= prefix ); if ( input.read( data ) != readLength ) throw new IOException( "I/O error: unable to read " + readLength + " bytes from offset " + offset ); System.arraycopy( mIV, 0, iv, 0, 8 ); offset /= kAESBlockSize; iv[ 8 ] = (byte)( offset >> 56 & 0xff ); iv[ 9 ] = (byte)( offset >> 48 & 0xff ); iv[ 10 ] = (byte)( offset >> 40 & 0xff ); iv[ 11 ] = (byte)( offset >> 32 & 0xff ); iv[ 12 ] = (byte)( offset >> 24 & 0xff ); iv[ 13 ] = (byte)( offset >> 16 & 0xff ); iv[ 14 ] = (byte)( offset >> 8 & 0xff ); iv[ 15 ] = (byte)( offset & 0xff ); if ( ( cipher = mCipher.get() ) == null ) throw new GeneralSecurityException( "Unable to initialize Cipher( \"AES/CTR/NoPadding\" )" ); cipher.init( Cipher.DECRYPT_MODE, mKey, new IvParameterSpec( iv ) ); long startTime = System.currentTimeMillis(); data = cipher.doFinal( data ); System.out.println( "decryption of " + data.length + " bytes took " + ( ( System.currentTimeMillis() - startTime ) / 1000.0 ) + "s" ); // cipher.doFinal() takes 5.9s on Samsung Galaxy emulator for 128kb block // cipher.doFinal() takes 2.6s on Samsung Galaxy hardware for 128kb block } finally { if ( input != null ) try { input.close(); } catch ( Exception e ) { } } // the default order of ByteBuffer is BIG_ENDIAN so it is unnecessary to explicitly set the order() return ByteBuffer.wrap( data, prefix, length ); } } 

Sí, el levantamiento pesado como que en una función contenida es exactamente donde el NDK brillaría. Tenga en cuenta que Java se interpreta, y en pre-2.2 Android, no hay JIT, por lo que cada instrucción se interpreta cada vez – que es una enorme sobrecarga.

Incluso con JIT, cada acceso a la matriz implica la comprobación de los límites implícitos, por lo que hay un montón de gastos generales.

Si escribe esta función en C ++, será significativamente más rápido.

  • Ionic: transiciones lentas en la aplicación android instalada
  • Cómo compartir datos con Android Volley
  • ¿Cómo detener Handler Runnable?
  • ¿Qué es más rápido? Una intent.putExtras (Bundle con cadenas) o muchos intent.putExtra (String)?
  • Android error Dx problema de escritura salida: ya preparado
  • Android ViewPager y TabLayout no funcionan rápido
  • El uso de un HashMap para almacenar grandes cantidades de datos está ralentizando mi aplicación de Android, ¿hay otras opciones?
  • Rendimiento ORM: ¿es greenDAO más rápido que ORMLite?
  • Responde al teclado mientras se actualiza la interfaz de usuario
  • Descomprimir archivos de una manera más rápida que usar java.util.zip en Android
  • Servicios WebSocket de Android que realizan varias conexiones
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.