【发布时间】:2015-12-23 16:30:37
【问题描述】:
所以我正在使用 Java 和 Crypto++ 5.6.3 库在 Android 上编写 ECDH 实现。
我编写了一些 C++ JNI 代码来调用 Crypto++ 函数,我有一个函数来生成公钥/私钥对,以及另一个函数来提取共享密钥。然而,共享机密不匹配似乎存在问题。
情况如下。 Alice 和 Bob 都生成自己的公钥和私钥对。他们成功交换了公钥。
为了获得共享秘密,Alice 执行以下操作:
byte[] sharedSecret = getSharedSecret(bobPublicKey, alicePrivateKey);
Bob 做了类似的操作:
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 中包含一些关于如何启动和运行它的说明。
【问题讨论】:
-
这对我们来说有点快...我联系了 Bouncy Castle 的 David Hook,希望尽快为用户提供一些好的 Java/Crypto++ 互操作示例。
-
同时... "// TODO: 弄清楚公钥和私钥有多大..." - 看看Ephemeral Key as (x,y) Coordinate。用户交换的公钥/私钥和交换中使用的临时密钥相似,但格式不同。两者都是 ASN.1 编码的。前者(静态密钥)是具有 OID 的主题 {public|private} 密钥。后者(临时密钥)只是内部的 {public|private}。使用 ASN.1 转储程序(例如 Gutmann 的
dumpasn1)来查看它们。 -
抱歉,我花了这么长时间才回复。老实说,我对这一切都很陌生,我不知道如何使用那个 ASN.1 转储程序。根据我自己的 Java 代码,我现在可以判断的是,我的公钥是 33 个字节,而私钥是 32 个字节。这是一个十六进制示例: Alice 密钥对 公钥:03E81B8252352EBE8EF941A8D01260066D2351D90D32C2005C4DF7F1DDF7EC8C74 私钥:560ECB9D777359C5FF6B8E5FBA21D57AA01C9DD302FC898BFC8800000000000
标签: java android c++ java-native-interface crypto++