Crypto ++与Android

时间:2015-12-23 16:30:37

标签: java android c++ java-native-interface crypto++

所以我正在使用Java和Crypto ++ 5.6.3库在Android上编写ECDH实现。

我写了一些C ++ JNI代码来调用Crypto ++函数,我有一个函数来生成公钥/私钥对,另一个函数来提取共享密钥。然而,似乎存在一个问题,即共享机密不匹配。

情况如下。 Alice和Bob都生成了自己的公钥和私钥对。他们成功地交换了公钥。

为获取共享密钥,Alice执行以下操作:

byte[] sharedSecret = getSharedSecret(bobPublicKey, alicePrivateKey);
鲍勃做了类似的操作:

byte[] sharedSecret = getSharedSecret(alicePublicKey, bobPrivateKey);

我看到的问题是,两个共享的秘密彼此不匹配。对于我应该如何运作,我是否存在一些误解?

我假设我方面有一个与共享秘密有关的具体实施问题,但我不确定。 C ++ JNI实现如下。 retrieveSharedSecret函数总是输出" It Worked"。关于我在这里做错了什么想法?

JNIEXPORT jobject JNICALL Java_com_myproject_test_cryptopp_ECDHLibrary_generateKeyPair
        (JNIEnv *env, jclass)
{
    // Generate a public private key pair using ECDH (Elliptic Curve Diffie Hellman)
    OID CURVE = secp256r1(); // the key is 256 bits (32 bytes) long
    AutoSeededRandomPool rng;

    // Because we are using point compression
    // Private Key 32 bytes
    // Public Key 33 bytes
    // If compression was not used the public key would be 65 bytes long
    ECDH < ECP >::Domain dhA( CURVE );
    dhA.AccessGroupParameters().SetPointCompression(true);

    SecByteBlock privA(dhA.PrivateKeyLength()), pubA(dhA.PublicKeyLength());
    dhA.GenerateKeyPair(rng, privA, pubA);

    jobject publicKeyByteBuffer = (*env).NewDirectByteBuffer(pubA.BytePtr(), pubA.SizeInBytes());
    jobject privateKeyByteBuffer = (*env).NewDirectByteBuffer(privA.BytePtr(), privA.SizeInBytes());

    // Return the ECDH Key Pair back as our custom Java ECDHKeyPair class object
    jclass keyPairClass = (*env).FindClass("com/myproject/test/cryptopp/ECDHKeyPair");
    jmethodID midConstructor = (*env).GetMethodID(keyPairClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)V");
    jobject keyPairObject = (*env).NewObject(keyPairClass, midConstructor, publicKeyByteBuffer, privateKeyByteBuffer);

    return keyPairObject;
}

JNIEXPORT jobject JNICALL Java_com_myproject_test_cryptopp_ECDHLibrary_retrieveSharedSecret
        (JNIEnv *env, jclass, jbyteArray publicKeyArray, jbyteArray privateKeyArray)
{
    // Use the same ECDH Setup that is specified in the generateKeyPair method above
    OID CURVE = secp256r1();
    DL_GroupParameters_EC<ECP> params(CURVE);
    ECDH<ECP>::Domain dhAgreement(params);
    dhAgreement.AccessGroupParameters().SetPointCompression(true);

    // Figure out how big the public and private keys are
    // Public Key: This belongs to the other user
    // Private Key: This is out personal private key
    int pubLen = (int)(*env).GetArrayLength(publicKeyArray);
    int privLen = (int)(*env).GetArrayLength(privateKeyArray);

    // Convert the keys from a jbyteArray to a SecByteBlock so that they can be passed
    // into the CryptoPP Library functions.
    unsigned char* pubData = new unsigned char[pubLen];
    (*env).GetByteArrayRegion(publicKeyArray, 0, pubLen, reinterpret_cast<jbyte*>(pubData));

    unsigned char* privData = new unsigned char[privLen];
    (*env).GetByteArrayRegion(privateKeyArray, 0, privLen, reinterpret_cast<jbyte*>(privData));

    SecByteBlock pubB(pubData, pubLen) , privA(privData, privLen);

    // Now extract shared secret between the two keys
    SecByteBlock sharedSecretByteBlock(dhAgreement.AgreedValueLength());
    ALOG("Shared Agreed Value Length: %d", dhAgreement.AgreedValueLength());

    bool didWork = dhAgreement.Agree(sharedSecretByteBlock, privA, pubB);

    ALOG("Key Agreement: %s", didWork ? "It Worked" : "It Failed");
    ALOG("Shared Secret Byte Size: %d", sharedSecretByteBlock.SizeInBytes());

    // Return the shared secret as a Java ByteBuffer
    jobject publicKeyByteBuffer = (*env).NewDirectByteBuffer(sharedSecretByteBlock.BytePtr(), sharedSecretByteBlock.SizeInBytes());

    return publicKeyByteBuffer;
}

修改 我将我的测试项目放在Github上here,以便其他人可以看看并尝试自己的运气。包含README中有关如何启动和运行的一些说明。

1 个答案:

答案 0 :(得分:1)

我能够在朋友的帮助下解决这个问题。问题是retrieveSharedSecret方法以及它直接返回一个字节缓冲区的事实,该缓冲区指向C ++方法调用期间在范围内的内存地址,但是一旦它返回到Java代码中就会超出范围。所以我基本上把垃圾记忆作为我的共同秘密。

我调整了代码,以便该方法返回一个自定义的SharedSecret Java对象,就像keyGeneration方法一样。这样做可以正确地复制我需要的所有信息,而不必担心这个范围问题。

修改后的方法代码如下。我还将更新Github项目,以便它可以作为如何将Android Studio与NDK(非实验性)和CryptoPP一起使用的工作示例。

// Use the same ECDH Setup that is specified in the generateKeyPair method above
OID CURVE = secp256r1();
DL_GroupParameters_EC<ECP> params(CURVE);
ECDH<ECP>::Domain dhAgreement(params);
dhAgreement.AccessGroupParameters().SetPointCompression(true);

// Figure out how big the public and private keys are
// Public Key: This belongs to the other user
// Private Key: This is out personal private key
int pubLen = (int)(*env).GetArrayLength(publicKeyArray);
int privLen = (int)(*env).GetArrayLength(privateKeyArray);

// Convert the keys from a jbyteArray to a SecByteBlock so that they can be passed
// into the CryptoPP Library functions.
unsigned char* pubData = new unsigned char[pubLen];
(*env).GetByteArrayRegion(publicKeyArray, 0, pubLen, reinterpret_cast<jbyte*>(pubData));

unsigned char* privData = new unsigned char[privLen];
(*env).GetByteArrayRegion(privateKeyArray, 0, privLen, reinterpret_cast<jbyte*>(privData));

SecByteBlock pubB(pubData, pubLen) , privA(privData, privLen);

// Now extract shared secret between the two keys
SecByteBlock sharedSecretByteBlock(dhAgreement.AgreedValueLength());
ALOG("Shared Agreed Value Length: %d", dhAgreement.AgreedValueLength());

bool didWork = dhAgreement.Agree(sharedSecretByteBlock, privA, pubB);

ALOG("Key Agreement: %s", didWork ? "It Worked" : "It Failed");
ALOG("Shared Secret Byte Size: %d", sharedSecretByteBlock.SizeInBytes());

// Return the shared secret as a Java ByteBuffer
jobject sharedSecretByteBuffer = (*env).NewDirectByteBuffer(sharedSecretByteBlock.BytePtr(), sharedSecretByteBlock.SizeInBytes());

// Return the ECDH Key Pair back as a Java ECDHKeyPair object
jclass keyPairClass = (*env).FindClass("com/tcolligan/ecdhtest/SharedSecret");
jmethodID midConstructor = (*env).GetMethodID(keyPairClass, "<init>", "(Ljava/nio/ByteBuffer;)V");
jobject sharedSecretObject = (*env).NewObject(keyPairClass, midConstructor, sharedSecretByteBuffer);

return sharedSecretObject;