// // 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 #else #include #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); } }