Files
ANSCORE/anslicensing/ecc.cpp

597 lines
14 KiB
C++

//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "ecc.h"
#include "bigint.h"
#include "ec2m.h"
#include "sha1.h"
#include "except.h"
#include "base64.h"
#include "uniconv.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
namespace ECC {
#if 0
void biPrint( bigint & data )
{
int n;
unsigned * u;
n = ( data.bits() + 31 ) / 32;
u = new unsigned[ n ];
data.store( u, n );
printf( "%d ", data.bits() );
for ( int i = n - 1; i >= 0; i-- )
{
printf( "%08X ", u[i] );
}
printf("\n");
delete [] u;
}
#endif
static const curve_parameter eccCurveTable[ 10 ] = { { 9, 7, 1, 17, 43, 48, 1},
{ 12, 7, 1, 83, 2049, 10, 1 },
{ 13, 7, 1, 27, 124, 52, 1},
{ 15, 7, 1, 3, 977, 110, 1},
{ 16, 7, 1, 45, 2902, 6, 1},
{ 10, 11, 2, 9, 139, 34, 1},
{ 12, 11, 2, 83, 2083, 66, 1},
{ 13, 11, 2, 27, 773, 48, 1},
{ 14, 11, 2, 43, 146, 40, 1},
{ 10, 17, 3, 9, 48, 28, 1} };
static void UintArrayToByteArray(unsigned * srcArray, int bitCount, unsigned char * dstArray)
{
int dstLength = ((int)bitCount + 7) >> 3;
int srcLength = (dstLength + 3) >> 2;
int i = 0;
int j = 0;
unsigned currentUint;
if (dstLength > 3)
{
while (i < dstLength - 3)
{
currentUint = (j < srcLength) ? srcArray[j] : 0;
dstArray[i + 3] = (unsigned char)(currentUint >> 24);
dstArray[i + 2] = (unsigned char)((currentUint >> 16) & 0xFF);
dstArray[i + 1] = (unsigned char)((currentUint >> 8) & 0xFF);
dstArray[i] = (unsigned char)(currentUint & 0xFF);
i += 4;
j += 1;
}
}
currentUint = (j < srcLength) ? srcArray[j] : 0;
if (i < dstLength) dstArray[i] = (unsigned char)(currentUint & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 8) & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 16) & 0xFF);
}
static void ByteArrayToUintArray(unsigned char * srcArray, int srcLength, unsigned * dstArray)
{
int roundedLen = (srcLength + sizeof(unsigned) - 1) / sizeof(unsigned);
int i = 0;
int j = 0;
while (i < roundedLen - 1)
{
dstArray[i] = (unsigned)(((unsigned)srcArray[j + 3] << 24) | ((unsigned)srcArray[j + 2] << 16) | ((unsigned)srcArray[j + 1] << 8) | (unsigned)srcArray[j]);
i += 1;
j += 4;
}
dstArray[roundedLen - 1] = 0;
if (j < srcLength) dstArray[roundedLen - 1] = (unsigned)(srcArray[j]); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 8); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 16); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 24);
}
class KeyImpl {
friend class Key;
friend class SignerImpl;
friend class VerifierImpl;
friend void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
private:
KeyImpl()
{
}
KeyImpl(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
Load(keyBuf, bufLen, keyType);
}
KeyImpl(const char * base64Key, KEY_TYPE keyType = ECC)
{
BASE64 base64;
int len;
auto buf = base64.decode(base64Key, strlen(base64Key), &len);
if (buf.empty())
throw new LicensingException(STATUS_INVALID_PARAM, "invalid base64 key");
Load(buf.data(), len, keyType);
}
void Load(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
if (keyType == ECC)
{
unsigned char * keyBytes = (unsigned char *)keyBuf;
if ((keyBytes[0] >> 5) != 0)
throw new LicensingException(STATUS_INVALID_PARAM, "unsupported key version");
if (keyBytes[1] + 2 != bufLen)
throw new LicensingException(STATUS_INVALID_PARAM, "invalid key size");
isPrivate = ((keyBytes[0] & 0x10) != 0);
SetKeyType((KEY_TYPE)(keyBytes[0] & 0x0F));
int roundedLen = sizeof(unsigned) * ((bufLen - 2 + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray(keyBytes + 2, bufLen - 2, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
} else
{
SetKeyType(keyType);
int roundedLen = sizeof(unsigned) * ((bufLen + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray((unsigned char *)keyBuf, bufLen, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
}
}
bool Store(void * buf, int * bufLen)
{
unsigned char * keyBytes = (unsigned char *)buf;
int numBits = m_key.bits();
int numBytes = (numBits + 7) >> 3;
if (*bufLen < 2 + numBytes)
return false;
keyBytes[0] &= 0x1F; // set first 3 bits to 0 - version 1
if (isPrivate) keyBytes[0] |= 0x10; else keyBytes[0] &= 0xEF; // the 4th bit is 1 if it's a private key
keyBytes[0] = (keyBytes[0] & 0xF0) | (((unsigned char)m_keyType) & 0x0F); // the next 4 bits from 1st byte are the key type
keyBytes[1] = numBytes; // the second byte specifies the key size
int numUints = (numBytes + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * temp = (unsigned int *)_alloca(numUints * sizeof(unsigned));
m_key.store(temp, numUints);
UintArrayToByteArray(temp, numBits, keyBytes + 2);
*bufLen = numBytes + 2;
return true;
}
void SetKeyType(KEY_TYPE keyType)
{
m_keyType = keyType;
switch (keyType)
{
case ECC_54: m_keySize = 54;break;
case ECC_73: m_keySize = 73;break;
case ECC_79: m_keySize = 79;break;
case ECC_91: m_keySize = 91;break;
case ECC_97: m_keySize = 97;break;
case ECC_100: m_keySize = 100;break;
case ECC_120: m_keySize = 120;break;
case ECC_131: m_keySize = 131;break;
case ECC_141: m_keySize = 141;break;
case ECC_161: m_keySize = 161;break;
}
}
KEY_TYPE GetKeyType()
{
return m_keyType;
}
KEY_TYPE m_keyType;
int m_keySize;
bigint m_key;
bool isPrivate;
};
class SignerImpl {
public:
SignerImpl()
{
m_hashBits = 0; // thus select ECDSA as the signing algorithm
}
~SignerImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
unsigned int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPrivateKey(const KeyImpl & privKey)
{
m_privateKey = privKey;
}
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_privateKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint temp;
bigint_pair signature;
*sigLenBits = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? m_hashBits + m_privateKey.m_keySize : m_privateKey.m_keySize << 1;
*sigLen = (*sigLenBits + 7) >> 3;
unsigned * buf = (unsigned *)_alloca(msgLen + *sigLen + sizeof(unsigned) - 1);
// take care of endianess here, do not do just a memcpy()
memcpy(buf, msg, msgLen);
memset((char *)buf + msgLen, 0, sizeof(unsigned) - 1);
unsigned msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char msgHashBuf[20];
sha.GetHash(msgHashBuf);
ByteArrayToUintArray(msgHashBuf, 20, msgHash);
#endif
message.load(msgHash, 5);
signature = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? ecc.schnorr_sign(message, m_privateKey.m_key, Hash, m_hashBits) : ecc.dsa_sign(message, m_privateKey.m_key, Hash);
temp = (signature.r << m_privateKey.m_keySize); temp += signature.s;
unsigned int n = (unsigned)((*sigLen + sizeof(unsigned) - 1) / sizeof(unsigned));
temp.store(buf, n);
#ifndef LICENSING_BIG_ENDIAN
// take care of endianess here
memcpy(sigBuf, buf, *sigLen);
#else
UintArrayToByteArray(buf, *sigLenBits, (unsigned char *)sigBuf);
#endif
}
private:
KeyImpl m_privateKey;
int m_hashBits;
};
class VerifierImpl {
public:
VerifierImpl()
{
m_hashBits = 0;
}
~VerifierImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPublicKey(const KeyImpl & pubKey)
{
m_publicKey = pubKey;
}
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_publicKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint_pair signature;
int msgBufLen = (msgLen + sizeof(unsigned) - 1) / sizeof(unsigned);
int sigBufLen = (sigLen + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * msgBuf = (unsigned *)_alloca(msgBufLen * sizeof(unsigned));
unsigned * sigBuf = (unsigned *)_alloca(sigBufLen * sizeof(unsigned));
#ifndef LICENSING_BIG_ENDIAN
memset(msgBuf, 0, msgBufLen * sizeof(unsigned));
memcpy(msgBuf, msg, msgLen);
memset(sigBuf, 0, sigBufLen * sizeof(unsigned));
memcpy(sigBuf, sig, sigLen);
#else
ByteArrayToUintArray((unsigned char *)msg, msgLen, msgBuf);
ByteArrayToUintArray((unsigned char *)sig, sigLen, sigBuf);
#endif
unsigned int msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char byteHash[20];
sha.GetHash(byteHash);
ByteArrayToUintArray(byteHash, 20, msgHash);
#endif
message.load(msgHash, 5);
signature.r.load(sigBuf, sigBufLen);
signature.r >>= m_publicKey.m_keySize; signature.r &= (pow2((unsigned)(sigLenBits - m_publicKey.m_keySize)) - 1);
signature.s.load(sigBuf, sigBufLen);
signature.s &= (pow2(m_publicKey.m_keySize) - 1);
return (m_hashBits && m_hashBits < m_publicKey.m_keySize) ? ecc.schnorr_verify(message, signature, m_publicKey.m_key, Hash, m_hashBits) : ecc.dsa_verify(message, signature, m_publicKey.m_key, Hash);
}
private:
int m_hashBits;
KeyImpl m_publicKey;
};
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey)
{
full_curve_parameter param(eccCurveTable[ keyType ]);
ECC_BASE ecc(param);
Key * privateKey = new Key(),
* publicKey = new Key();
privateKey->m_Impl.m_key = ecc.create_private_key();
privateKey->m_Impl.SetKeyType(keyType);
privateKey->m_Impl.isPrivate = true;
publicKey->m_Impl.m_key = ecc.create_public_key(privateKey->m_Impl.m_key);
publicKey->m_Impl.SetKeyType(keyType);
*privKey = privateKey;
*pubKey = publicKey;
}
Key::Key():
m_Impl( *new KeyImpl() )
{
}
Key::Key(const void * keyBuf, int bufLen, KEY_TYPE keyType):
m_Impl( *new KeyImpl(keyBuf, bufLen, keyType) )
{
}
Key::Key(const char * base64Key, KEY_TYPE keyType):
m_Impl( *new KeyImpl(base64Key, keyType))
{
}
Key::~Key()
{
delete & m_Impl;
}
void Key::Load(const void * keyData, int keyLen, KEY_TYPE keyType)
{
m_Impl.Load(keyData, keyLen, keyType);
}
bool Key::Store(void * buf, int * bufLen) const
{
return m_Impl.Store(buf, bufLen);
}
const char * Key::ToString()
{
static string base64key;
int len = 2 + ((m_Impl.m_key.bits() + 7) >> 3);
unsigned char * buf = (unsigned char *)_alloca(len);
Store(buf, &len);
BASE64 base64;
auto base64Buf = base64.encode(buf, len, true);
if (base64Buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
base64key = base64Buf.c_str();
return base64key.c_str();
}
KEY_TYPE Key::GetKeyType()
{
return m_Impl.GetKeyType();
}
const Key & Key::operator = (const Key & key)
{
m_Impl = key.m_Impl;
return (const Key &)(*this);
}
Signer::Signer():
m_Impl(*new SignerImpl())
{
}
Signer::~Signer()
{
delete & m_Impl;
}
void Signer::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Signer::SetPrivateKey(const Key * privKey)
{
m_Impl.SetPrivateKey(privKey->m_Impl);
}
void Signer::Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
m_Impl.Sign(msg, msgLen, sigBuf, sigLen, sigLenBits);
}
Verifier::Verifier():
m_Impl( *new VerifierImpl() )
{
}
Verifier::~Verifier()
{
delete & m_Impl;
}
void Verifier::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Verifier::SetPublicKey(const Key * pubKey)
{
m_Impl.SetPublicKey(pubKey->m_Impl);
}
bool Verifier::Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
return m_Impl.Verify(msg, msgLen, sig, sigLen, sigLenBits);
}
}