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.
- Dispositivos Android que no tienen JIT
- Cómo dibujar una imagen de fondo grande con libgdx - las mejores prácticas?
- Rendimiento de Scala para Android
- Rendimiento de Android ContentProvider
- ArrayAdapter de Listview Arregla () redibujo muy lento de notificydatasetchanged
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 ); } }
- La mejor manera de obtener una SpannableString de un SpannableStringBuilder
- Android Studio es más rápido en una PC con Linux?
- Perfomance de red móvil: ¿Cuál sería el tipo de datos más eficiente para transferir datos de un servidor web a un teléfono móvil?
- ¿Cómo ahorrar una matriz larga como números hexadecimales inversos más rápido?
- Android: nesting FrameLayouts - ¿cuál es la sobrecarga de rendimiento exacto?
- Acceder directamente a los campos estáticos en lugar de llamar a un método getter estático, ¿es más rápido?
- ¿Debo reemplazar las actividades de Android por fragmentos?
- Float o doble?
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.
- ¿Cómo puedo mostrar el mapa de inclinación en Android?
- Cortar la pantalla del teléfono en dos partes que hacen simultáneamente dos cosas