// // The developer of the original code and/or files is Tripwire, Inc. // Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire, // Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights // reserved. // // This program is free software. The contents of this file are subject // to the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. You may redistribute it and/or modify it // only in compliance with the GNU General Public License. // // This program is distributed in the hope that it will be useful. // However, this program is distributed AS-IS WITHOUT ANY // WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. Please see the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // Nothing in the GNU General Public License or any other license to use // the code or files shall permit you to use Tripwire's trademarks, // service marks, or other intellectual property without Tripwire's // prior written consent. // // If you have any questions, please contact Tripwire, Inc. at either // info@tripwire.org or www.tripwire.org. // /////////////////////////////////////////////////////////////////////////////// // crypto.cpp -- Tripwire crypto implementation // #include "stdtwcrypto.h" #include "crypto.h" #include "core/errorgeneral.h" #include "time.h" #include "core/archive.h" #include "cryptlib/sha.h" #include "cryptlib/rng.h" #include "cryptlib/des.h" #include "cryptlib/integer.h" #include "cryptlib/elgamal.h" #include "cryptlib/des.h" #ifdef _IDEA_ENCRYPTION #include "cryptlib/idea.h" #endif #ifdef _RSA_ENCRYPTION #include "cryptlib/rsa.h" #endif const uint32 EL_GAMAL_SIG_PUBLIC_MAGIC_NUM = 0x7ae2c945; const uint32 EL_GAMAL_SIG_PRIVATE_MAGIC_NUM = 0x0d0ffa12; /////////////////////////////////////////////////////////////////////////////// // macros for reading and writing integers #define WRITE_INTEGER(I) \ len = I.MinEncodedSize(Integer::UNSIGNED); \ ASSERT(len >=0 && len < 9000); \ i32 = tw_htonl(len); \ memcpy(pOut, &i32, sizeof(i32)); \ pOut += sizeof(int32); \ I.Encode(pOut, len, Integer::UNSIGNED); \ pOut += len; #define READ_INTEGER(I) \ memcpy(&i32, pIn, sizeof(i32)); \ len = tw_ntohl(i32); \ ASSERT(len >= 0 && len < 9000); \ pIn += sizeof(int32); \ I.Decode(pIn, len, Integer::UNSIGNED); \ pIn += len; /////////////////////////////////////////////////////////////////////////////// // class cNullCipher -- no encryption cipher int cNullCipher::GetBlockSizePlain() { // lets use the blocksize of TripleDES_Encryption since that may be // better than picking a blocksize at random return TripleDES_Encryption::BLOCKSIZE; } // return the size of data blocks for plaintext and cipertext int cNullCipher::GetBlockSizeCipher() { return TripleDES_Encryption::BLOCKSIZE; } // process a block of data. indata and outdata may be the same memory void cNullCipher::ProcessBlock(const void* indata, void* outdata) { memmove(outdata, indata, TripleDES_Encryption::BLOCKSIZE); } ////////////////////////////////////////////////////////////////////////////// // class cIDEA ////////////////////////////////////////////////////////////////////////////// #ifdef _IDEA_ENCRYPTION class cIDEA_i { public: IDEA* mpIDEA; }; cIDEA::cIDEA() { mpData = new cIDEA_i; mpData->mpIDEA = 0; } cIDEA::~cIDEA() { delete mpData->mpIDEA; delete mpData; mpData = 0; } void cIDEA::SetKey(iCipher::EncryptionDir dir, const cHashedKey128& key) { // some things we are assuming ASSERT(IDEA::KEYLENGTH == 16); ASSERT(mpData); delete mpData->mpIDEA; mpData->mpIDEA = new IDEA((byte*)key.GetKey(), dir == iCipher::ENCRYPT ? ENCRYPTION : DECRYPTION); } // return the size of data block this crypter works on int cIDEA::GetBlockSizePlain() { return IDEA::BLOCKSIZE; } int cIDEA::GetBlockSizeCipher() { return IDEA::BLOCKSIZE; } // process a block of data. indata and outdata may be the same memory void cIDEA::ProcessBlock(const void* indata, void* outdata) { ASSERT(mpData->mpIDEA); if (!mpData->mpIDEA) { ThrowAndAssert(eInternal(_T("Key not set in symmetric encryption."))); } mpData->mpIDEA->ProcessBlock((byte*)indata, (byte*)outdata); } #endif // _IDEA_ENCRYPTION ////////////////////////////////////////////////////////////////////////////// // class cTripleDES ////////////////////////////////////////////////////////////////////////////// class cTripleDES_i { public: TripleDES_Encryption* mpEncryptor; TripleDES_Decryption* mpDecryptor; }; cTripleDES::cTripleDES() { mpData = new cTripleDES_i; mpData->mpEncryptor = 0; mpData->mpDecryptor = 0; } cTripleDES::~cTripleDES() { delete mpData->mpEncryptor; delete mpData->mpDecryptor; delete mpData; mpData = 0; } void cTripleDES::SetKey(iCipher::EncryptionDir dir, const cHashedKey192& key) { // some things we are assuming ASSERT(TripleDES_Encryption::KEYLENGTH == 24); ASSERT(cHashedKey192::GetWriteLen() == 24); ASSERT(mpData != 0); if (dir == iCipher::ENCRYPT) { delete mpData->mpEncryptor; delete mpData->mpDecryptor; mpData->mpDecryptor = 0; mpData->mpEncryptor = new TripleDES_Encryption((byte*)key.GetKey()); } else { delete mpData->mpEncryptor; delete mpData->mpDecryptor; mpData->mpEncryptor = 0; mpData->mpDecryptor = new TripleDES_Decryption((byte*)key.GetKey()); } } // return the size of data block this crypter works on int cTripleDES::GetBlockSizePlain() { ASSERT(TripleDES_Encryption::BLOCKSIZE == TripleDES_Decryption::BLOCKSIZE); return TripleDES_Encryption::BLOCKSIZE; } int cTripleDES::GetBlockSizeCipher() { ASSERT(TripleDES_Encryption::BLOCKSIZE == TripleDES_Decryption::BLOCKSIZE); return TripleDES_Encryption::BLOCKSIZE; } // process a block of data. indata and outdata may be the same memory void cTripleDES::ProcessBlock(const void* indata, void* outdata) { ASSERT(mpData != 0); ASSERT(mpData->mpEncryptor || mpData->mpDecryptor); if (!mpData->mpEncryptor && !mpData->mpDecryptor) { ThrowAndAssert(INTERNAL_ERROR("crypto.cpp")); //cTWError::E_INTERNAL, TSTRING(_T("Key not set in symmetric encryption.")))); } if (mpData->mpEncryptor) mpData->mpEncryptor->ProcessBlock((byte*)indata, (byte*)outdata); else mpData->mpDecryptor->ProcessBlock((byte*)indata, (byte*)outdata); } /////////////////////////////////////////////////////////////////////////////// // class cRSA #ifdef _RSA_ENCRYPTION // class cRSAPrivateKey class cRSAPrivateKey_i { public: int16 mKeyLength; RSAPrivateKey* mpKey; }; cRSAPrivateKey::cRSAPrivateKey() { mpData = new cRSAPrivateKey_i; mpData->mpKey = 0; mpData->mKeyLength = 0; } cRSAPrivateKey::cRSAPrivateKey(void* pDataStream) { mpData = new cRSAPrivateKey_i; int32 len; int32 i32; int16 i16; byte* pIn = (byte*)pDataStream; memcpy(&i16, pIn, sizeof(i16)); mpData->mKeyLength = tw_ntohs(i16); pIn += sizeof(int16); Integer n, e, d, p, q, dp, dq, u; READ_INTEGER(n); READ_INTEGER(e); READ_INTEGER(d); READ_INTEGER(p); READ_INTEGER(q); READ_INTEGER(dp); READ_INTEGER(dq); READ_INTEGER(u); mpData->mpKey = new RSAPrivateKey(n, e, d, p, q, dp, dq, u); } cRSAPrivateKey::~cRSAPrivateKey() { if (mpData) { delete mpData->mpKey; delete mpData; } } int cRSAPrivateKey::GetWriteLen() const { ASSERT(mpData->mpKey); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetModulus().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetExponent().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetPrime1().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetPrime2().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetDecryptionExponent().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterDP().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterDQ().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterU().IsPositive()); int len = sizeof(int16) + mpData->mpKey->GetTrapdoorFunction().GetModulus().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetExponent().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetPrime1().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetPrime2().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetDecryptionExponent().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetParameterDP().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetParameterDQ().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetParameterU().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32); return len; } void cRSAPrivateKey::Write(void* pDataStream) const { ASSERT(mpData->mpKey); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetModulus().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetExponent().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetPrime1().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetPrime2().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetDecryptionExponent().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterDP().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterDQ().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetParameterU().IsPositive()); byte* pOut = (byte*)pDataStream; int16 i16; int32 i32; i16 = tw_htons(mpData->mKeyLength); memcpy(pOut, &i16, sizeof(i16)); pOut += sizeof(int16); Integer n, e, d, p, q, dp, dq, u; n = mpData->mpKey->GetTrapdoorFunction().GetModulus(); e = mpData->mpKey->GetTrapdoorFunction().GetExponent(); p = mpData->mpKey->GetTrapdoorFunction().GetPrime1(); q = mpData->mpKey->GetTrapdoorFunction().GetPrime2(); d = mpData->mpKey->GetTrapdoorFunction().GetDecryptionExponent(); dp = mpData->mpKey->GetTrapdoorFunction().GetParameterDP(); dq = mpData->mpKey->GetTrapdoorFunction().GetParameterDQ(); u = mpData->mpKey->GetTrapdoorFunction().GetParameterU(); int32 len; #define WRITE_INTEGER(I) \ len = I.MinEncodedSize(Integer::UNSIGNED); \ i32 = tw_htonl(len); \ memcpy(pOut, &i32, sizeof(i32)); \ pOut += sizeof(int32); \ I.Encode(pOut, len, Integer::UNSIGNED); \ pOut += len; WRITE_INTEGER(n); WRITE_INTEGER(e); WRITE_INTEGER(d); WRITE_INTEGER(p); WRITE_INTEGER(q); WRITE_INTEGER(dp); WRITE_INTEGER(dq); WRITE_INTEGER(u); } // class cRSAPublicKey class cRSAPublicKey_i { public: int16 mKeyLength; RSAPublicKey* mpKey; }; cRSAPublicKey::cRSAPublicKey() { mpData = new cRSAPublicKey_i; mpData->mpKey = 0; mpData->mKeyLength = 0; } cRSAPublicKey::cRSAPublicKey(void* pDataStream) { mpData = new cRSAPublicKey_i; Integer n, e; int32 len; int16 i16; int32 i32; byte* pIn = (byte*)pDataStream; memcpy(&i16, pIn, sizeof(i16)); mpData->mKeyLength = tw_ntohs(i16); pIn += sizeof(int16); READ_INTEGER(n); READ_INTEGER(e); //std::cout << "cRSAPublicKey n = " << n << std::endl; //std::cout << "cRSAPublicKey e = " << e << std::endl; mpData->mpKey = new RSAPublicKey(n, e); } cRSAPublicKey::cRSAPublicKey(const cRSAPrivateKey& privateKey) { mpData = new cRSAPublicKey_i; ASSERT(privateKey.mpData); ASSERT(privateKey.mpData->mpKey); mpData->mKeyLength = privateKey.mpData->mKeyLength; mpData->mpKey = new RSAPublicKey(*privateKey.mpData->mpKey); } cRSAPublicKey::~cRSAPublicKey() { if (mpData) { delete mpData->mpKey; delete mpData; } } int cRSAPublicKey::GetWriteLen() const { ASSERT(mpData->mpKey); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetModulus().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetExponent().IsPositive()); int len = sizeof(int16) + mpData->mpKey->GetTrapdoorFunction().GetModulus().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetTrapdoorFunction().GetExponent().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32); return len; } void cRSAPublicKey::Write(void* pDataStream) const { ASSERT(mpData->mpKey); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetModulus().IsPositive()); ASSERT(mpData->mpKey->GetTrapdoorFunction().GetExponent().IsPositive()); int16 i16; int32 i32; byte* pOut = (byte*)pDataStream; i16 = tw_htons(mpData->mKeyLength); memcpy(pOut, &i16, sizeof(i16)); pOut += sizeof(int16); Integer n, e; n = mpData->mpKey->GetTrapdoorFunction().GetModulus(); e = mpData->mpKey->GetTrapdoorFunction().GetExponent(); int32 len; WRITE_INTEGER(n); WRITE_INTEGER(e); } #ifdef DEBUG void cRSAPublicKey::TraceContents() { cDebug d("cRSAPublicKey::TraceContents"); { std::ostringstream os; os << mpData->mpKey->GetTrapdoorFunction().GetModulus(); d.TraceDebug("Modulus = %s\n", os.str().c_str()); } { std::ostringstream os; os << mpData->mpKey->GetTrapdoorFunction().GetExponent(); d.TraceDebug("Exponent = %s\n", os.str().c_str()); } } #endif // class cRSA class cRSA_i { public: int mKeyBits; enum Action { ENCRYPT, DECRYPT, SIGN, VERIFY }; Action mAction; const cRSAPrivateKey* mpPrivateKey; const cRSAPublicKey* mpPublicKey; X917RNG* mpRNG; }; cRSA::cRSA(KeySize keysize) { Init(keysize); } cRSA::cRSA(const cRSAPublicKey& publicKey) { ASSERT(publicKey.mpData); Init((KeySize)publicKey.mpData->mKeyLength); } cRSA::cRSA(const cRSAPrivateKey& privateKey) { ASSERT(privateKey.mpData); Init((KeySize)privateKey.mpData->mKeyLength); } void cRSA::Init(KeySize keysize) { mpData = new cRSA_i; mpData->mpPrivateKey = 0; mpData->mpPublicKey = 0; mpData->mKeyBits = (keysize == KEY256) ? 256 : (keysize == KEY512) ? 512 : (keysize == KEY1024) ? 1024 : (keysize == KEY2048) ? 2048 : 256; // Create a random seed and a key byte seed[MD5::DATASIZE]; byte deskey[TripleDES_Encryption::KEYLENGTH]; RandomizeBytes((int8*)seed, MD5::DATASIZE); RandomizeBytes((int8*)deskey, TripleDES_Encryption::KEYLENGTH); mpData->mpRNG = new X917RNG(new TripleDES_Encryption(deskey), seed); } cRSA::~cRSA() { if (mpData) { delete mpData->mpRNG; delete mpData; mpData = 0; } } void cRSA::SetEncrypting(const cRSAPublicKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("RSA Key length mismatch."))); mpData->mAction = cRSA_i::ENCRYPT; mpData->mpPublicKey = pKey; mpData->mpPrivateKey = 0; } void cRSA::SetDecrypting(const cRSAPrivateKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("RSA Key length mismatch."))); mpData->mAction = cRSA_i::DECRYPT; mpData->mpPrivateKey = pKey; mpData->mpPublicKey = 0; } void cRSA::SetSigning(const cRSAPrivateKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("RSA Key length mismatch."))); mpData->mAction = cRSA_i::SIGN; mpData->mpPrivateKey = pKey; mpData->mpPublicKey = 0; } void cRSA::SetVerifying(const cRSAPublicKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("RSA Key length mismatch."))); mpData->mAction = cRSA_i::VERIFY; mpData->mpPublicKey = pKey; mpData->mpPrivateKey = 0; } // Lets encrypt in 128 bit chunks, even though the crypto // lib implementation can do arbitrary length plaintext // encryptions. We will most likely only use this to // encrypt a 128 bit random number anyway. int cRSA::GetBlockSizePlain() { //Integer i = mpData->mKeyBits - 1; return (mpData->mKeyBits >> 3) - 11; } int cRSA::GetBlockSizeCipher() { return mpData->mKeyBits >> 3; } void cRSA::ProcessBlock(const void* indata, void* outdata) { ASSERT(mpData); ASSERT(mpData->mpPrivateKey != 0 || mpData->mpPublicKey != 0); if (mpData->mpPrivateKey == 0 && mpData->mpPublicKey == 0) ThrowAndAssert(eInternal(_T("RSA Key length mismatch."))); unsigned int l; switch (mpData->mAction) { case cRSA_i::ENCRYPT: { ASSERT(mpData->mpPublicKey); ASSERT(mpData->mpPublicKey->mpData->mpKey->MaxPlainTextLength() == GetBlockSizePlain()); ASSERT(mpData->mpPublicKey->mpData->mpKey->CipherTextLength() == GetBlockSizeCipher()); mpData->mpPublicKey->mpData->mpKey->Encrypt(*mpData->mpRNG, (const byte *)indata, GetBlockSizePlain(), (byte *)outdata); break; } case cRSA_i::DECRYPT: { ASSERT(mpData->mpPrivateKey); ASSERT(mpData->mpPrivateKey->mpData->mpKey->CipherTextLength() == GetBlockSizeCipher()); l = mpData->mpPrivateKey->mpData->mpKey->Decrypt((const byte *)indata, (byte *)outdata); if (l != GetBlockSizePlain()) throw eArchiveCrypto(); break; } case cRSA_i::SIGN: { ASSERT(mpData->mpPrivateKey); ASSERT(mpData->mpPrivateKey->mpData->mpKey->MaxMessageLength() == GetBlockSizePlain()); ASSERT(mpData->mpPrivateKey->mpData->mpKey->SignatureLength() == GetBlockSizeCipher()); mpData->mpPrivateKey->mpData->mpKey->Sign(*mpData->mpRNG, (const byte *)indata, GetBlockSizePlain(), (byte *)outdata); break; } case cRSA_i::VERIFY: { ASSERT(mpData->mpPublicKey); ASSERT(mpData->mpPublicKey->mpData->mpKey->SignatureLength() == GetBlockSizeCipher()); l = mpData->mpPublicKey->mpData->mpKey->Recover((const byte *)indata, (byte *)outdata); if (l != GetBlockSizePlain()) throw eArchiveCrypto(); break; } default: { ASSERT(false); break; } } } void cRSA::GenerateKeys(cRSAPrivateKey*& retPrivate, cRSAPublicKey*& retPublic) { RSAPrivateKey* pNewPrivateKey = new RSAPrivateKey(*mpData->mpRNG, mpData->mKeyBits); RSAPublicKey* pNewPublicKey = new RSAPublicKey(*pNewPrivateKey); retPrivate = new cRSAPrivateKey(); retPrivate->mpData->mpKey = pNewPrivateKey; retPrivate->mpData->mKeyLength = mpData->mKeyBits; retPublic = new cRSAPublicKey(); retPublic->mpData->mpKey = pNewPublicKey; retPublic->mpData->mKeyLength = mpData->mKeyBits; #ifdef DEBUG int l; l = retPublic->mpData->mpKey->MaxPlainTextLength(); ASSERT(l == GetBlockSizePlain()); l = retPublic->mpData->mpKey->CipherTextLength(); ASSERT(l == GetBlockSizeCipher()); l = retPrivate->mpData->mpKey->CipherTextLength(); ASSERT(l == GetBlockSizeCipher()); #endif } #endif // _RSA_ENCRYPTION /////////////////////////////////////////////////////////////////////////////// // class cElGamalSig // class cElGamalSigPrivateKey class cElGamalSigPrivateKey_i { public: int16 mKeyLength; ElGamalSigPrivateKey* mpKey; }; cElGamalSigPrivateKey::cElGamalSigPrivateKey() { mpData = new cElGamalSigPrivateKey_i; mpData->mpKey = 0; mpData->mKeyLength = 0; } cElGamalSigPrivateKey::cElGamalSigPrivateKey(void* pDataStream) { mpData = new cElGamalSigPrivateKey_i; int32 len; int32 i32; int16 i16; uint32 magicNum; byte* pIn = (byte*)pDataStream; memcpy(&i16, pIn, sizeof(i16)); mpData->mKeyLength = tw_ntohs(i16); pIn += sizeof(int16); memcpy(&i32, pIn, sizeof(i32)); magicNum = tw_ntohl(i32); pIn += sizeof(int32); if (magicNum != EL_GAMAL_SIG_PRIVATE_MAGIC_NUM) ThrowAndAssert( eArchiveOpen() ); Integer p, q, g, y, x; READ_INTEGER(p); READ_INTEGER(q); READ_INTEGER(g); READ_INTEGER(y); READ_INTEGER(x); mpData->mpKey = new ElGamalSigPrivateKey(p, q, g, y, x); } cElGamalSigPrivateKey::~cElGamalSigPrivateKey() { if (mpData) { delete mpData->mpKey; delete mpData; } } int cElGamalSigPrivateKey::GetWriteLen() const { ASSERT(mpData->mpKey != 0); ASSERT(mpData->mpKey->GetPrime().IsPositive()); ASSERT(mpData->mpKey->GetParameterQ().IsPositive()); ASSERT(mpData->mpKey->GetParameterG().IsPositive()); ASSERT(mpData->mpKey->GetParameterY().IsPositive()); ASSERT(mpData->mpKey->GetParameterX().IsPositive()); int len = sizeof(int16) + sizeof(int32) + mpData->mpKey->GetPrime().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterQ().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterG().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterY().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterX().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32); return len; } void cElGamalSigPrivateKey::Write(void* pDataStream) const { ASSERT(mpData->mpKey != 0); ASSERT(mpData->mpKey->GetPrime().IsPositive()); ASSERT(mpData->mpKey->GetParameterQ().IsPositive()); ASSERT(mpData->mpKey->GetParameterG().IsPositive()); ASSERT(mpData->mpKey->GetParameterY().IsPositive()); ASSERT(mpData->mpKey->GetParameterX().IsPositive()); byte* pOut = (byte*)pDataStream; int16 i16; int32 i32; i16 = tw_htons(mpData->mKeyLength); memcpy(pOut, &i16, sizeof(i16)); pOut += sizeof(int16); i32 = tw_htonl(EL_GAMAL_SIG_PRIVATE_MAGIC_NUM); memcpy(pOut, &i32, sizeof(i32)); pOut += sizeof(int32); Integer p, q, g, y, x; p = mpData->mpKey->GetPrime(); q = mpData->mpKey->GetParameterQ(); g = mpData->mpKey->GetParameterG(); y = mpData->mpKey->GetParameterY(); x = mpData->mpKey->GetParameterX(); int32 len; WRITE_INTEGER(p); WRITE_INTEGER(q); WRITE_INTEGER(g); WRITE_INTEGER(y); WRITE_INTEGER(x); } // class cElGamalSigPublicKey class cElGamalSigPublicKey_i { public: int16 mKeyLength; ElGamalSigPublicKey* mpKey; }; cElGamalSigPublicKey::cElGamalSigPublicKey() { mpData = new cElGamalSigPublicKey_i; mpData->mpKey = 0; mpData->mKeyLength = 0; } cElGamalSigPublicKey::cElGamalSigPublicKey(void* pDataStream) { mpData = new cElGamalSigPublicKey_i; Integer p, q, g, y; int32 len; int16 i16; int32 i32; uint32 magicNum; byte* pIn = (byte*)pDataStream; memcpy(&i16, pIn, sizeof(i16)); mpData->mKeyLength = tw_ntohs(i16); pIn += sizeof(int16); memcpy(&i32, pIn, sizeof(i32)); magicNum = tw_ntohl(i32); pIn += sizeof(int32); if (magicNum != EL_GAMAL_SIG_PUBLIC_MAGIC_NUM) ThrowAndAssert( eArchiveOpen() ); READ_INTEGER(p); READ_INTEGER(q); READ_INTEGER(g); READ_INTEGER(y); //std::cout << "cElGamalSigPublicKey n = " << n << std::endl; //std::cout << "cElGamalSigPublicKey e = " << e << std::endl; mpData->mpKey = new ElGamalSigPublicKey(p, q, g, y); } cElGamalSigPublicKey::cElGamalSigPublicKey(const cElGamalSigPrivateKey& privateKey) { mpData = new cElGamalSigPublicKey_i; ASSERT(privateKey.mpData != 0); ASSERT(privateKey.mpData->mpKey != 0); mpData->mKeyLength = privateKey.mpData->mKeyLength; mpData->mpKey = new ElGamalSigPublicKey(*privateKey.mpData->mpKey); } cElGamalSigPublicKey::~cElGamalSigPublicKey() { if (mpData) { delete mpData->mpKey; delete mpData; } } int cElGamalSigPublicKey::GetWriteLen() const { ASSERT(mpData->mpKey != 0); ASSERT(mpData->mpKey->GetPrime().IsPositive()); ASSERT(mpData->mpKey->GetParameterQ().IsPositive()); ASSERT(mpData->mpKey->GetParameterG().IsPositive()); ASSERT(mpData->mpKey->GetParameterY().IsPositive()); int len = sizeof(int16) + sizeof(int32) + mpData->mpKey->GetPrime().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterQ().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterG().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32) + mpData->mpKey->GetParameterY().MinEncodedSize(Integer::UNSIGNED) + sizeof(int32); return len; } void cElGamalSigPublicKey::Write(void* pDataStream) const { ASSERT(mpData->mpKey != 0); ASSERT(mpData->mpKey->GetPrime().IsPositive()); ASSERT(mpData->mpKey->GetParameterQ().IsPositive()); ASSERT(mpData->mpKey->GetParameterG().IsPositive()); ASSERT(mpData->mpKey->GetParameterY().IsPositive()); byte* pOut = (byte*)pDataStream; int16 i16; int32 i32; i16 = tw_htons(mpData->mKeyLength); memcpy(pOut, &i16, sizeof(i16)); pOut += sizeof(int16); i32 = tw_htonl(EL_GAMAL_SIG_PUBLIC_MAGIC_NUM); memcpy(pOut, &i32, sizeof(i32)); pOut += sizeof(int32); Integer p, q, g, y; p = mpData->mpKey->GetPrime(); q = mpData->mpKey->GetParameterQ(); g = mpData->mpKey->GetParameterG(); y = mpData->mpKey->GetParameterY(); int32 len; WRITE_INTEGER(p); WRITE_INTEGER(q); WRITE_INTEGER(g); WRITE_INTEGER(y); } bool cElGamalSigPublicKey::IsEqual(const cElGamalSigPublicKey& rhs) const { return this->mpData->mpKey->GetPrime() == rhs.mpData->mpKey->GetPrime() && this->mpData->mpKey->GetParameterQ() == rhs.mpData->mpKey->GetParameterQ() && this->mpData->mpKey->GetParameterG() == rhs.mpData->mpKey->GetParameterG() && this->mpData->mpKey->GetParameterY() == rhs.mpData->mpKey->GetParameterY() ; } #ifdef DEBUG void cElGamalSigPublicKey::TraceContents() { cDebug d("cElGamalSigPublicKey::TraceContents"); { std::ostringstream os; os << mpData->mpKey->GetPrime(); d.TraceDebug("Prime = %s\n", os.str().c_str()); } { std::ostringstream os; os << mpData->mpKey->GetParameterQ(); d.TraceDebug("Q = %s\n", os.str().c_str()); } { std::ostringstream os; os << mpData->mpKey->GetParameterG(); d.TraceDebug("G = %s\n", os.str().c_str()); } { std::ostringstream os; os << mpData->mpKey->GetParameterY(); d.TraceDebug("Y = %s\n", os.str().c_str()); } } #endif // class cElGamalSig class cElGamalSig_i { public: int mKeyBits; enum Action { /*ENCRYPT, DECRYPT,*/ SIGN, VERIFY }; Action mAction; const cElGamalSigPrivateKey* mpPrivateKey; const cElGamalSigPublicKey* mpPublicKey; SHA mSHA; X917RNG* mpRNG; }; cElGamalSig::cElGamalSig(KeySize keysize) { Init(keysize); } cElGamalSig::cElGamalSig(const cElGamalSigPublicKey& publicKey) { ASSERT(publicKey.mpData != 0); Init((KeySize)publicKey.mpData->mKeyLength); } cElGamalSig::cElGamalSig(const cElGamalSigPrivateKey& privateKey) { ASSERT(privateKey.mpData != 0); Init((KeySize)privateKey.mpData->mKeyLength); } void cElGamalSig::Init(KeySize keysize) { mpData = new cElGamalSig_i; mpData->mpPrivateKey = 0; mpData->mpPublicKey = 0; mpData->mKeyBits = (keysize == KEY256) ? 256 : (keysize == KEY512) ? 512 : (keysize == KEY1024) ? 1024 : (keysize == KEY2048) ? 2048 : 256; // Create a random seed and a key byte seed[SHA::DATASIZE]; byte deskey[TripleDES_Encryption::KEYLENGTH]; RandomizeBytes((int8*)seed, SHA::DATASIZE); RandomizeBytes((int8*)deskey, TripleDES_Encryption::KEYLENGTH); mpData->mpRNG = new X917RNG(new TripleDES_Encryption(deskey), seed); } cElGamalSig::~cElGamalSig() { if (mpData) { delete mpData->mpRNG; delete mpData; mpData = 0; } } void cElGamalSig::SetSigning(const cElGamalSigPrivateKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("Signature Key length mismatch."))); mpData->mAction = cElGamalSig_i::SIGN; mpData->mpPrivateKey = pKey; mpData->mpPublicKey = 0; } void cElGamalSig::SetVerifying(const cElGamalSigPublicKey* pKey) { ASSERT(pKey->mpData->mKeyLength == mpData->mKeyBits); if (pKey->mpData->mKeyLength != mpData->mKeyBits) ThrowAndAssert(eInternal(_T("Signature Key length mismatch."))); mpData->mAction = cElGamalSig_i::VERIFY; mpData->mpPublicKey = pKey; mpData->mpPrivateKey = 0; } int cElGamalSig::GetBlockSizePlain() { return PLAIN_BLOCK_SIZE; } int cElGamalSig::GetBlockSizeCipher() { return PLAIN_BLOCK_SIZE + (NumberTheory::DiscreteLogWorkFactor(mpData->mKeyBits) >> 1) + 4; // got this from nbtheory.cpp in crypto++ lib // El Gamal's sig size = 2 * 2 * (DiscreteLogWorkFactor() >> 3) } void cElGamalSig::ProcessBlock(const void* indata, void* outdata) { ASSERT(mpData != 0); ASSERT(mpData->mpPrivateKey != 0 || mpData->mpPublicKey != 0); int8 shaSig[SHA::DIGESTSIZE]; if (mpData->mpPrivateKey == 0 && mpData->mpPublicKey == 0) ThrowAndAssert(eInternal(_T("Signature Key length mismatch."))); switch (mpData->mAction) { case cElGamalSig_i::SIGN: { ASSERT(mpData->mpPrivateKey != 0); ASSERT((int)mpData->mpPrivateKey->mpData->mpKey->SignatureLength() + PLAIN_BLOCK_SIZE <= GetBlockSizeCipher()); memmove(outdata, indata, PLAIN_BLOCK_SIZE); mpData->mSHA.CalculateDigest((byte*)shaSig, (byte*)outdata, PLAIN_BLOCK_SIZE); RandomizeBytes((int8 *)outdata + PLAIN_BLOCK_SIZE, GetBlockSizeCipher() - PLAIN_BLOCK_SIZE); mpData->mpPrivateKey->mpData->mpKey->Sign(*mpData->mpRNG, (const byte *)shaSig, SHA::DIGESTSIZE, (byte *)outdata + PLAIN_BLOCK_SIZE); /* Integer m((const byte*)indata, PLAIN_BLOCK_SIZE); std::cout << "Signing:\n"; std::cout << "M = " << m << std::endl; const byte* signature = (const byte *)outdata + PLAIN_BLOCK_SIZE; int qLen = mpData->mpPrivateKey->mpData->mpKey->q.ByteCount(); Integer rs(signature, qLen); Integer ss(signature+qLen, qLen); std::cout << "Stored R = " << rs << std::endl; std::cout << "Stored S = " << ss << std::endl; */ break; } case cElGamalSig_i::VERIFY: { ASSERT(mpData->mpPublicKey != 0); ASSERT((int)mpData->mpPublicKey->mpData->mpKey->SignatureLength() + PLAIN_BLOCK_SIZE <= GetBlockSizeCipher()); mpData->mSHA.CalculateDigest((byte*)shaSig, (byte*)indata, PLAIN_BLOCK_SIZE); /* const byte* signature = (const byte *)indata + PLAIN_BLOCK_SIZE; int qLen = mpData->mpPublicKey->mpData->mpKey->q.ByteCount(); Integer m((const byte*)indata, PLAIN_BLOCK_SIZE); Integer r(signature, qLen); Integer s(signature+qLen, qLen); std::cout << "Verifying:\n"; std::cout << "M = " << m << std::endl; std::cout << "R = " << r << std::endl; std::cout << "S = " << s << std::endl; */ if (mpData->mpPublicKey->mpData->mpKey->Verify((const byte *)shaSig, SHA::DIGESTSIZE, (const byte *)indata + PLAIN_BLOCK_SIZE) == false) throw eArchiveCrypto(); memmove(outdata, indata, PLAIN_BLOCK_SIZE); break; } default: { ASSERT(false); break; } } } void cElGamalSig::GenerateKeys(cElGamalSigPrivateKey*& retPrivate, cElGamalSigPublicKey*& retPublic) { ElGamalSigPrivateKey* pNewPrivateKey = new ElGamalSigPrivateKey(*mpData->mpRNG, mpData->mKeyBits); ElGamalSigPublicKey* pNewPublicKey = new ElGamalSigPublicKey(*pNewPrivateKey); retPrivate = new cElGamalSigPrivateKey(); retPrivate->mpData->mpKey = pNewPrivateKey; retPrivate->mpData->mKeyLength = (int16)mpData->mKeyBits; retPublic = new cElGamalSigPublicKey(); retPublic->mpData->mpKey = pNewPublicKey; retPublic->mpData->mKeyLength = (int16)mpData->mKeyBits; #ifdef DEBUG int l; l = retPublic->mpData->mpKey->SignatureLength(); ASSERT(l + PLAIN_BLOCK_SIZE <= GetBlockSizeCipher()); l = retPrivate->mpData->mpKey->SignatureLength(); ASSERT(l + PLAIN_BLOCK_SIZE <= GetBlockSizeCipher()); #endif } /////////////////////////////////////////////////////////////////////////////// // class cHashedKey128 -- A 128 bit key based on the hash value of some data cHashedKey128::cHashedKey128(const TSTRING& data) { SHA sha; ASSERT(SHA::DIGESTSIZE >= KEYLEN); sha.CalculateDigest((byte*)mKey, (byte*)data.data(), data.length() * sizeof(TCHAR)); } cHashedKey128::cHashedKey128(void* pData, int dataLen) { SHA sha; ASSERT(SHA::DIGESTSIZE >= KEYLEN); ASSERT(SHA::DIGESTSIZE <= BUFSIZE); sha.CalculateDigest((byte*)mKey, (byte*)pData, dataLen); } cHashedKey128::~cHashedKey128() { RandomizeBytes(mKey, KEYLEN); } /////////////////////////////////////////////////////////////////////////////// // class cHashedKey192 -- A 192 bit key based on the hash value of some data cHashedKey192::cHashedKey192(const TSTRING& data) { SHA sha; ASSERT(SHA::DIGESTSIZE == 20); ASSERT(40 >= KEYLEN); byte localKey[40]; sha.CalculateDigest(localKey, (byte*)data.data(), data.length() * sizeof(TCHAR)); sha.CalculateDigest(localKey + 20, localKey, 20); memcpy(mKey, localKey, KEYLEN); } cHashedKey192::cHashedKey192(void* pData, int dataLen) { SHA sha; ASSERT(SHA::DIGESTSIZE == 20); ASSERT(40 >= KEYLEN); byte localKey[40]; sha.CalculateDigest(localKey, (byte*)pData, dataLen); sha.CalculateDigest(localKey + 20, localKey, 20); memcpy(mKey, localKey, KEYLEN); } cHashedKey192::~cHashedKey192() { RandomizeBytes(mKey, KEYLEN); } /////////////////////////////////////////////////////////////////////////////// // void RandomizeBytes(byte* destbuf, int len) -- Fill a buffer with random bytes static bool gRandomizeBytesSeeded = false; void RandomizeBytes(int8* destbuf, int len) { if (!gRandomizeBytesSeeded) { // generate a rancom number from processor timing. // this should be fairly unpredictable. time_t mask, start = time(NULL); for (mask = 0xb147688c; time(NULL) - start < 1; mask += 0x8984cc88) ; #ifdef DEBUG time_t t = time(NULL); t ^= mask; //time_t t = 920492046 - 3600; // try to the same random values each time //std::cerr << (*(time_t*)mask()) << ":" << t << std::endl; srand( t ); #else srand( time(NULL) ^ mask ); #endif gRandomizeBytesSeeded = true; } int i; for (i = 0; i < len; ++i) destbuf[i] = (byte)( (rand() * 256 / RAND_MAX) ^ 0xdc ); // 0xdc came from random.org }