blob: 3c29d0613e8ebe6253add45b5d31abbb89acf4b8 [file] [log] [blame]
/*
* Copyright (c) 2010 SURFnet bv
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*****************************************************************************
ECDSATests.cpp
Contains test cases to test the ECDSA class
*****************************************************************************/
#include <stdlib.h>
#include <utility>
#include <vector>
#include <cppunit/extensions/HelperMacros.h>
#include "ECDSATests.h"
#include "CryptoFactory.h"
#include "RNG.h"
#include "AsymmetricKeyPair.h"
#include "AsymmetricAlgorithm.h"
#ifdef WITH_ECC
#include "ECParameters.h"
#include "ECPublicKey.h"
#include "ECPrivateKey.h"
CPPUNIT_TEST_SUITE_REGISTRATION(ECDSATests);
void ECDSATests::setUp()
{
ecdsa = NULL;
ecdsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA);
// Check the ECDSA object
CPPUNIT_ASSERT(ecdsa != NULL);
}
void ECDSATests::tearDown()
{
if (ecdsa != NULL)
{
CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdsa);
}
fflush(stdout);
}
void ECDSATests::testKeyGeneration()
{
AsymmetricKeyPair* kp;
// Curves to test
std::vector<ByteString> curves;
// Add X9.62 prime256v1
curves.push_back(ByteString("06082a8648ce3d030107"));
// Add secp384r1
curves.push_back(ByteString("06052b81040022"));
// Add secp521r1
curves.push_back(ByteString("06052b81040023"));
for (std::vector<ByteString>::iterator c = curves.begin(); c != curves.end(); c++)
{
// Set domain parameters
ECParameters* p = new ECParameters;
p->setEC(*c);
// Generate key-pair
CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
ECPublicKey* pub = (ECPublicKey*) kp->getPublicKey();
ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
CPPUNIT_ASSERT(pub->getEC() == *c);
CPPUNIT_ASSERT(priv->getEC() == *c);
ecdsa->recycleParameters(p);
ecdsa->recycleKeyPair(kp);
}
}
void ECDSATests::testSerialisation()
{
// Get prime256v1 domain parameters
ECParameters* p = new ECParameters;
p->setEC(ByteString("06082a8648ce3d030107"));
// Serialise the parameters
ByteString serialisedParams = p->serialise();
// Deserialise the parameters
AsymmetricParameters* dEC;
CPPUNIT_ASSERT(ecdsa->reconstructParameters(&dEC, serialisedParams));
CPPUNIT_ASSERT(dEC->areOfType(ECParameters::type));
ECParameters* ddEC = (ECParameters*) dEC;
CPPUNIT_ASSERT(p->getEC() == ddEC->getEC());
// Generate a key-pair
AsymmetricKeyPair* kp;
CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, dEC));
// Serialise the key-pair
ByteString serialisedKP = kp->serialise();
// Deserialise the key-pair
AsymmetricKeyPair* dKP;
CPPUNIT_ASSERT(ecdsa->reconstructKeyPair(&dKP, serialisedKP));
// Check the deserialised key-pair
ECPrivateKey* privKey = (ECPrivateKey*) kp->getPrivateKey();
ECPublicKey* pubKey = (ECPublicKey*) kp->getPublicKey();
ECPrivateKey* dPrivKey = (ECPrivateKey*) dKP->getPrivateKey();
ECPublicKey* dPubKey = (ECPublicKey*) dKP->getPublicKey();
CPPUNIT_ASSERT(privKey->getEC() == dPrivKey->getEC());
CPPUNIT_ASSERT(privKey->getD() == dPrivKey->getD());
CPPUNIT_ASSERT(pubKey->getEC() == dPubKey->getEC());
CPPUNIT_ASSERT(pubKey->getQ() == dPubKey->getQ());
ecdsa->recycleParameters(p);
ecdsa->recycleParameters(dEC);
ecdsa->recycleKeyPair(kp);
ecdsa->recycleKeyPair(dKP);
}
void ECDSATests::testPKCS8()
{
// Get prime256v1 domain parameters
ECParameters* p = new ECParameters;
p->setEC(ByteString("06082a8648ce3d030107"));
// Generate a key-pair
AsymmetricKeyPair* kp;
CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
CPPUNIT_ASSERT(kp != NULL);
ECPrivateKey* priv = (ECPrivateKey*) kp->getPrivateKey();
CPPUNIT_ASSERT(priv != NULL);
// Encode and decode the private key
ByteString pkcs8 = priv->PKCS8Encode();
CPPUNIT_ASSERT(pkcs8.size() != 0);
ECPrivateKey* dPriv = (ECPrivateKey*) ecdsa->newPrivateKey();
CPPUNIT_ASSERT(dPriv != NULL);
CPPUNIT_ASSERT(dPriv->PKCS8Decode(pkcs8));
CPPUNIT_ASSERT(priv->getEC() == dPriv->getEC());
CPPUNIT_ASSERT(priv->getD() == dPriv->getD());
ecdsa->recycleParameters(p);
ecdsa->recycleKeyPair(kp);
ecdsa->recyclePrivateKey(dPriv);
}
void ECDSATests::testSigningVerifying()
{
AsymmetricKeyPair* kp;
ECParameters *p;
// Curves/Hashes to test
std::vector<std::pair<ByteString, HashAlgo::Type> > totest;
// Add X9.62 prime256v1
totest.push_back(std::make_pair(ByteString("06082a8648ce3d030107"), HashAlgo::SHA256));
// Add secp384r1
totest.push_back(std::make_pair(ByteString("06052b81040022"), HashAlgo::SHA384));
// Add secp521r1
totest.push_back(std::make_pair(ByteString("06052b81040023"), HashAlgo::SHA384));
for (std::vector<std::pair<ByteString, HashAlgo::Type> >::iterator k = totest.begin(); k != totest.end(); k++)
{
// Get parameters
p = new ECParameters;
CPPUNIT_ASSERT(p != NULL);
p->setEC(k->first);
HashAlgorithm *hash;
hash = CryptoFactory::i()->getHashAlgorithm(k->second);
CPPUNIT_ASSERT(hash != NULL);
// Generate key-pair
CPPUNIT_ASSERT(ecdsa->generateKeyPair(&kp, p));
// Generate some data to sign
ByteString dataToSign;
RNG* rng = CryptoFactory::i()->getRNG();
CPPUNIT_ASSERT(rng != NULL);
CPPUNIT_ASSERT(rng->generateRandom(dataToSign, 567));
// Sign the data
CPPUNIT_ASSERT(hash->hashInit());
CPPUNIT_ASSERT(hash->hashUpdate(dataToSign));
ByteString hResult;
CPPUNIT_ASSERT(hash->hashFinal(hResult));
ByteString sig;
CPPUNIT_ASSERT(ecdsa->sign(kp->getPrivateKey(), hResult, sig, AsymMech::ECDSA));
// And verify it
CPPUNIT_ASSERT(ecdsa->verify(kp->getPublicKey(), hResult, sig, AsymMech::ECDSA));
ecdsa->recycleKeyPair(kp);
ecdsa->recycleParameters(p);
CryptoFactory::i()->recycleHashAlgorithm(hash);
}
}
void ECDSATests::testSignVerifyKnownVector()
{
ECPublicKey* pubKey1 = (ECPublicKey*) ecdsa->newPublicKey();
ECPublicKey* pubKey2 = (ECPublicKey*) ecdsa->newPublicKey();
ECPrivateKey* privKey1 = (ECPrivateKey*) ecdsa->newPrivateKey();
ECPrivateKey* privKey2 = (ECPrivateKey*) ecdsa->newPrivateKey();
HashAlgorithm* hash1 = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
HashAlgorithm* hash2 = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
// Reconstruct public and private key #1
ByteString ec1 = "06082a8648ce3d030107"; // X9.62 prime256v1
ByteString d1 = "dc51d3866a15bacde33d96f992fca99da7e6ef0934e7097559c27f1614c88a7f";
// add 04 (ASN_String) <len+1> 04 (UNCOMPRESSED) in front!
ByteString q1 = "0441042442a5cc0ecd015fa3ca31dc8e2bbc70bf42d60cbca20085e0822cb04235e9706fc98bd7e50211a4a27102fa3549df79ebcb4bf246b80945cddfe7d509bbfd7d";
pubKey1->setEC(ec1);
pubKey1->setQ(q1);
privKey1->setEC(ec1);
privKey1->setD(d1);
CPPUNIT_ASSERT(hash1 != NULL);
// Test with key #1
ByteString data1 = "616263"; // "abc"
ByteString goodSignature1 = "cb28e0999b9c7715fd0a80d8e47a77079716cbbf917dd72e97566ea1c066957c86fa3bb4e26cad5bf90b7f81899256ce7594bb1ea0c89212748bff3b3d5b0315";
ByteString badSignature1 = "cb28e0999b9c7715fd0a80d8e47a77079716cbbf917dd72e97566ea1c066957c86fa3bb4e26cad5bf90b7f81899256ce7594bb1ea0c89212748bff3b3d5b0316";
// Reconstruct public and private key #2
ByteString ec2 = "06052b81040022"; // secp384r1
ByteString d2 = "0beb646634ba87735d77ae4809a0ebea865535de4c1e1dcb692e84708e81a5af62e528c38b2a81b35309668d73524d9f";
// add 04 (ASN_String) <len+1> 04 (UNCOMPRESSED) in front!
ByteString q2 = "04610496281bf8dd5e0525ca049c048d345d3082968d10fedf5c5aca0c64e6465a97ea5ce10c9dfec21797415710721f437922447688ba94708eb6e2e4d59f6ab6d7edff9301d249fe49c33096655f5d502fad3d383b91c5e7edaa2b714cc99d5743ca";
pubKey2->setEC(ec2);
pubKey2->setQ(q2);
privKey2->setEC(ec2);
privKey2->setD(d2);
CPPUNIT_ASSERT(hash2 != NULL);
// Test with key #2
ByteString data2 = "616263"; // "abc"
ByteString goodSignature2 = "fb017b914e29149432d8bac29a514640b46f53ddab2c69948084e2930f1c8f7e08e07c9c63f2d21a07dcb56a6af56eb3b263a1305e057f984d38726a1b46874109f417bca112674c528262a40a629af1cbb9f516ce0fa7d2ff630863a00e8b9f";
ByteString badSignature2 = "fb017b914e29149432d8bac29a514640b46f53ddab2c69948084e2930f1c8f7e08e07c9c63f2d21a07dcb56a6af56eb3b263a1305e057f984d38726a1b46874109f417bca112674c528262a40a629af1cbb9f516ce0fa7d2ff630863a00e8b9e";
CPPUNIT_ASSERT(hash1->hashInit());
CPPUNIT_ASSERT(hash1->hashUpdate(data1));
ByteString hResult1;
CPPUNIT_ASSERT(hash1->hashFinal(hResult1));
CPPUNIT_ASSERT(ecdsa->verify(pubKey1, hResult1, goodSignature1, AsymMech::ECDSA));
CPPUNIT_ASSERT(!ecdsa->verify(pubKey1, hResult1, badSignature1, AsymMech::ECDSA));
CPPUNIT_ASSERT(hash2->hashInit());
CPPUNIT_ASSERT(hash2->hashUpdate(data2));
ByteString hResult2;
CPPUNIT_ASSERT(hash2->hashFinal(hResult2));
CPPUNIT_ASSERT(ecdsa->verify(pubKey2, hResult2, goodSignature2, AsymMech::ECDSA));
CPPUNIT_ASSERT(!ecdsa->verify(pubKey2, hResult2, badSignature2, AsymMech::ECDSA));
ecdsa->recyclePublicKey(pubKey1);
ecdsa->recyclePublicKey(pubKey2);
ecdsa->recyclePrivateKey(privKey1);
ecdsa->recyclePrivateKey(privKey2);
CryptoFactory::i()->recycleHashAlgorithm(hash1);
CryptoFactory::i()->recycleHashAlgorithm(hash2);
}
#endif