【问题标题】:RSA::PublicKey Load function segfaults ART (Android Runtime)RSA::PublicKey 加载函数 segfaults ART(Android 运行时)
【发布时间】:2015-03-06 13:49:24
【问题描述】:

我们为 Cryptopp 实现了一个小型包装器,用于在 iOS 和 Android (JNI) 之间交换密钥。共享代码适用于 iOS 和 pre-ART android 设备。据说 ART 和它的垃圾收集器现在更严格了。

指出设置私钥功能在 Dalvik 和 ART 运行时都成功可能很重要。

代码: --> 设置公钥:

jboolean *isCopy;
//get bytes from jbytearray
jbyte* ba = (jbyte *)env->GetByteArrayElements( byteArray, isCopy);

//load bytearray to crypto bytequeue
ByteQueue queue2;

queue2.Put2((byte*)ba, 1000, 0, true);

//build public key
AutoSeededRandomPool rnd;
RSA::PublicKey publicKey;
publicKey.Load(*queue2);  //<-------- CRASH

--> 设置私钥

jboolean *isCopy;
jbyte* ba = (jbyte *)env->GetByteArrayElements( byteArray, isCopy);

//load bytearray to bytequeue
ByteQueue queue2;
queue2.Put2((byte*)ba, 3072, 0, true);

//fill up the key
RSA::PrivateKey privateKey;
privateKey.Load(queue2);

堆栈跟踪:

 backtrace:
     #00 pc 00027e6c  <project_name>/lib/arm/libstlport_shared.so
     #01 pc 00027e79  <project_name>/lib/arm/libstlport_shared.so
     #02 pc 00027efb  <project_name>/lib/arm/libstlport_shared.so (std::terminate()+6)
     #03 pc 000273d3  <project_name>/lib/arm/libstlport_shared.so
     #04 pc 000268c9  <project_name>/lib/arm/libstlport_shared.so
     #05 pc 0002698b  <project_name>/lib/arm/libstlport_shared.so (__cxa_throw+34)
     #06 pc 001b3ce4  <project_name>/lib/arm/libcryptopp.so (CryptoPP::BERDecodeError()+128)
     #07 pc 001b1598  <project_name>/lib/arm/libcryptopp.so (CryptoPP::BERGeneralDecoder::Init(unsigned char)+56)
     #08 pc 001b1638  <project_name>/lib/arm/libcryptopp.so (CryptoPP::BERGeneralDecoder::BERGeneralDecoder(CryptoPP::BufferedTransformation&, unsigned char)+104)
     #09 pc 0027697c  <project_name>/lib/arm/libcryptopp.so (CryptoPP::Integer::BERDecode(CryptoPP::BufferedTransformation&)+20)
     #10 pc 002aec7c  <project_name>/lib/arm/libcryptopp.so (CryptoPP::RSAFunction::BERDecodePublicKey(CryptoPP::BufferedTransformation&, bool, unsigned int)+64)
     #11 pc 001b20e0  <project_name>/lib/arm/libcryptopp.so (CryptoPP::X509PublicKey::BERDecode(CryptoPP::BufferedTransformation&)+264)
     #12 pc 00014a0b  <project_name>/lib/arm/libsecurity.so (CryptoPP::ASN1CryptoMaterial<CryptoPP::PublicKey>::Load(CryptoPP::BufferedTransformation&)+6)

值得一提的是,新的(大部分)Google 设备(Nexus 4、5、7)现在默认使用 ART。

请指教!

【问题讨论】:

  • 你是怎么看出来的?

标签: android android-ndk segmentation-fault android-5.0-lollipop crypto++


【解决方案1】:
jbyte* ba = (jbyte *)env->GetByteArrayElements( byteArray, isCopy);
ByteQueue queue; 
queue.Put((byte*)ba, 1000, 0, true);
...

还有:

ByteQueue queue;
queue.Put((byte*)ba, 3072, 0, true);
...

这是不正确的。当密钥通常是几百字节时,您无法对大小进行硬编码。

这是我用来处理jbyteArray 的代码:

if(env && ba)
{
    ReadByteBuffer buffer(env, ba);

    const byte* _arr = buffer.GetByteArray();
    size_t _len = buffer.GetArrayLen();

    ByteQueue queue;
    queue.Put(_arr, _len);
    ...
}

并且您应该将其包装在 try/catch 中,同时捕获 BERDecodeErr 以防其格式不正确。这似乎是您遇到的另一个问题。见BERDecodeErr Class Reference


这也不完全正确(请注意基于堆栈的ByteQueue 的指针取消引用):

ByteQueue queue2;
...
publicKey.Load(*queue2);

我将写出这种差异,但您应该确保您发布的代码能够代表您正在做的事情。


值得一提的是,新的(大部分)Google 设备(Nexus 4、5、7)现在默认使用 ART。

我有一个用于测试的 Nexus 5,Crypto++ 运行良好 :)


这是我用于ReadByteBuffer 的类。它在析构函数中处理释放。

class ReadByteBuffer
{
public:
    explicit ReadByteBuffer(JNIEnv*& env, jbyteArray& barr)
    : m_env(env), m_arr(barr), m_ptr(NULL), m_len(0)
    {
        if(m_env && m_arr)
        {
            m_ptr = m_env->GetByteArrayElements(m_arr, NULL);
            m_len = m_env->GetArrayLength(m_arr);
        }
    }

    ~ReadByteBuffer()
    {
        if(m_env && m_arr)
        {
            m_env->ReleaseByteArrayElements(m_arr, m_ptr, JNI_ABORT);
        }
    }

    const byte* GetByteArray() const {
        return (const byte*) m_ptr;
    }

    size_t GetArrayLen() const {
        if(m_len < 0)
            return 0;
        return (size_t) m_len;
    }

private:
    JNIEnv*& m_env;
    jbyteArray& m_arr;

    jbyte* m_ptr;
    jint m_len;
};

这是我用来写作的课程。和它的对应物一样,WriteByteBuffer 在析构函数中处理提交和释放。

class WriteByteBuffer
{
public:
    explicit WriteByteBuffer(JNIEnv*& env, jbyteArray& barr)
    : m_env(env), m_arr(barr), m_ptr(NULL), m_len(0)
    {
        if(m_env && m_arr)
        {
            m_ptr = m_env->GetByteArrayElements(m_arr, NULL);
            m_len = m_env->GetArrayLength(m_arr);
        }
    }

    ~WriteByteBuffer()
    {
        if(m_env && m_arr)
        {
            m_env->ReleaseByteArrayElements(m_arr, m_ptr, 0);
        }
    }

    byte* GetByteArray() const {
        return (byte*) m_ptr;
    }

    size_t GetArrayLen() const {
        if(m_len < 0)
            return 0;
        return (size_t) m_len;
    }

private:
    JNIEnv*& m_env;
    jbyteArray& m_arr;

    jbyte* m_ptr;
    jint m_len;
};

【讨论】:

    猜你喜欢
    • 2011-10-25
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 2014-04-29
    相关资源
    最近更新 更多