tripwire-open-source/src/twtest/crypto_t.cpp

423 lines
13 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2021 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-t.cpp -- generic crypto implementations
//
#include "twcrypto/stdtwcrypto.h"
#include "twcrypto/crypto.h"
#include "core/archive.h"
#include "twtest/test.h"
void TestCrypto()
{
const int COUNT = 4000;
const int BUFFER_SIZE = 9000;
std::vector<char> source_buf(BUFFER_SIZE);
std::vector<char> crypt_buf(COUNT + BUFFER_SIZE); // needs to be able to hold even number of blocks
std::vector<char> dest_buf(COUNT);
char* source = &source_buf[0];
char* crypt = &crypt_buf[0];
char* dest = &dest_buf[0];
memcpy(source, "I love the smell of the sheep.", 31);
#ifdef _IDEA_ENCRYPTION
///////////////////////////////////////////////////////////////////////////
// IDEA test
{
memset(crypt, 0, COUNT + 1024);
memset(dest, 0, COUNT);
cIDEA crypter;
// we use buf for when the end of the source doesn't fall on a
// blocksize boundry.
TEST(crypter.GetBlockSizePlain() < 32);
TEST(crypter.GetBlockSizeCipher() < 32);
char buf[32];
// encrypt the phrase
crypter.SetKey(iCipher::ENCRYPT, cHashedKey128(_T("big cow")));
int i, j;
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
memcpy(buf, source + i, COUNT - i);
memset(buf + COUNT - i, 0, crypter.GetBlockSizePlain() - COUNT + i);
crypter.ProcessBlock(buf, crypt + j);
break;
}
crypter.ProcessBlock(source + i, crypt + j);
}
// dycrypt the phrase
crypter.SetKey(iCipher::DECRYPT, cHashedKey128(_T("big cow")));
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
}
#endif
#ifdef _RSA_ENCRYPTION
///////////////////////////////////////////////////////////////////////////
// RSA test
{
int i, j;
memset(crypt, 0, COUNT + 1024);
memset(dest, 0, COUNT);
cRSA crypter(cRSA::KEY2048);
// we use buf for when the end of the source doesn't fall on a
// blocksize boundry.
TEST(crypter.GetBlockSizePlain() < BUFFER_SIZE);
TEST(crypter.GetBlockSizeCipher() < BUFFER_SIZE);
char buf[BUFFER_SIZE];
cRSAPublicKey* pPublic;
cRSAPrivateKey* pPrivate;
crypter.GenerateKeys(pPrivate, pPublic);
// save the keys to a data stream and read back in
cRSAPublicKey* pPublic2;
cRSAPrivateKey* pPrivate2;
TEST(pPublic->GetWriteLen() < BUFFER_SIZE);
pPublic->Write(buf);
pPublic2 = new cRSAPublicKey(buf);
TEST(pPrivate->GetWriteLen() < BUFFER_SIZE);
pPrivate->Write(buf);
pPrivate2 = new cRSAPrivateKey(buf);
// we will try encrypting to a second pair of buffers and see if all goes well
char crypt2[COUNT + BUFFER_SIZE];
char dest2[COUNT];
// encrypt the phrase
crypter.SetEncrypting(pPublic);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
memcpy(buf, source + i, COUNT - i);
memset(buf + COUNT - i, 0, crypter.GetBlockSizePlain() - COUNT + i);
crypter.ProcessBlock(buf, crypt + j);
break;
}
crypter.ProcessBlock(source + i, crypt + j);
}
crypter.SetEncrypting(pPublic2);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
memcpy(buf, source + i, COUNT - i);
memset(buf + COUNT - i, 0, crypter.GetBlockSizePlain() - COUNT + i);
crypter.ProcessBlock(buf, crypt2 + j);
break;
}
crypter.ProcessBlock(source + i, crypt2 + j);
}
// You might think this test would be valid (I did), but it is not.
// The Crypto++ lib pads input with random bytes so encrypting the
// same plaintext twice will not create the same ciphertext.
//TEST(memcmp(crypt, crypt2, crypter.GetBlockSizeCipher()) == 0);
// dycrypt the phrase
crypter.SetDecrypting(pPrivate);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
crypter.SetDecrypting(pPrivate2);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt2 + j, buf);
memcpy(dest2 + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt2 + j, dest2 + i);
}
TEST(memcmp(source, dest2, COUNT) == 0);
TEST(memcmp(dest, dest2, COUNT) == 0);
// zero out things and try signing and verifying
memset(crypt, 0, COUNT + 1024);
memset(dest, 0, COUNT);
// sign the phrase
crypter.SetSigning(pPrivate);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
memcpy(buf, source + i, COUNT - i);
memset(buf + COUNT - i, 0, crypter.GetBlockSizePlain() - COUNT + i);
crypter.ProcessBlock(buf, crypt + j);
break;
}
crypter.ProcessBlock(source + i, crypt + j);
}
// verify the phrase
crypter.SetVerifying(pPublic);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
// verify the phrase again using a local public key
cRSAPublicKey publicKey(*pPrivate);
crypter.SetVerifying(&publicKey);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
delete pPublic;
delete pPrivate;
}
#endif
///////////////////////////////////////////////////////////////////////////
// El Gamal test
{
int i, j;
TCOUT << _T("El Gamal test\n");
memset(crypt, 0, COUNT + 1024);
memset(dest, 0, COUNT);
cElGamalSig crypter(cElGamalSig::KEY512);
// we use buf for when the end of the source doesn't fall on a
// blocksize boundry.
TEST(crypter.GetBlockSizePlain() < BUFFER_SIZE);
TEST(crypter.GetBlockSizeCipher() < BUFFER_SIZE);
char buf[BUFFER_SIZE];
cElGamalSigPublicKey* pPublic;
cElGamalSigPrivateKey* pPrivate;
crypter.GenerateKeys(pPrivate, pPublic);
// save the keys to a data stream and read back in
cElGamalSigPublicKey* pPublic2;
cElGamalSigPrivateKey* pPrivate2;
TEST(pPublic->GetWriteLen() < BUFFER_SIZE);
pPublic->Write(buf);
pPublic2 = new cElGamalSigPublicKey(buf);
TEST(pPrivate->GetWriteLen() < BUFFER_SIZE);
pPrivate->Write(buf);
pPrivate2 = new cElGamalSigPrivateKey(buf);
// we will try encrypting to a second pair of buffers and see if all goes well
//char crypt2[COUNT + BUFFER_SIZE];
//char dest2[COUNT];
// zero out things and try signing and verifying
memset(crypt, 0, COUNT + 1024);
memset(dest, 0, COUNT);
TCOUT << _T("El Gamal Signing...\n");
// sign the phrase
crypter.SetSigning(pPrivate);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
memcpy(buf, source + i, COUNT - i);
memset(buf + COUNT - i, 0, crypter.GetBlockSizePlain() - COUNT + i);
crypter.ProcessBlock(buf, crypt + j);
break;
}
crypter.ProcessBlock(source + i, crypt + j);
}
TCOUT << _T("El Gamal Verifying...\n");
// verify the phrase
crypter.SetVerifying(pPublic);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
TCOUT << _T("El Gamal Verifying with serialized key...\n");
// verify the phrase again using a local public key
cElGamalSigPublicKey publicKey(*pPrivate);
crypter.SetVerifying(&publicKey);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
TCOUT << _T("El Gamal Testing altered buffer...\n");
try
{
crypt[4] = '\x42';
// verify the phrase again using a local public key
cElGamalSigPublicKey publicKey(*pPrivate);
crypter.SetVerifying(&publicKey);
for (i = 0, j = 0;; i += crypter.GetBlockSizePlain(), j += crypter.GetBlockSizeCipher())
{
if (i + crypter.GetBlockSizePlain() > COUNT)
{
crypter.ProcessBlock(crypt + j, buf);
memcpy(dest + i, buf, COUNT - i);
break;
}
crypter.ProcessBlock(crypt + j, dest + i);
}
TEST(memcmp(source, dest, COUNT) == 0);
}
catch (eArchiveCrypto&)
{
// accept eArchiveCrypto
}
catch (eArchive&)
{
TCOUT << _T("Modified Buffer Test failed!\n");
TEST(false);
}
delete pPublic;
delete pPrivate;
delete pPublic2;
delete pPrivate2;
}
}
void RegisterSuite_Crypto()
{
RegisterTest("Crypto", "Basic", TestCrypto);
}