当前位置: 首页 > 面试题库 >

Android上的AES解密太慢而无法使用。NDK会更快吗?还有其他想法吗?

高溪叠
2023-03-14
问题内容

我已经使用内置的Cipher类在Android上实现了AES /
CTR。出于我的目的,解密似乎太慢了,一个128KB的块在模拟器上需要大约6秒钟来解密,而在Samsung Galaxy硬件上则需要2.6秒。

我想知道使用NDK构建OpenSSL并调用其方法是否会更快。有人对这个有经验么?我的一部分要相信Cipher(“ AES / CTR /
NoPadding”)方法仅仅是本地OpenSSL调用的包装,因为支持Android的Linux
OS应该安装libcrypto。如果真是这样,那么尝试使用NDK只是浪费时间,因为无法预期会有性能提升。

我没有在iOS上花时间,但即使3G硬件也是如此快速地解密,最终用户似乎可以立即进行10MB的解密。我发现很难相信Android的实现确实差了几个数量级,但这也许是事实。

如果这确实是我所面对的,是否有人对其他实施策略有任何想法,这些策略将为最终用户提供无法感知的响应(在10Mb文件上)?我办公室的另一位开发人员以嘲讽的方式建议我只使用XOR加密,这使我想面对自己,但我认为(除了安全方面的考虑),如果我这样做会起作用。

谢谢!

这是一些简化的代码供参考:

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

问题答案:

是的,像这样包含功能中的繁重工作正是NDK发挥作用的地方。请记住,Java是可解释的,而在2.2之前的Android上,没有JIT,因此每条指令每次都会被解释-
这是一个巨大的开销。

即使使用JIT,每个数组访问也会执行隐式边界检查,因此存在大量开销。

如果您使用C ++编写此函数,它将明显更快。



 类似资料:
  • 我需要解密用AES加密的传入请求,我尝试使用共享示例但无法找到正确的参数集 加密:AES/CBC/PKCS5添加AES/CBC/PKCS5 初始化向量:长度为16的空字节数组 测试密钥:1234567890123456 纯文本:abcdefghigklmnopqrstuvwxyz0123456789 加密:8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP

  • 问题内容: 我只是在测试JCIFS以访问Windows共享。完全无法使用的速度非常慢。 初始输出需要很长时间,后续读取也很慢。任何想法如何使用它?我也可以使用任何其他可替代的方式来编写Java代码来以可移植的方式访问Windows共享。 问题答案: 我在某处发现SmbFileInputStream不会自己进行缓冲,因此很慢。将SmbFileInputStream包裹在BufferedInputSt

  • 如果ArrayList中还没有,我希望将添加到ArrayList中,但由于某些原因,它无法工作。在本例中,arrlist是,arr是。此代码位于for循环中,其中arr在循环中定义,因此arr中的值会更改。即使我打印出arrlist并且它有arr,代码总是说arrlist不包含arr。是否有其他方法可以检查ArrayList是否包含?

  • 问题内容: 我对Java和Maven还是比较陌生的,但是我无法想象如果不使用Maven就开始一个新的Java项目。 我想提供一种人类可读的项目模型的想法在许多语言中都是普遍希望的。当您的应用程序依赖大量外部库时,尤其如此。 是否有其他任何项目管理或针对Java以外的语言的构建工具,这些语言本质上与Maven相似;也就是说,是否为项目维护者提供了一种机制来指定依赖关系和构建顺序? 问题答案: 这是我

  • 节点模块: Java类:主要方法现在只是用于测试,稍后将被删除。

  • 我正在为我的应用程序制作加密/解密模块。我按照这个教程 它没有给出任何错误,也没有显示输出。 日志文件 MainActivity.Java AESHelper.Java } AESHelper.java:52 还有AESHelper.java:25