Would someone be kind enough to tell me what is wrong with the code
below? I've been wrestling with elliptic curve cryptography (ECC) all
day and can't seem to get it to work. I can encrypt data with either the
public or private keys, but decryption simple does not work. With a
private key I cannot manage to decrypt the ciphertext, and with a public
key I cannot instance an Encryptor. What am I missing?
Is it possible to encrypt data with an ECC private key and decrypt it
with an ECC public key?
Also, is it considered a bug that ECC doesn't check that the ciphertext
length it is decrypting is greater than or equal to some minimum before
trying to allocate a SecByteBlock? If so, line 1181 of pubkey.h needs to
be changed to bounds check ciphertextLength -= elementSize;
I'm using MS Visual C++ 2003 and Crypto++ 5.2.3, btw.
Any help would be greatly appreciated.
Thanks
- Jason
#include <conio.h>
#include <iostream>
#include <cryptopp.h>
#pragma warning(disable:4267)
#pragma warning(disable:4661)
#include <CryptoPP/oids.h>
#include <CryptoPP/osrng.h>
#include <CryptoPP/eccrypto.h>
#include <CryptoPP/asn.h>
#include <CryptoPP/ec2n.h>
#include <CryptoPP/ecp.h>
using namespace std;
using namespace CryptoPP;
#define __STRING(a) #a
#define __XSTRING(a) __STRING(a)
#define USE_TRY_CATCH 1
//#define USE_KEY_VALIDATION 1
#define USE_PUBLIC_TO_PRIVATE 1
//#define USE_PRIVATE_TO_PUBLIC 1
#define USE_ECP 1
//#define USE_EC2N 1
#if defined(USE_ECP)
# define USE_ALGORITHM ECP
#elif defined(USE_EC2N)
# define USE_ALGORITHM EC2N
#else
# error define either USE_ECP or USE_EC2N to 1
#endif
#define NAME_ALGORITHM __XSTRING(USE_ALGORITHM)
static ECIES<USE_ALGORITHM>::PrivateKey gPrivateKey;
static ECIES<USE_ALGORITHM>::PublicKey gPublicKey;
// BUGBUG ???
// Test data must be padded for a minimum length; otherwise, we will
// get an std::exception for bad allocation in DL_DecryptorBase::Decrypt
// when it tries to allocate a SecByteBlock but doesn't check that
// ciphertextLength < elementSize where ciphertextLength -= elementSize!
// Minimum size is 133 bytes for ECC.
static const char gTestData[133] =
"Test Data 1234567890 Test Data 1234567890 Test Data 1234567890";
static size_t gTestDataSize = sizeof(gTestData);
static byte gEncryptBuf[1 * 1024];
static byte gDecryptBuf[1 * 1024];
int
main(int argc, char **argv)
{
#if defined(USE_TRY_CATCH)
try {
#endif
AutoSeededRandomPool rng;
cout << "Testing Elliptic Curve " << NAME_ALGORITHM << endl;
cout << "Generating PrivateKey" << endl;
#if defined(USE_ECP)
// gPrivateKey.Initialize(rng, ASN1::secp112r1());
// gPrivateKey.Initialize(rng, ASN1::secp112r2());
// gPrivateKey.Initialize(rng, ASN1::secp160r1());
// gPrivateKey.Initialize(rng, ASN1::secp160k1());
// gPrivateKey.Initialize(rng, ASN1::secp256k1());
// gPrivateKey.Initialize(rng, ASN1::secp128r1());
// gPrivateKey.Initialize(rng, ASN1::secp128r2());
// gPrivateKey.Initialize(rng, ASN1::secp160r2());
// gPrivateKey.Initialize(rng, ASN1::secp192k1());
// gPrivateKey.Initialize(rng, ASN1::secp224k1());
// gPrivateKey.Initialize(rng, ASN1::secp224r1());
// gPrivateKey.Initialize(rng, ASN1::secp384r1());
gPrivateKey.Initialize(rng, ASN1::secp521r1());
#else // EC2N
// gPrivateKey.Initialize(rng, ASN1::sect163k1());
// gPrivateKey.Initialize(rng, ASN1::sect163r1());
// gPrivateKey.Initialize(rng, ASN1::sect239k1());
// gPrivateKey.Initialize(rng, ASN1::sect113r1());
// gPrivateKey.Initialize(rng, ASN1::sect113r2());
// gPrivateKey.Initialize(rng, ASN1::sect163r2());
// gPrivateKey.Initialize(rng, ASN1::sect283k1());
// gPrivateKey.Initialize(rng, ASN1::sect283r1());
// gPrivateKey.Initialize(rng, ASN1::sect131r1());
// gPrivateKey.Initialize(rng, ASN1::sect131r2());
// gPrivateKey.Initialize(rng, ASN1::sect193r1());
// gPrivateKey.Initialize(rng, ASN1::sect193r2());
// gPrivateKey.Initialize(rng, ASN1::sect233k1());
// gPrivateKey.Initialize(rng, ASN1::sect233r1());
// gPrivateKey.Initialize(rng, ASN1::sect409k1());
// gPrivateKey.Initialize(rng, ASN1::sect409r1());
// gPrivateKey.Initialize(rng, ASN1::sect571k1());
gPrivateKey.Initialize(rng, ASN1::sect571r1());
#endif
cout << "Generating PublicKey" << endl;
gPrivateKey.MakePublicKey(gPublicKey);
#if defined(USE_KEY_VALIDATION)
cout << "Validating PrivateKey" << endl;
if (gPrivateKey.Validate(rng, 3) == false)
cout << "PrivateKey invalid?!" << endl;
cout << "Validating PublicKey" << endl;
if (gPublicKey.Validate(rng, 3) == false)
cout << "PublicKey invalid?!" << endl;
#endif
#if defined(USE_PUBLIC_TO_PRIVATE)
cout << "Instancing PublicKey encryptor" << endl;
ECIES<USE_ALGORITHM>::Encryptor encryptor(gPublicKey);
cout << "Instancing PrivateKey decryptor" << endl;
ECIES<USE_ALGORITHM>::Decryptor decryptor(gPrivateKey);
#else
cout << "Instancing PrivateKey encryptor" << endl;
ECIES<USE_ALGORITHM>::Encryptor encryptor(gPrivateKey);
cout << "Instancing PublicKey decryptor" << endl;
ECIES<USE_ALGORITHM>::Decryptor decryptor(gPublicKey);
#endif
cout << "Using Test Data: " << gTestData << endl;
cout << "Encrypting test data: " << gTestDataSize << " bytes" << endl;
encryptor.Encrypt(rng, (const byte *)gTestData, gTestDataSize,
gEncryptBuf);
cout << "Decrypting test data" << endl;
// decryptor.Decrypt(rng, gEncryptBuf, gTestDataSize, gDecryptBuf);
DecodingResult result(decryptor.Decrypt(
rng, gEncryptBuf, gTestDataSize, gDecryptBuf));
cout << "DecodingResult.isValidCoding == " << result.isValidCoding
<< endl;
cout << "DecodingResult.messageLength == " << result.messageLength
<< endl;
cout << "Comparing test data to decrypted data" << endl;
// if (strcmp((char *)gTestData, (char *)gDecryptBuf) == 0)
if (memcmp(gTestData, gDecryptBuf, gTestDataSize) == 0)
cout << "Decrypt Success" << endl;
else
cout << "Decrypt Failed" << endl;
#if defined(USE_TRY_CATCH)
} catch (CryptoPP::Exception &e) {
cout << "CryptoPP::Exception " << e.what() << endl;
} catch (std::exception &e) {
cout << "std::exception " << e.what() << endl;
}
#endif
cout << "Press any key to exit ..." << endl;
getch();
return 0;
}