在Android上速度太慢AES加密技术是可用的。将NDK更快?其他的想法? [英] AES decryption on Android too slow to be usable. Will NDK be faster? Other ideas?

查看:811
本文介绍了在Android上速度太慢AES加密技术是可用的。将NDK更快?其他的想法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用实现AES / CTR在Android上内置的加密类。解密似乎是对于我而言过于缓慢,具有128KB块,大约需要6秒钟解密在模拟器和2.6秒的三星Galaxy硬件。

我想知道如果构建OpenSSL的使用NDK并调用它的方法将是任何更快。有没有人有这样的经验吗?我的一部分要相信密码(AES / CTR / NoPadding)的方法仅仅是围绕本地的OpenSSL调用封装反正自从Linux操作系统支持的Andr​​oid应该有libcrypto安装。如果是这样的话,那么尝试使用NDK的也只是浪费时间,因为没有性能提升可以预期。

我没有打扰到这个时候在iOS上,但一个10MB的解密似乎是瞬间给最终用户甚至3Gs的硬件解密这么快。我发现它很难相信Android的实施更糟糕的是顺序的,幅度很清楚,但是这就是现实。

如果这真的是我面对任何人都不会对其他执行战略,将为最终用户(在10Mb的文件)不易察觉的回应任何想法?在我的办公室另一位开发者在舌头在脸颊的方式,我只是使用XOR加密这让我想facepalm自己,但我认为(安全问题除外),如果我这样做,这是可行的建议。

谢谢!

下面是一些简单的code,以供参考:

 公共类ResourceDecryptor {
    私有静态ThreadLocal的<密码> mCipher;
    私人byte []的MIV =新的字节[8]。
    私人SecretKeySpec MKEY;
    私人字符串mResourcePath;

    私有静态最终诠释kAESBlockSize = 16;

    公共ResourceDecryptor(字符串resourcePath,字符串decryptionKey)抛出UnsupportedOperationException {
        // MKEY,MIV,与放大器的初始化; mResourcePath,省略

        //商店mCipher作为一个线程局部的,因为Cipher.getInstance()是如此之慢,
        // ResourceDecryptor是持续的应用程序生命周期静态对象
        //所以这次泄漏是故意和确定。
        mCipher =新的ThreadLocal<密码>(){
            保护的密码初值(){
                尝试{返回Cipher.getInstance(AES / CTR / NoPadding); }赶上(例外五){}

                返回null;
            }
        };
    }

    公共ByteBuffer的读取(长抵消,诠释长度)抛出GeneralSecurityException,IOException异常{
        加密密码;
        byte []的数据,四;
        的FileInputStream输入;
        INT preFIX,读数长度;

        输入= NULL;
        preFIX =(INT)(偏移%kAESBlockSize);
        读数长度=(preFIX +长度+ kAESBlockSize  -  1)/ kAESBlockSize * kAESBlockSize;
        数据=新的字节[读数长度]
        IV =新的字节[16];

        尝试 {
            输入=新的FileInputStream(mResourcePath);
            input.skip(偏移 -  = preFIX);

            如果(!input.read(数据)=读数长度)抛出新IOException异常(I / O错误:无法读取+读数长度+从offset字节+偏移量);

            System.arraycopy(MIV,0,四,0,8);

            偏移/ = kAESBlockSize;

            四[8] =(字节)(偏移>> 56&安培; 0xff的);
            四[9] =(字节)(偏移>> 48&安培; 0xff的);
            四[10] =(字节)(偏移>→40&安培; 0xff的);
            四[11] =(字节)(偏移>> 32&安培; 0xff的);
            四[12] =(字节)(偏移>> 24&安培; 0xff的);
            四[13] =(字节)(偏移>> 16&安培; 0xff的);
            四[14] =(字节)(偏移>→8&安培; 0xff的);
            四[15] =(字节)(偏移&安培; 0xff的);

            如果((密码= mCipher.get())== NULL)抛出新GeneralSecurityException(无法初始化密码(\AES / CTR / NoPadding \));
            cipher.init(Cipher.DECRYPT_MODE,MKEY,新IvParameterSpec(四));

            长的startTime = System.currentTimeMillis的();
            数据= cipher.doFinal(数据);
            的System.out.println(+ data.length +解密,字节以+((System.currentTimeMillis的() - 的startTime)/ 1000.0)+的);

            // cipher.doFinal()需要5.9s的三星Galaxy模拟器128KB块
            // cipher.doFinal()采用2.6S的三星Galaxy硬件128KB块
        } 最后 {
            如果(!输入= NULL){尝试input.close(); }赶上(例外五){}
        }

        // ByteBuffer的默认顺序是BIG_ENDIAN所以它是没有必要明确设置顺序()

        返回ByteBuffer.wrap(数据,preFIX,长度);
    }
}
 

解决方案

是的,举重一样,在一个包含的功能也正是在NDK将大放异彩。请记住,Java是跨preTED,并在pre-2.2的Andr​​oid,没有JIT,所以每一个指令除$ P $每次PTED - 这是一个巨大的开销

即使使用JIT,每个数组访问,那么隐含的边界检查,所以有很多很多的开销。

如果你写在C ++中这个功能,这将是显著更快。

I've implemented AES/CTR on Android using the built-in Cipher class. Decryption appears to be far too slow for my purposes, with a 128KB block taking approximately 6 seconds to decrypt on the emulator and 2.6 seconds on the Samsung Galaxy hardware.

I'm wondering if building OpenSSL using the NDK and calling its methods would be any faster. Does anyone have any experience with this? Part of me wants to believe that the Cipher( "AES/CTR/NoPadding" ) methods are just a wrapper around native OpenSSL calls anyway since the Linux OS backing Android should have libcrypto installed. If that were the case then trying to use the NDK would just be a waste of time as no performance gain could be expected.

I haven't bothered to time this on iOS but even 3Gs hardware decrypts so fast that a 10MB decryption appears to be instantaneous to the end user. I'm finding it difficult to believe that the Android implementation is really order-of-magnitudes worse but maybe that's the reality.

If this is really what I'm faced with does anyone have any ideas on other implementation strategies that would provide imperceptible response (on 10Mb files) for end users? Another developer in my office suggested in a tongue-in-cheek way that I just use XOR encryption which makes me want to facepalm myself but I think (security concerns aside) that if I did that it would work.

Thanks!

Here's some simplified code for reference:

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

解决方案

Yes, heavy lifting like that in a contained function is exactly where the NDK would shine. Keep in mind that Java is interpreted, and on pre-2.2 Android, there is no JIT, so every instruction is interpreted each time - that is a huge overhead.

Even with JIT, every array access does implicit bounds checking, so there is lots and lots of overhead.

If you write this function in C++, it will be significantly faster.

这篇关于在Android上速度太慢AES加密技术是可用的。将NDK更快?其他的想法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆