Итак, я пишу реализацию ECDH на Android, используя Java и библиотеку Crypto++ 5.6.3.
Я написал некоторый код C++ JNI для вызова функций Crypto++, у меня есть одна функция для создания пары открытого/закрытого ключа и другая функция для извлечения общего секрета. Однако существует проблема с несовпадением общих секретов.
Ситуация следующая. Алиса и Боб генерируют свои собственные пары открытых и закрытых ключей. Они успешно обмениваются открытыми ключами.
Чтобы получить общий секрет, Алиса делает следующее:
byte[] sharedSecret = getSharedSecret(bobPublicKey, alicePrivateKey);
Боб делает аналогичную операцию:
byte[] sharedSecret = getSharedSecret(alicePublicKey, bobPrivateKey);
Проблема, которую я вижу, заключается в том, что два общих секрета не соответствуют друг другу. Есть ли какое-то непонимание с моей стороны о том, как это должно работать?
Я предполагаю, что на моей стороне есть только конкретная проблема реализации, связанная с общим секретом, но я не уверен. Реализация C++ JNI приведена ниже. Функция retrieveSharedSecret всегда выводит «Это сработало». Любые идеи о том, что я делаю неправильно здесь?
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;
}
EDIT: я разместил свой тестовый проект на Github здесь, чтобы другие можно посмотреть и попытать счастья. Содержит некоторые инструкции в README о том, как его настроить и запустить.
dumpasn1
Гутмана, для их просмотра. - person jww   schedule 24.12.2015