gpt4 book ai didi

java - ECDH 共享 key 在 Crypto++ 和 Android 之间不匹配

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:15:16 26 4
gpt4 key购买 nike

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

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

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

为了获得共享 secret ,Alice 执行以下操作:

byte[] sharedSecret = getSharedSecret(bobPublicKey, alicePrivateKey);

Bob 做了一个类似的操作:

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

我看到的问题是,这两个共享 secret 彼此不匹配。我对这应该如何工作有什么误解吗?

我假设我这边只有一个与共享 secret 相关的具体实现问题,但我不确定。 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 中包含一些关于如何启动和运行它的说明。

最佳答案

我是在 friend 的帮助下弄明白的。问题在于 retrieveSharedSecret 方法以及它直接返回一个字节缓冲区的事实,该缓冲区指向一个内存地址,该内存地址在 C++ 方法调用期间处于范围内,但一旦返回到 Java 代码中就超出了范围.所以我实际上是在获取垃圾内存作为我的共享 secret 。

我调整了代码,使该方法返回自定义 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;

关于java - ECDH 共享 key 在 Crypto++ 和 Android 之间不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34439990/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com