Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/97.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android上的AES解密速度太慢,无法使用。NDK会更快吗?其他想法?_Java_Android_Aes_Performance - Fatal编程技术网

Java Android上的AES解密速度太慢,无法使用。NDK会更快吗?其他想法?

Java Android上的AES解密速度太慢,无法使用。NDK会更快吗?其他想法?,java,android,aes,performance,Java,Android,Aes,Performance,我已经使用内置的密码类在Android上实现了AES/CTR。对于我来说,解密速度似乎太慢了,在模拟器上解密128KB的数据块大约需要6秒,在三星Galaxy硬件上解密大约需要2.6秒 我想知道使用NDK构建OpenSSL并调用其方法是否会更快。有没有人有这方面的经验?我的一部分人想相信,Cipher(“AES/CTR/NoPadding”)方法只是本地OpenSSL调用的包装器,因为支持Android的Linux操作系统应该安装libcrypto。如果是这样的话,那么尝试使用NDK只会是浪费时

我已经使用内置的密码类在Android上实现了AES/CTR。对于我来说,解密速度似乎太慢了,在模拟器上解密128KB的数据块大约需要6秒,在三星Galaxy硬件上解密大约需要2.6秒

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

我没有费心在iOS上计时,但即使是3Gs硬件解密速度也非常快,最终用户似乎可以立即进行10MB的解密。我发现很难相信安卓系统的实现真的比它差很多,但也许这就是现实

如果这真的是我面临的问题,有没有人对其他的实现策略有什么想法,可以为最终用户提供难以察觉的响应(在10Mb文件上)?我办公室的另一位开发人员开玩笑地建议我只使用XOR加密,这让我想自己使用facepalm,但我认为(撇开安全问题不谈),如果我这样做,它会起作用

谢谢

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

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 );
    }
}
公共类资源解密程序{
专用静态线程本地mCipher;
专用字节[]mIV=新字节[8];
私人保密密钥规范mKey;
私有字符串mResourcePath;
私有静态最终int kAESBlockSize=16;
public ResourceDecryptor(String resourcePath,String decryptionKey)抛出UnsupportedOperationException{
//mKey、mIV和mResourcePath的初始化,省略
//将mCipher存储为本地线程,因为Cipher.getInstance()非常慢,
//ResourceDecryptor是一个静态对象,在应用程序生命周期内持续存在
//所以这次泄漏是故意的,没有问题。
mCipher=new ThreadLocal(){
受保护的密码初始值(){
尝试{return Cipher.getInstance(“AES/CTR/NoPadding”);}catch(异常e){}
返回null;
}
};
}
public ByteBuffer read(长偏移量,整数长度)抛出GeneralSecurityException,IOException{
密码;
字节[]数据,iv;
文件输入流输入;
int前缀,readLength;
输入=空;
前缀=(int)(偏移量%kAESBlockSize);
readLength=(前缀+长度+kAESBlockSize-1)/kAESBlockSize*kAESBlockSize;
数据=新字节[readLength];
iv=新字节[16];
试一试{
输入=新文件输入流(mResourcePath);
输入.跳过(偏移量-=前缀);
如果(input.read(data)!=readLength)抛出新的IOException(“I/O错误:无法从偏移量+偏移量读取“+readLength+”字节);
系统阵列副本(mIV,0,iv,0,8);
偏移量/=kAESBlockSize;
iv[8]=(字节)(偏移量>>56&0xff);
iv[9]=(字节)(偏移量>>48&0xff);
iv[10]=(字节)(偏移量>>40&0xff);
iv[11]=(字节)(偏移量>>32&0xff);
iv[12]=(字节)(偏移量>>24和0xff);
iv[13]=(字节)(偏移量>>16和0xff);
iv[14]=(字节)(偏移量>>8和0xff);
iv[15]=(字节)(偏移量和0xff);
if((cipher=mCipher.get())==null)抛出新的GeneralSecurityException(“无法初始化密码(\“AES/CTR/NoPadding\”));
cipher.init(cipher.DECRYPT_模式,mKey,新的IvParameterSpec(iv));
long startTime=System.currentTimeMillis();
数据=cipher.doFinal(数据);
System.out.println(“解密“+data.length+”字节需要”+((System.currentTimeMillis()-startTime)/1000.0)+“s”);
//cipher.doFinal()在三星Galaxy emulator上的128kb数据块使用5.9秒
//cipher.doFinal()在三星Galaxy硬件上需要2.6秒才能获得128kb的数据块
}最后{
如果(输入!=null),请尝试{input.close();}捕获(异常e){}
}
//ByteBuffer的默认顺序是BIG_ENDIAN,因此无需显式设置顺序()
返回ByteBuffer.wrap(数据、前缀、长度);
}
}

是的,像在一个包含功能中那样的繁重工作正是NDK的亮点所在。请记住,Java是解释的,在2.2之前的Android上,没有JIT,所以每次都解释每条指令——这是一个巨大的开销

即使使用JIT,每个数组访问都会进行隐式边界检查,因此会有很多开销


如果你在C++中写这个函数,它会明显快。

玩得开心!使用NDK实际上是非常有趣的,尤其是您的问题对于它来说是绝对完美的。速度的提高应该是巨大的。关于这一点的快速更新:我们确实使用NDK进行本机AES解密,它工作得非常好。我们的应用程序现在速度非常快。@par您能告诉我您使用什么库进行本机AES解密吗?您能详细说明使用openssl的步骤吗。非常感谢你的邀请help@preetha我很抱歉,但我目前在保密协议与这一特定的代码位,不能张贴它。通常我不会发布我在问题中写的代码,但正如前面提到的,它速度很慢,因此无法使用,所以没有人对它有任何问题。我可以告诉你,我们的努力非常直接。如果你用NDK构建一个hello world应用程序,你将获得90%的w