summaryrefslogtreecommitdiff
path: root/lib/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/CipherAES.cpp163
-rw-r--r--lib/crypto/CipherAES.h50
-rwxr-xr-xlib/crypto/CipherBlowfish.cpp220
-rwxr-xr-xlib/crypto/CipherBlowfish.h60
-rwxr-xr-xlib/crypto/CipherContext.cpp615
-rwxr-xr-xlib/crypto/CipherContext.h83
-rwxr-xr-xlib/crypto/CipherDescription.cpp73
-rwxr-xr-xlib/crypto/CipherDescription.h59
-rwxr-xr-xlib/crypto/CipherException.h17
-rw-r--r--lib/crypto/CipherException.txt18
-rwxr-xr-xlib/crypto/MD5Digest.cpp82
-rwxr-xr-xlib/crypto/MD5Digest.h57
-rwxr-xr-xlib/crypto/Makefile.extra7
-rwxr-xr-xlib/crypto/Random.cpp127
-rwxr-xr-xlib/crypto/Random.h25
-rwxr-xr-xlib/crypto/RollingChecksum.cpp38
-rwxr-xr-xlib/crypto/RollingChecksum.h96
17 files changed, 1790 insertions, 0 deletions
diff --git a/lib/crypto/CipherAES.cpp b/lib/crypto/CipherAES.cpp
new file mode 100644
index 00000000..b4de6048
--- /dev/null
+++ b/lib/crypto/CipherAES.cpp
@@ -0,0 +1,163 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherAES.cpp
+// Purpose: AES cipher description
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+// Only available in new versions of openssl
+#ifndef PLATFORM_OLD_OPENSSL
+
+#include <openssl/evp.h>
+
+#define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+
+#include "CipherAES.h"
+#include "CipherException.h"
+
+#include "MemLeakFindOn.h"
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherAES::CipherAES(CipherDescription::CipherMode, const void *, unsigned int, const void *)
+// Purpose: Constructor -- note key material and IV are not copied. KeyLength in bytes.
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+CipherAES::CipherAES(CipherDescription::CipherMode Mode, const void *pKey, unsigned int KeyLength, const void *pInitialisationVector)
+ : CipherDescription(),
+ mMode(Mode),
+ mpKey(pKey),
+ mKeyLength(KeyLength),
+ mpInitialisationVector(pInitialisationVector)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherAES::CipherAES(const CipherAES &)
+// Purpose: Copy constructor
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+CipherAES::CipherAES(const CipherAES &rToCopy)
+ : CipherDescription(rToCopy),
+ mMode(rToCopy.mMode),
+ mpKey(rToCopy.mpKey),
+ mKeyLength(rToCopy.mKeyLength),
+ mpInitialisationVector(rToCopy.mpInitialisationVector)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ~CipherAES::CipherAES()
+// Purpose: Destructor
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+CipherAES::~CipherAES()
+{
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherAES::operator=(const CipherAES &)
+// Purpose: Assignment operator
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+CipherAES &CipherAES::operator=(const CipherAES &rToCopy)
+{
+ CipherDescription::operator=(rToCopy);
+
+ mMode = rToCopy.mMode;
+ mpKey = rToCopy.mpKey;
+ mKeyLength = rToCopy.mKeyLength;
+ mpInitialisationVector = rToCopy.mpInitialisationVector;
+
+ return *this;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherAES::GetCipher()
+// Purpose: Returns cipher object
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+const EVP_CIPHER *CipherAES::GetCipher() const
+{
+ switch(mMode)
+ {
+ case CipherDescription::Mode_ECB:
+ switch(mKeyLength)
+ {
+ case (128/8): return EVP_aes_128_ecb(); break;
+ case (192/8): return EVP_aes_192_ecb(); break;
+ case (256/8): return EVP_aes_256_ecb(); break;
+ default:
+ THROW_EXCEPTION(CipherException, EVPBadKeyLength)
+ break;
+ }
+ break;
+
+ case CipherDescription::Mode_CBC:
+ switch(mKeyLength)
+ {
+ case (128/8): return EVP_aes_128_cbc(); break;
+ case (192/8): return EVP_aes_192_cbc(); break;
+ case (256/8): return EVP_aes_256_cbc(); break;
+ default:
+ THROW_EXCEPTION(CipherException, EVPBadKeyLength)
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Unknown!
+ THROW_EXCEPTION(CipherException, UnknownCipherMode)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherAES::SetupParameters(EVP_CIPHER_CTX *)
+// Purpose: Set up various parameters for cipher
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+void CipherAES::SetupParameters(EVP_CIPHER_CTX *pCipherContext) const
+{
+ ASSERT(pCipherContext != 0);
+
+ // Set key (key length is implied)
+ if(EVP_CipherInit_ex(pCipherContext, NULL, NULL, (unsigned char*)mpKey, (unsigned char*)mpInitialisationVector, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+}
+
+
+
+#endif // n PLATFORM_OLD_OPENSSL
+
diff --git a/lib/crypto/CipherAES.h b/lib/crypto/CipherAES.h
new file mode 100644
index 00000000..51fb146a
--- /dev/null
+++ b/lib/crypto/CipherAES.h
@@ -0,0 +1,50 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherAES.h
+// Purpose: AES cipher description
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef CIPHERAES__H
+#define CIPHERAES__H
+
+// Only available in new versions of openssl
+#ifndef PLATFORM_OLD_OPENSSL
+
+#include "CipherDescription.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CipherAES
+// Purpose: AES cipher description
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+class CipherAES : public CipherDescription
+{
+public:
+ CipherAES(CipherDescription::CipherMode Mode, const void *pKey, unsigned int KeyLength, const void *pInitialisationVector = 0);
+ CipherAES(const CipherAES &rToCopy);
+ virtual ~CipherAES();
+ CipherAES &operator=(const CipherAES &rToCopy);
+
+ // Return OpenSSL cipher object
+ virtual const EVP_CIPHER *GetCipher() const;
+
+ // Setup any other parameters
+ virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const;
+
+private:
+ CipherDescription::CipherMode mMode;
+ const void *mpKey;
+ unsigned int mKeyLength;
+ const void *mpInitialisationVector;
+};
+
+#endif // n PLATFORM_OLD_OPENSSL
+
+#endif // CIPHERAES__H
+
diff --git a/lib/crypto/CipherBlowfish.cpp b/lib/crypto/CipherBlowfish.cpp
new file mode 100755
index 00000000..e27e3b0a
--- /dev/null
+++ b/lib/crypto/CipherBlowfish.cpp
@@ -0,0 +1,220 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherBlowfish.cpp
+// Purpose: Blowfish cipher description
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <openssl/evp.h>
+
+#ifdef PLATFORM_OLD_OPENSSL
+ #include <string.h>
+ #include <strings.h>
+#endif
+
+#define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+
+#include "CipherBlowfish.h"
+#include "CipherException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherBlowfish::CipherBlowfish(CipherDescription::CipherMode, const void *, unsigned int, const void *)
+// Purpose: Constructor -- note key material and IV are not copied. KeyLength in bytes.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherBlowfish::CipherBlowfish(CipherDescription::CipherMode Mode, const void *pKey, unsigned int KeyLength, const void *pInitialisationVector)
+ : CipherDescription(),
+ mMode(Mode)
+#ifndef PLATFORM_OLD_OPENSSL
+ , mpKey(pKey),
+ mKeyLength(KeyLength),
+ mpInitialisationVector(pInitialisationVector)
+{
+}
+#else
+{
+ mKey.assign((const char *)pKey, KeyLength);
+ if(pInitialisationVector == 0)
+ {
+ bzero(mInitialisationVector, sizeof(mInitialisationVector));
+ }
+ else
+ {
+ ::memcpy(mInitialisationVector, pInitialisationVector, sizeof(mInitialisationVector));
+ }
+}
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherBlowfish::CipherBlowfish(const CipherBlowfish &)
+// Purpose: Copy constructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherBlowfish::CipherBlowfish(const CipherBlowfish &rToCopy)
+ : CipherDescription(rToCopy),
+ mMode(rToCopy.mMode),
+#ifndef PLATFORM_OLD_OPENSSL
+ mpKey(rToCopy.mpKey),
+ mKeyLength(rToCopy.mKeyLength),
+ mpInitialisationVector(rToCopy.mpInitialisationVector)
+{
+}
+#else
+ mKey(rToCopy.mKey)
+{
+ ::memcpy(mInitialisationVector, rToCopy.mInitialisationVector, sizeof(mInitialisationVector));
+}
+#endif
+
+
+#ifdef PLATFORM_OLD_OPENSSL
+// Hack functions to support old OpenSSL API
+CipherDescription *CipherBlowfish::Clone() const
+{
+ return new CipherBlowfish(*this);
+}
+void CipherBlowfish::SetIV(const void *pIV)
+{
+ if(pIV == 0)
+ {
+ bzero(mInitialisationVector, sizeof(mInitialisationVector));
+ }
+ else
+ {
+ ::memcpy(mInitialisationVector, pIV, sizeof(mInitialisationVector));
+ }
+}
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ~CipherBlowfish::CipherBlowfish()
+// Purpose: Destructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherBlowfish::~CipherBlowfish()
+{
+#ifdef PLATFORM_OLD_OPENSSL
+ // Zero copy of key
+ for(unsigned int l = 0; l < mKey.size(); ++l)
+ {
+ mKey[l] = '\0';
+ }
+#endif
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherBlowfish::operator=(const CipherBlowfish &)
+// Purpose: Assignment operator
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherBlowfish &CipherBlowfish::operator=(const CipherBlowfish &rToCopy)
+{
+ CipherDescription::operator=(rToCopy);
+
+ mMode = rToCopy.mMode;
+#ifndef PLATFORM_OLD_OPENSSL
+ mpKey = rToCopy.mpKey;
+ mKeyLength = rToCopy.mKeyLength;
+ mpInitialisationVector = rToCopy.mpInitialisationVector;
+#else
+ mKey = rToCopy.mKey;
+ ::memcpy(mInitialisationVector, rToCopy.mInitialisationVector, sizeof(mInitialisationVector));
+#endif
+
+ return *this;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherBlowfish::GetCipher()
+// Purpose: Returns cipher object
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+const EVP_CIPHER *CipherBlowfish::GetCipher() const
+{
+ switch(mMode)
+ {
+ case CipherDescription::Mode_ECB:
+ return EVP_bf_ecb();
+ break;
+
+ case CipherDescription::Mode_CBC:
+ return EVP_bf_cbc();
+ break;
+
+ case CipherDescription::Mode_CFB:
+ return EVP_bf_cfb();
+ break;
+
+ case CipherDescription::Mode_OFB:
+ return EVP_bf_ofb();
+ break;
+
+ default:
+ break;
+ }
+
+ // Unknown!
+ THROW_EXCEPTION(CipherException, UnknownCipherMode)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherBlowfish::SetupParameters(EVP_CIPHER_CTX *)
+// Purpose: Set up various parameters for cipher
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void CipherBlowfish::SetupParameters(EVP_CIPHER_CTX *pCipherContext) const
+{
+ ASSERT(pCipherContext != 0);
+
+ // Set key length
+#ifndef PLATFORM_OLD_OPENSSL
+ if(EVP_CIPHER_CTX_set_key_length(pCipherContext, mKeyLength) != 1)
+#else
+ if(EVP_CIPHER_CTX_set_key_length(pCipherContext, mKey.size()) != 1)
+#endif
+ {
+ THROW_EXCEPTION(CipherException, EVPBadKeyLength)
+ }
+ // Set key
+#ifndef PLATFORM_OLD_OPENSSL
+ if(EVP_CipherInit_ex(pCipherContext, NULL, NULL, (unsigned char*)mpKey, (unsigned char*)mpInitialisationVector, -1) != 1)
+#else
+ if(EVP_CipherInit(pCipherContext, NULL, (unsigned char*)mKey.c_str(), (unsigned char*)mInitialisationVector, -1) != 1)
+#endif
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+}
+
+
+
diff --git a/lib/crypto/CipherBlowfish.h b/lib/crypto/CipherBlowfish.h
new file mode 100755
index 00000000..92db1d85
--- /dev/null
+++ b/lib/crypto/CipherBlowfish.h
@@ -0,0 +1,60 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherBlowfish.h
+// Purpose: Blowfish cipher description
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef CIPHERBLOWFISH__H
+#define CIPHERBLOWFISH__H
+
+#ifdef PLATFORM_OLD_OPENSSL
+ #include <string>
+#endif
+
+#include "CipherDescription.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CipherBlowfish
+// Purpose: Description of Blowfish cipher parameters -- note that copies are not made of key material and IV, careful with object lifetimes.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+class CipherBlowfish : public CipherDescription
+{
+public:
+ CipherBlowfish(CipherDescription::CipherMode Mode, const void *pKey, unsigned int KeyLength, const void *pInitialisationVector = 0);
+ CipherBlowfish(const CipherBlowfish &rToCopy);
+ virtual ~CipherBlowfish();
+ CipherBlowfish &operator=(const CipherBlowfish &rToCopy);
+
+ // Return OpenSSL cipher object
+ virtual const EVP_CIPHER *GetCipher() const;
+
+ // Setup any other parameters
+ virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const;
+
+#ifdef PLATFORM_OLD_OPENSSL
+ CipherDescription *Clone() const;
+ void SetIV(const void *pIV);
+#endif
+
+private:
+ CipherDescription::CipherMode mMode;
+#ifndef PLATFORM_OLD_OPENSSL
+ const void *mpKey;
+ unsigned int mKeyLength;
+ const void *mpInitialisationVector;
+#else
+ std::string mKey;
+ uint8_t mInitialisationVector[8];
+#endif
+};
+
+
+#endif // CIPHERBLOWFISH__H
+
diff --git a/lib/crypto/CipherContext.cpp b/lib/crypto/CipherContext.cpp
new file mode 100755
index 00000000..42707497
--- /dev/null
+++ b/lib/crypto/CipherContext.cpp
@@ -0,0 +1,615 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherContext.cpp
+// Purpose: Context for symmetric encryption / descryption
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+#include "CipherContext.h"
+#include "CipherDescription.h"
+#include "CipherException.h"
+#include "Random.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::CipherContext()
+// Purpose: Constructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherContext::CipherContext()
+ : mInitialised(false),
+ mWithinTransform(false),
+ mPaddingOn(true)
+#ifdef PLATFORM_OLD_OPENSSL
+ , mFunction(Decrypt),
+ mpDescription(0)
+#endif
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::~CipherContext()
+// Purpose: Destructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherContext::~CipherContext()
+{
+ if(mInitialised)
+ {
+ // Clean up
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ mInitialised = false;
+ }
+#ifdef PLATFORM_OLD_OPENSSL
+ if(mpDescription != 0)
+ {
+ delete mpDescription;
+ mpDescription = 0;
+ }
+#endif
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::Init(CipherContext::CipherFunction, const CipherDescription &)
+// Purpose: Initialises the context, specifying the direction for the encryption, and a
+// description of the cipher to use, it's keys, etc
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void CipherContext::Init(CipherContext::CipherFunction Function, const CipherDescription &rDescription)
+{
+ // Check for bad usage
+ if(mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, AlreadyInitialised)
+ }
+ if(Function != Decrypt && Function != Encrypt)
+ {
+ THROW_EXCEPTION(CipherException, BadArguments)
+ }
+
+ // Initialise the cipher
+#ifndef PLATFORM_OLD_OPENSSL
+ EVP_CIPHER_CTX_init(&ctx); // no error return code, even though the docs says it does
+
+ if(EVP_CipherInit_ex(&ctx, rDescription.GetCipher(), NULL, NULL, NULL, Function) != 1)
+#else
+ // Store function for later
+ mFunction = Function;
+
+ // Use old version of init call
+ if(EVP_CipherInit(&ctx, rDescription.GetCipher(), NULL, NULL, Function) != 1)
+#endif
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+ try
+ {
+#ifndef PLATFORM_OLD_OPENSSL
+ // Let the description set up everything else
+ rDescription.SetupParameters(&ctx);
+#else
+ // With the old version, a copy needs to be taken first.
+ mpDescription = rDescription.Clone();
+ // Mark it as not a leak, otherwise static cipher contexts cause supriously memory leaks to be reported
+ MEMLEAKFINDER_NOT_A_LEAK(mpDescription);
+ mpDescription->SetupParameters(&ctx);
+#endif
+ }
+ catch(...)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ throw;
+ }
+
+ // mark as initialised
+ mInitialised = true;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::Reset()
+// Purpose: Reset the context, so it can be initialised again with a different key
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void CipherContext::Reset()
+{
+ if(mInitialised)
+ {
+ // Clean up
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ mInitialised = false;
+ }
+#ifdef PLATFORM_OLD_OPENSSL
+ if(mpDescription != 0)
+ {
+ delete mpDescription;
+ mpDescription = 0;
+ }
+#endif
+ mWithinTransform = false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::Begin()
+// Purpose: Begin a transformation
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void CipherContext::Begin()
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Warn if in a transformation (not an error, because a context might not have been finalised if an exception occured)
+ if(mWithinTransform)
+ {
+ TRACE0("CipherContext::Begin called when context flagged as within a transform\n");
+ }
+
+ // Initialise the cipher context again
+ if(EVP_CipherInit(&ctx, NULL, NULL, NULL, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+ // Mark as being within a transform
+ mWithinTransform = true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::Transform(void *, int, const void *, int)
+// Purpose: Transforms the data in the in buffer to the out buffer. If pInBuffer == 0 && InLength == 0
+// then Final() is called instead.
+// Returns the number of bytes placed in the out buffer.
+// There must be room in the out buffer for all the data in the in buffer.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::Transform(void *pOutBuffer, int OutLength, const void *pInBuffer, int InLength)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ if(!mWithinTransform)
+ {
+ THROW_EXCEPTION(CipherException, BeginNotCalled)
+ }
+
+ // Check parameters
+ if(pOutBuffer == 0 || OutLength < 0 || (pInBuffer != 0 && InLength <= 0) || (pInBuffer == 0 && InLength != 0))
+ {
+ THROW_EXCEPTION(CipherException, BadArguments)
+ }
+
+ // Is this the final call?
+ if(pInBuffer == 0)
+ {
+ return Final(pOutBuffer, OutLength);
+ }
+
+ // Check output buffer size
+ if(OutLength < (InLength + EVP_CIPHER_CTX_block_size(&ctx)))
+ {
+ THROW_EXCEPTION(CipherException, OutputBufferTooSmall);
+ }
+
+ // Do the transform
+ int outLength = OutLength;
+ if(EVP_CipherUpdate(&ctx, (unsigned char*)pOutBuffer, &outLength, (unsigned char*)pInBuffer, InLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPUpdateFailure)
+ }
+
+ return outLength;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::Final(void *, int)
+// Purpose: Transforms the data as per Transform, and returns the final data in the out buffer.
+// Returns the number of bytes written in the out buffer.
+// Two main causes of exceptions being thrown: 1) Data is corrupt, and so the end isn't
+// padded properly. 2) Padding is off, and the data to be encrypted isn't a multiple
+// of a block long.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::Final(void *pOutBuffer, int OutLength)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ if(!mWithinTransform)
+ {
+ THROW_EXCEPTION(CipherException, BeginNotCalled)
+ }
+
+ // Check parameters
+ if(pOutBuffer == 0 || OutLength < 0)
+ {
+ THROW_EXCEPTION(CipherException, BadArguments)
+ }
+
+ // Check output buffer size
+ if(OutLength < (2 * EVP_CIPHER_CTX_block_size(&ctx)))
+ {
+ THROW_EXCEPTION(CipherException, OutputBufferTooSmall);
+ }
+
+ // Do the transform
+ int outLength = OutLength;
+#ifndef PLATFORM_OLD_OPENSSL
+ if(EVP_CipherFinal_ex(&ctx, (unsigned char*)pOutBuffer, &outLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+#else
+ OldOpenSSLFinal((unsigned char*)pOutBuffer, outLength);
+#endif
+
+ mWithinTransform = false;
+
+ return outLength;
+}
+
+
+#ifdef PLATFORM_OLD_OPENSSL
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::OldOpenSSLFinal(unsigned char *, int &)
+// Purpose: The old version of OpenSSL needs more work doing to finalise the cipher,
+// and reset it so that it's ready for another go.
+// Created: 27/3/04
+//
+// --------------------------------------------------------------------------
+void CipherContext::OldOpenSSLFinal(unsigned char *Buffer, int &rOutLengthOut)
+{
+ // Old version needs to use a different form, and then set up the cipher again for next time around
+ int outLength = rOutLengthOut;
+ // Have to emulate padding off...
+ int blockSize = EVP_CIPHER_CTX_block_size(&ctx);
+ if(mPaddingOn)
+ {
+ // Just use normal final call
+ if(EVP_CipherFinal(&ctx, Buffer, &outLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+ }
+ else
+ {
+ // Padding is off. OpenSSL < 0.9.7 doesn't support this, so it has to be
+ // bodged in there. Which isn't nice.
+ if(mFunction == Decrypt)
+ {
+ // NASTY -- fiddling around with internals like this is bad.
+ // But only way to get this working on old versions of OpenSSL.
+ if(!EVP_EncryptUpdate(&ctx,Buffer,&outLength,ctx.buf,0)
+ || outLength != blockSize)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+ // Clean up
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ }
+ else
+ {
+ // Check that the length is correct
+ if((ctx.buf_len % blockSize) != 0)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+ // For encryption, assume that the last block entirely is
+ // padding, and remove it.
+ char temp[1024];
+ outLength = sizeof(temp);
+ if(EVP_CipherFinal(&ctx, Buffer, &outLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+ // Remove last block, assuming it's full of padded bytes only.
+ outLength -= blockSize;
+ // Copy anything to the main buffer
+ // (can't just use main buffer, because it might overwrite something important)
+ if(outLength > 0)
+ {
+ ::memcpy(Buffer, temp, outLength);
+ }
+ }
+ }
+ // Reinitialise the cipher for the next time around
+ if(EVP_CipherInit(&ctx, mpDescription->GetCipher(), NULL, NULL, mFunction) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+ mpDescription->SetupParameters(&ctx);
+
+ // Update length for caller
+ rOutLengthOut = outLength;
+}
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::InSizeForOutBufferSize(int)
+// Purpose: Returns the maximum amount of data that can be sent in
+// given a output buffer size.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::InSizeForOutBufferSize(int OutLength)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Strictly speaking, the *2 is unnecessary. However...
+ // Final() is paranoid, and requires two input blocks of space to work.
+ return OutLength - (EVP_CIPHER_CTX_block_size(&ctx) * 2);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::MaxOutSizeForInBufferSize(int)
+// Purpose: Returns the maximum output size for an input of a given length.
+// Will tend to over estimate, as it needs to allow space for Final() to be called.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::MaxOutSizeForInBufferSize(int InLength)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Final() is paranoid, and requires two input blocks of space to work, and so we need to add
+ // three blocks on to be absolutely sure.
+ return InLength + (EVP_CIPHER_CTX_block_size(&ctx) * 3);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::TransformBlock(void *, int, const void *, int)
+// Purpose: Transform one block to another all in one go, no Final required.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::TransformBlock(void *pOutBuffer, int OutLength, const void *pInBuffer, int InLength)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Warn if in a transformation
+ if(mWithinTransform)
+ {
+ TRACE0("CipherContext::TransformBlock called when context flagged as within a transform\n");
+ }
+
+ // Check output buffer size
+ if(OutLength < (InLength + EVP_CIPHER_CTX_block_size(&ctx)))
+ {
+ // Check if padding is off, in which case the buffer can be smaller
+ if(!mPaddingOn && OutLength <= InLength)
+ {
+ // This is OK.
+ }
+ else
+ {
+ THROW_EXCEPTION(CipherException, OutputBufferTooSmall);
+ }
+ }
+
+ // Initialise the cipher context again
+ if(EVP_CipherInit(&ctx, NULL, NULL, NULL, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+ // Do the entire block
+ int outLength = 0;
+ try
+ {
+ // Update
+ outLength = OutLength;
+ if(EVP_CipherUpdate(&ctx, (unsigned char*)pOutBuffer, &outLength, (unsigned char*)pInBuffer, InLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPUpdateFailure)
+ }
+ // Finalise
+ int outLength2 = OutLength - outLength;
+#ifndef PLATFORM_OLD_OPENSSL
+ if(EVP_CipherFinal_ex(&ctx, ((unsigned char*)pOutBuffer) + outLength, &outLength2) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+#else
+ OldOpenSSLFinal(((unsigned char*)pOutBuffer) + outLength, outLength2);
+#endif
+ outLength += outLength2;
+ }
+ catch(...)
+ {
+ // Finalise the context, so definately ready for the next caller
+ int outs = OutLength;
+#ifndef PLATFORM_OLD_OPENSSL
+ EVP_CipherFinal_ex(&ctx, (unsigned char*)pOutBuffer, &outs);
+#else
+ OldOpenSSLFinal((unsigned char*)pOutBuffer, outs);
+#endif
+ throw;
+ }
+
+ return outLength;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::GetIVLength()
+// Purpose: Returns the size of the IV for this context
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+int CipherContext::GetIVLength()
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ return EVP_CIPHER_CTX_iv_length(&ctx);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::SetIV(const void *)
+// Purpose: Sets the IV for this context (must be correctly sized, use GetIVLength)
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void CipherContext::SetIV(const void *pIV)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Warn if in a transformation
+ if(mWithinTransform)
+ {
+ TRACE0("CipherContext::SetIV called when context flagged as within a transform\n");
+ }
+
+ // Set IV
+ if(EVP_CipherInit(&ctx, NULL, NULL, (unsigned char *)pIV, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+#ifdef PLATFORM_OLD_OPENSSL
+ // Update description
+ if(mpDescription != 0)
+ {
+ mpDescription->SetIV(pIV);
+ }
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::SetRandomIV(int &)
+// Purpose: Set a random IV for the context, and return a pointer to the IV used,
+// and the length of this IV in the rLengthOut arg.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+const void *CipherContext::SetRandomIV(int &rLengthOut)
+{
+ if(!mInitialised)
+ {
+ THROW_EXCEPTION(CipherException, NotInitialised)
+ }
+
+ // Warn if in a transformation
+ if(mWithinTransform)
+ {
+ TRACE0("CipherContext::SetRandomIV called when context flagged as within a transform\n");
+ }
+
+ // Get length of IV
+ unsigned int ivLen = EVP_CIPHER_CTX_iv_length(&ctx);
+ if(ivLen > sizeof(mGeneratedIV))
+ {
+ THROW_EXCEPTION(CipherException, IVSizeImplementationLimitExceeded)
+ }
+
+ // Generate some random data
+ Random::Generate(mGeneratedIV, ivLen);
+
+ // Set IV
+ if(EVP_CipherInit(&ctx, NULL, NULL, mGeneratedIV, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+#ifdef PLATFORM_OLD_OPENSSL
+ // Update description
+ if(mpDescription != 0)
+ {
+ mpDescription->SetIV(mGeneratedIV);
+ }
+#endif
+
+ // Return the IV and it's length
+ rLengthOut = ivLen;
+ return mGeneratedIV;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherContext::UsePadding(bool)
+// Purpose: Set whether or not the context uses padding.
+// Created: 12/12/03
+//
+// --------------------------------------------------------------------------
+void CipherContext::UsePadding(bool Padding)
+{
+#ifndef PLATFORM_OLD_OPENSSL
+ if(EVP_CIPHER_CTX_set_padding(&ctx, Padding) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPSetPaddingFailure)
+ }
+#endif
+ mPaddingOn = Padding;
+}
+
+
+
diff --git a/lib/crypto/CipherContext.h b/lib/crypto/CipherContext.h
new file mode 100755
index 00000000..f9dcd022
--- /dev/null
+++ b/lib/crypto/CipherContext.h
@@ -0,0 +1,83 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherContext.h
+// Purpose: Context for symmetric encryption / descryption
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef CIPHERCONTEXT__H
+#define CIPHERCONTEXT__H
+
+#ifdef BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_FALSE
+ always include CipherContext.h first in any .cpp file
+#endif
+#define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+#include <openssl/evp.h>
+class CipherDescription;
+
+#define CIPHERCONTEXT_MAX_GENERATED_IV_LENGTH 32
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CipherContext
+// Purpose: Context for symmetric encryption / descryption
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+class CipherContext
+{
+public:
+ CipherContext();
+ ~CipherContext();
+private:
+ CipherContext(const CipherContext &); // no copying
+ CipherContext &operator=(const CipherContext &); // no assignment
+public:
+
+ typedef enum
+ {
+ Decrypt = 0,
+ Encrypt = 1
+ } CipherFunction;
+
+ void Init(CipherContext::CipherFunction Function, const CipherDescription &rDescription);
+ void Reset();
+
+ void Begin();
+ int Transform(void *pOutBuffer, int OutLength, const void *pInBuffer, int InLength);
+ int Final(void *pOutBuffer, int OutLength);
+ int InSizeForOutBufferSize(int OutLength);
+ int MaxOutSizeForInBufferSize(int InLength);
+
+ int TransformBlock(void *pOutBuffer, int OutLength, const void *pInBuffer, int InLength);
+
+ bool IsInitialised() {return mInitialised;}
+
+ int GetIVLength();
+ void SetIV(const void *pIV);
+ const void *SetRandomIV(int &rLengthOut);
+
+ void UsePadding(bool Padding = true);
+
+#ifdef PLATFORM_OLD_OPENSSL
+ void OldOpenSSLFinal(unsigned char *Buffer, int &rOutLengthOut);
+#endif
+
+private:
+ EVP_CIPHER_CTX ctx;
+ bool mInitialised;
+ bool mWithinTransform;
+ bool mPaddingOn;
+ uint8_t mGeneratedIV[CIPHERCONTEXT_MAX_GENERATED_IV_LENGTH];
+#ifdef PLATFORM_OLD_OPENSSL
+ CipherFunction mFunction;
+ CipherDescription *mpDescription;
+#endif
+};
+
+
+#endif // CIPHERCONTEXT__H
+
diff --git a/lib/crypto/CipherDescription.cpp b/lib/crypto/CipherDescription.cpp
new file mode 100755
index 00000000..f0ba6ec8
--- /dev/null
+++ b/lib/crypto/CipherDescription.cpp
@@ -0,0 +1,73 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherDescription.cpp
+// Purpose: Pure virtual base class for describing ciphers
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <openssl/evp.h>
+
+#define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+
+#include "CipherDescription.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherDescription::CipherDescription()
+// Purpose: Constructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherDescription::CipherDescription()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherDescription::CipherDescription(const CipherDescription &)
+// Purpose: Copy constructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherDescription::CipherDescription(const CipherDescription &rToCopy)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ~CipherDescription::CipherDescription()
+// Purpose: Destructor
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherDescription::~CipherDescription()
+{
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CipherDescription::operator=(const CipherDescription &)
+// Purpose: Assignment operator
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+CipherDescription &CipherDescription::operator=(const CipherDescription &rToCopy)
+{
+ return *this;
+}
+
+
diff --git a/lib/crypto/CipherDescription.h b/lib/crypto/CipherDescription.h
new file mode 100755
index 00000000..2977f7da
--- /dev/null
+++ b/lib/crypto/CipherDescription.h
@@ -0,0 +1,59 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherDescription.h
+// Purpose: Pure virtual base class for describing ciphers
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef CIPHERDESCRIPTION__H
+#define CIPHERDESCRIPTION__H
+
+#ifndef BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_TRUE
+ #define BOX_LIB_CRYPTO_OPENSSL_HEADERS_INCLUDED_FALSE
+ class EVP_CIPHER;
+ class EVP_CIPHER_CTX;
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CipherDescription
+// Purpose: Describes a cipher
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+class CipherDescription
+{
+public:
+ CipherDescription();
+ CipherDescription(const CipherDescription &rToCopy);
+ virtual ~CipherDescription();
+ CipherDescription &operator=(const CipherDescription &rToCopy);
+
+ // Return OpenSSL cipher object
+ virtual const EVP_CIPHER *GetCipher() const = 0;
+
+ // Setup any other parameters
+ virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const = 0;
+
+ // Mode parameter for cipher -- used in derived classes
+ typedef enum
+ {
+ Mode_ECB = 0,
+ Mode_CBC = 1,
+ Mode_CFB = 2,
+ Mode_OFB = 3
+ } CipherMode;
+
+#ifdef PLATFORM_OLD_OPENSSL
+ // For the old version of OpenSSL, we need to be able to store cipher descriptions.
+ virtual CipherDescription *Clone() const = 0;
+ // And to be able to store new IVs
+ virtual void SetIV(const void *pIV) = 0;
+#endif
+};
+
+#endif // CIPHERDESCRIPTION__H
+
diff --git a/lib/crypto/CipherException.h b/lib/crypto/CipherException.h
new file mode 100755
index 00000000..b0c9f8cd
--- /dev/null
+++ b/lib/crypto/CipherException.h
@@ -0,0 +1,17 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherException.h
+// Purpose: Exception
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef CIPHEREXCEPTION__H
+#define CIPHEREXCEPTION__H
+
+// Compatibility
+#include "autogen_CipherException.h"
+
+#endif // CIPHEREXCEPTION__H
+
diff --git a/lib/crypto/CipherException.txt b/lib/crypto/CipherException.txt
new file mode 100644
index 00000000..abdbac87
--- /dev/null
+++ b/lib/crypto/CipherException.txt
@@ -0,0 +1,18 @@
+EXCEPTION Cipher 5
+
+Internal 0
+UnknownCipherMode 1
+AlreadyInitialised 2
+BadArguments 3
+EVPInitFailure 4
+EVPUpdateFailure 5
+EVPFinalFailure 6
+NotInitialised 7
+OutputBufferTooSmall 8
+EVPBadKeyLength 9
+BeginNotCalled 10
+IVSizeImplementationLimitExceeded 11
+PseudoRandNotAvailable 12
+EVPSetPaddingFailure 13
+RandomInitFailed 14 Failed to read from random device
+LengthRequestedTooLongForRandomHex 15
diff --git a/lib/crypto/MD5Digest.cpp b/lib/crypto/MD5Digest.cpp
new file mode 100755
index 00000000..58cc90ee
--- /dev/null
+++ b/lib/crypto/MD5Digest.cpp
@@ -0,0 +1,82 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MD5Digest.cpp
+// Purpose: Simple interface for creating MD5 digests
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+
+
+#include "Box.h"
+
+#include "MD5Digest.h"
+
+#include "MemLeakFindOn.h"
+
+
+MD5Digest::MD5Digest()
+{
+ MD5_Init(&md5);
+ for(unsigned int l = 0; l < sizeof(mDigest); ++l)
+ {
+ mDigest[l] = 0;
+ }
+}
+
+MD5Digest::~MD5Digest()
+{
+}
+
+void MD5Digest::Add(const std::string &rString)
+{
+ MD5_Update(&md5, rString.c_str(), rString.size());
+}
+
+void MD5Digest::Add(const void *pData, int Length)
+{
+ MD5_Update(&md5, pData, Length);
+}
+
+void MD5Digest::Finish()
+{
+ MD5_Final(mDigest, &md5);
+}
+
+std::string MD5Digest::DigestAsString()
+{
+ std::string r;
+
+ static const char *hex = "0123456789abcdef";
+
+ for(unsigned int l = 0; l < sizeof(mDigest); ++l)
+ {
+ r += hex[(mDigest[l] & 0xf0) >> 4];
+ r += hex[(mDigest[l] & 0x0f)];
+ }
+
+ return r;
+}
+
+int MD5Digest::CopyDigestTo(uint8_t *to)
+{
+ for(int l = 0; l < MD5_DIGEST_LENGTH; ++l)
+ {
+ to[l] = mDigest[l];
+ }
+
+ return MD5_DIGEST_LENGTH;
+}
+
+
+bool MD5Digest::DigestMatches(uint8_t *pCompareWith) const
+{
+ for(int l = 0; l < MD5_DIGEST_LENGTH; ++l)
+ {
+ if(pCompareWith[l] != mDigest[l])
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/lib/crypto/MD5Digest.h b/lib/crypto/MD5Digest.h
new file mode 100755
index 00000000..1be01ea9
--- /dev/null
+++ b/lib/crypto/MD5Digest.h
@@ -0,0 +1,57 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MD5Digest.h
+// Purpose: Simple interface for creating MD5 digests
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef MD5DIGEST_H
+#define MD5DIGEST_H
+
+#include <openssl/md5.h>
+#include <string>
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MD5Digest
+// Purpose: Simple interface for creating MD5 digests
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+class MD5Digest
+{
+public:
+ MD5Digest();
+ virtual ~MD5Digest();
+
+ void Add(const std::string &rString);
+ void Add(const void *pData, int Length);
+
+ void Finish();
+
+ std::string DigestAsString();
+ uint8_t *DigestAsData(int *pLength = 0)
+ {
+ if(pLength) *pLength = sizeof(mDigest);
+ return mDigest;
+ }
+
+ enum
+ {
+ DigestLength = MD5_DIGEST_LENGTH
+ };
+
+ int CopyDigestTo(uint8_t *to);
+
+ bool DigestMatches(uint8_t *pCompareWith) const;
+
+private:
+ MD5_CTX md5;
+ uint8_t mDigest[MD5_DIGEST_LENGTH];
+};
+
+#endif // MD5DIGEST_H
+
diff --git a/lib/crypto/Makefile.extra b/lib/crypto/Makefile.extra
new file mode 100755
index 00000000..a7e42000
--- /dev/null
+++ b/lib/crypto/Makefile.extra
@@ -0,0 +1,7 @@
+
+MAKEEXCEPTION = ../../lib/common/makeexception.pl
+
+# AUTOGEN SEEDING
+autogen_CipherException.cpp autogen_CipherException.h: $(MAKEEXCEPTION) CipherException.txt
+ perl $(MAKEEXCEPTION) CipherException.txt
+
diff --git a/lib/crypto/Random.cpp b/lib/crypto/Random.cpp
new file mode 100755
index 00000000..3df5fc5e
--- /dev/null
+++ b/lib/crypto/Random.cpp
@@ -0,0 +1,127 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Random.cpp
+// Purpose: Random numbers
+// Created: 31/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <openssl/rand.h>
+#include <stdio.h>
+
+#include "Random.h"
+#include "CipherException.h"
+
+#include "MemLeakFindOn.h"
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Random::Initialise()
+// Purpose: Add additional randomness to the standard library initialisation
+// Created: 18/6/04
+//
+// --------------------------------------------------------------------------
+void Random::Initialise()
+{
+#ifndef PLATFORM_RANDOM_DEVICE_NONE
+ if(::RAND_load_file(PLATFORM_RANDOM_DEVICE, 1024) != 1024)
+ {
+ THROW_EXCEPTION(CipherException, RandomInitFailed)
+ }
+#else
+ ::fprintf(stderr, "No random device -- additional seeding of random number generator not performed.\n");
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Random::Generate(void *, int)
+// Purpose: Generate Length bytes of random data
+// Created: 31/12/03
+//
+// --------------------------------------------------------------------------
+void Random::Generate(void *pOutput, int Length)
+{
+ if(RAND_pseudo_bytes((uint8_t*)pOutput, Length) == -1)
+ {
+ THROW_EXCEPTION(CipherException, PseudoRandNotAvailable)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Random::GenerateHex(int)
+// Purpose: Generate Length bytes of hex encoded data. Note that the
+// maximum length requested is limited. (Returns a string
+// 2 x Length characters long.)
+// Created: 1/11/04
+//
+// --------------------------------------------------------------------------
+std::string Random::GenerateHex(int Length)
+{
+ uint8_t r[256];
+ if(Length > sizeof(r))
+ {
+ THROW_EXCEPTION(CipherException, LengthRequestedTooLongForRandomHex)
+ }
+ Random::Generate(r, Length);
+
+ std::string o;
+ static const char *h = "0123456789abcdef";
+ for(int l = 0; l < Length; ++l)
+ {
+ o += h[r[l] >> 4];
+ o += h[r[l] & 0xf];
+ }
+
+ return o;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Random::RandomInt(int)
+// Purpose: Return a random integer between 0 and MaxValue inclusive.
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+uint32_t Random::RandomInt(uint32_t MaxValue)
+{
+ uint32_t v = 0;
+
+ // Generate a mask
+ uint32_t mask = 0;
+ while(mask < MaxValue)
+ {
+ mask = (mask << 1) | 1;
+ }
+
+ do
+ {
+ // Generate a random number
+ uint32_t r = 0;
+ Random::Generate(&r, sizeof(r));
+
+ // Mask off relevant bits
+ v = r & mask;
+
+ // Check that it's in the right range.
+ } while(v > MaxValue);
+
+ // NOTE: don't do a mod, because this doesn't give a correct random distribution
+
+ return v;
+}
+
+
+
diff --git a/lib/crypto/Random.h b/lib/crypto/Random.h
new file mode 100755
index 00000000..da3e4335
--- /dev/null
+++ b/lib/crypto/Random.h
@@ -0,0 +1,25 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Random.h
+// Purpose: Random numbers
+// Created: 31/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef RANDOM__H
+#define RANDOM__H
+
+#include <string>
+
+namespace Random
+{
+ void Initialise();
+ void Generate(void *pOutput, int Length);
+ std::string GenerateHex(int Length);
+ uint32_t RandomInt(uint32_t MaxValue);
+};
+
+
+#endif // RANDOM__H
+
diff --git a/lib/crypto/RollingChecksum.cpp b/lib/crypto/RollingChecksum.cpp
new file mode 100755
index 00000000..75bad7df
--- /dev/null
+++ b/lib/crypto/RollingChecksum.cpp
@@ -0,0 +1,38 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: RollingChecksum.cpp
+// Purpose: A simple rolling checksum over a block of data
+// Created: 6/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "RollingChecksum.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: RollingChecksum::RollingChecksum(const void *, unsigned int)
+// Purpose: Constructor -- does initial computation of the checksum.
+// Created: 6/12/03
+//
+// --------------------------------------------------------------------------
+RollingChecksum::RollingChecksum(const void *data, unsigned int Length)
+ : a(0),
+ b(0)
+{
+ uint8_t *block = (uint8_t *)data;
+ for(unsigned int x = Length; x >= 1; --x)
+ {
+ a += (*block);
+ b += x * (*block);
+
+ ++block;
+ }
+}
+
+
+
diff --git a/lib/crypto/RollingChecksum.h b/lib/crypto/RollingChecksum.h
new file mode 100755
index 00000000..99d116b9
--- /dev/null
+++ b/lib/crypto/RollingChecksum.h
@@ -0,0 +1,96 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: RollingChecksum.h
+// Purpose: A simple rolling checksum over a block of data
+// Created: 6/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef ROLLINGCHECKSUM__H
+#define ROLLINGCHECKSUM__H
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: RollingChecksum
+// Purpose: A simple rolling checksum over a block of data -- can move the block
+// "forwards" in memory and get the next checksum efficiently.
+//
+// Implementation of http://rsync.samba.org/tech_report/node3.html
+// Created: 6/12/03
+//
+// --------------------------------------------------------------------------
+class RollingChecksum
+{
+public:
+ RollingChecksum(const void *data, unsigned int Length);
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: RollingChecksum::RollForward(uint8_t, uint8_t, unsigned int)
+ // Purpose: Move the checksum forward a block, given the first byte of the current block,
+ // last byte of the next block (it's rolling forward to) and the length of the block.
+ // Created: 6/12/03
+ //
+ // --------------------------------------------------------------------------
+ inline void RollForward(uint8_t StartOfThisBlock, uint8_t LastOfNextBlock, unsigned int Length)
+ {
+ // IMPLEMENTATION NOTE: Everything is implicitly mod 2^16 -- uint16_t's will overflow nicely.
+ a -= StartOfThisBlock;
+ a += LastOfNextBlock;
+ b -= Length * StartOfThisBlock;
+ b += a;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: RollingChecksum::GetChecksum()
+ // Purpose: Returns the checksum
+ // Created: 6/12/03
+ //
+ // --------------------------------------------------------------------------
+ inline uint32_t GetChecksum()
+ {
+ return ((uint32_t)a) | (((uint32_t)b) << 16);
+ }
+
+ // Components, just in case they're handy
+ inline uint16_t GetComponent1() {return a;}
+ inline uint16_t GetComponent2() {return b;}
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: RollingChecksum::GetComponentForHashing()
+ // Purpose: Return the 16 bit component used for hashing and/or quick checks
+ // Created: 6/12/03
+ //
+ // --------------------------------------------------------------------------
+ inline uint16_t GetComponentForHashing()
+ {
+ return b;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: RollingChecksum::ExtractHashingComponent(uint32_t)
+ // Purpose: Static. Given a full checksum, extract the component used in the hashing table.
+ // Created: 14/1/04
+ //
+ // --------------------------------------------------------------------------
+ static inline uint16_t ExtractHashingComponent(uint32_t Checksum)
+ {
+ return Checksum >> 16;
+ }
+
+private:
+ uint16_t a;
+ uint16_t b;
+};
+
+#endif // ROLLINGCHECKSUM__H
+