summaryrefslogtreecommitdiff
path: root/indra/llmessage
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-02-15 20:24:08 +0000
committerJames Cook <james@lindenlab.com>2007-02-15 20:24:08 +0000
commit12ac04231b8d358e70c830f7958f7efbc0f7c0d1 (patch)
tree189b9bc4e3bfa63275cc41be8dc42a28b0f54ffe /indra/llmessage
parent4feabe4a9caec380cad405d5410bc762c862113d (diff)
merge -r 57761:57967 im-email-session-3, removes database load from IM to email session tracking, introduces new format for email return addresses
Diffstat (limited to 'indra/llmessage')
-rw-r--r--indra/llmessage/llblowfishcipher.cpp135
-rw-r--r--indra/llmessage/llblowfishcipher.h39
-rw-r--r--indra/llmessage/llcipher.h38
-rw-r--r--indra/llmessage/llfiltersd2xmlrpc.cpp1
-rw-r--r--indra/llmessage/llmail.cpp80
-rw-r--r--indra/llmessage/llmail.h119
-rw-r--r--indra/llmessage/llnullcipher.cpp16
-rw-r--r--indra/llmessage/llnullcipher.h30
-rw-r--r--indra/llmessage/llxorcipher.cpp16
-rw-r--r--indra/llmessage/llxorcipher.h49
10 files changed, 454 insertions, 69 deletions
diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp
new file mode 100644
index 0000000000..0255a654df
--- /dev/null
+++ b/indra/llmessage/llblowfishcipher.cpp
@@ -0,0 +1,135 @@
+/**
+ * @file llblowcipher.cpp
+ * @brief Wrapper around OpenSSL Blowfish encryption algorithm.
+ *
+ * We do not have OpenSSL headers or libraries on Windows, so this
+ * class only works on Linux.
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llblowfishcipher.h"
+
+
+LLBlowfishCipher::LLBlowfishCipher(const U8* secret, size_t secret_size)
+: LLCipher()
+{
+ llassert(secret);
+
+ mSecretSize = secret_size;
+ mSecret = new U8[mSecretSize];
+ memcpy(mSecret, secret, mSecretSize);
+}
+
+LLBlowfishCipher::~LLBlowfishCipher()
+{
+ delete [] mSecret;
+ mSecret = NULL;
+}
+
+
+#if LL_LINUX
+
+#include <openssl/evp.h>
+
+// virtual
+U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ if (!src || !src_len || !dst || !dst_len) return 0;
+ if (src_len > dst_len) return 0;
+
+ // OpenSSL uses "cipher contexts" to hold encryption parameters.
+ EVP_CIPHER_CTX context;
+ EVP_CIPHER_CTX_init(&context);
+
+ // We want a blowfish cyclic block chain cipher, but need to set
+ // the key length before we pass in a key, so call EncryptInit
+ // first with NULLs.
+ EVP_EncryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL);
+ EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize);
+
+ // Complete initialization. Per EVP_EncryptInit man page, the
+ // cipher pointer must be NULL. Apparently initial_vector must
+ // be 8 bytes for blowfish, as this is the block size.
+ unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ EVP_EncryptInit_ex(&context, NULL, NULL, mSecret, initial_vector);
+
+ int blocksize = EVP_CIPHER_CTX_block_size(&context);
+ int keylen = EVP_CIPHER_CTX_key_length(&context);
+ int iv_length = EVP_CIPHER_CTX_iv_length(&context);
+ lldebugs << "LLBlowfishCipher blocksize " << blocksize
+ << " keylen " << keylen
+ << " iv_len " << iv_length
+ << llendl;
+
+ int output_len = 0;
+ if (!EVP_EncryptUpdate(&context,
+ dst,
+ &output_len,
+ src,
+ src_len))
+ {
+ llwarns << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << llendl;
+ return 0;
+ }
+
+ // There may be some final data left to encrypt if the input is
+ // not an exact multiple of the block size.
+ int temp_len = 0;
+ if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len))
+ {
+ llwarns << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << llendl;
+ return 0;
+ }
+ output_len += temp_len;
+ return output_len;
+}
+
+// virtual
+U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ llerrs << "LLBlowfishCipher decrypt unsupported" << llendl;
+ return 0;
+}
+
+// virtual
+U32 LLBlowfishCipher::requiredEncryptionSpace(U32 len) const
+{
+ // *HACK: We know blowfish uses an 8 byte block size.
+ // Oddly, sometimes EVP_Encrypt produces an extra block
+ // if the input is an exact multiple of the block size.
+ // So round up.
+ const U32 BLOCK_SIZE = 8;
+ len += BLOCK_SIZE;
+ len -= (len % BLOCK_SIZE);
+ return len;
+}
+
+#else // !LL_LINUX
+
+// virtual
+U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ llerrs << "LLBlowfishCipher only supported on Linux" << llendl;
+ return 0;
+}
+
+// virtual
+U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ llerrs << "LLBlowfishCipher only supported on Linux" << llendl;
+ return 0;
+}
+
+// virtual
+U32 LLBlowfishCipher::requiredEncryptionSpace(U32 len) const
+{
+ llerrs << "LLBlowfishCipher only supported on Linux" << llendl;
+ return 0;
+}
+
+#endif
+
diff --git a/indra/llmessage/llblowfishcipher.h b/indra/llmessage/llblowfishcipher.h
new file mode 100644
index 0000000000..3c5ee1a626
--- /dev/null
+++ b/indra/llmessage/llblowfishcipher.h
@@ -0,0 +1,39 @@
+/**
+ * @file llblowfishcipher.h
+ * @brief A symmetric block cipher, designed in 1993 by Bruce Schneier.
+ * We use it because it has an 8 byte block size, allowing encryption of
+ * two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of
+ * output. AES has a block size of 32 bytes, so this would require 64 bytes.
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLBLOWFISHCIPHER_H
+#define LLBLOWFISHCIPHER_H
+
+#include "llcipher.h"
+
+
+class LLBlowfishCipher : public LLCipher
+{
+public:
+ // Secret may be up to 56 bytes in length per Blowfish spec.
+ LLBlowfishCipher(const U8* secret, size_t secret_size);
+ virtual ~LLBlowfishCipher();
+
+ // See llcipher.h for documentation.
+ /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const;
+
+#ifdef _DEBUG
+ static BOOL testHarness();
+#endif
+
+private:
+ U8* mSecret;
+ size_t mSecretSize;
+};
+
+#endif // LL_LLCRYPTO_H
diff --git a/indra/llmessage/llcipher.h b/indra/llmessage/llcipher.h
new file mode 100644
index 0000000000..3dce949c2e
--- /dev/null
+++ b/indra/llmessage/llcipher.h
@@ -0,0 +1,38 @@
+/**
+ * @file llcipher.h
+ * @brief Abstract base class for encryption ciphers.
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLCIPHER_H
+#define LLCIPHER_H
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLCipher
+//
+// Abstract base class for a cipher object.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLCipher
+{
+public:
+ virtual ~LLCipher() {}
+
+ // encrypt src and place result into dst. returns TRUE if
+ // Returns number of bytes written into dst, or 0 on error.
+ virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
+
+ // decrypt src and place result into dst.
+ // Returns number of bytes written into dst, or 0 on error.
+ virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
+
+ // returns the minimum amount of space required to encrypt for a
+ // unencrypted source buffer of length len.
+ // *NOTE: This is estimated space and you should check the return value
+ // of the encrypt function.
+ virtual U32 requiredEncryptionSpace(U32 src_len) const = 0 ;
+};
+
+#endif
diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp
index 6d5f92e983..5f81471348 100644
--- a/indra/llmessage/llfiltersd2xmlrpc.cpp
+++ b/indra/llmessage/llfiltersd2xmlrpc.cpp
@@ -248,6 +248,7 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
LLSD::Binary buffer = sd.asBinary();
if(!buffer.empty())
{
+ // *TODO: convert to LLBase64
int b64_buffer_length = apr_base64_encode_len(buffer.size());
char* b64_buffer = new char[b64_buffer_length];
b64_buffer_length = apr_base64_encode_binary(
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp
index 4dd550901e..5417976006 100644
--- a/indra/llmessage/llmail.cpp
+++ b/indra/llmessage/llmail.cpp
@@ -8,6 +8,8 @@
#include "linden_common.h"
+#include "llmail.h"
+
// APR on Windows needs full windows headers
#ifdef LL_WINDOWS
# undef WIN32_LEAN_AND_MEAN
@@ -19,14 +21,16 @@
#include <sstream>
#include <boost/regex.hpp>
-#include "llmail.h"
-
#include "apr-1/apr_pools.h"
#include "apr-1/apr_network_io.h"
#include "llapr.h"
+#include "llbase64.h" // IM-to-email address
+#include "llblowfishcipher.h"
#include "llerror.h"
#include "llhost.h"
+#include "llstring.h"
+#include "lluuid.h"
#include "net.h"
//
@@ -86,11 +90,12 @@ void disconnect_smtp()
// Returns TRUE on success.
// message should NOT be SMTP escaped.
-BOOL send_mail(const char* from_name, const char* from_address,
+// static
+BOOL LLMail::send(const char* from_name, const char* from_address,
const char* to_name, const char* to_address,
const char* subject, const char* message)
{
- std::string header = build_smtp_transaction(
+ std::string header = buildSMTPTransaction(
from_name,
from_address,
to_name,
@@ -106,12 +111,13 @@ BOOL send_mail(const char* from_name, const char* from_address,
{
message_str = message;
}
- bool rv = send_mail(header, message_str, to_address, from_address);
+ bool rv = send(header, message_str, to_address, from_address);
if(rv) return TRUE;
return FALSE;
}
-void init_mail(const std::string& hostname, apr_pool_t* pool)
+// static
+void LLMail::init(const std::string& hostname, apr_pool_t* pool)
{
gMailSocket = NULL;
if(hostname.empty() || !pool)
@@ -138,12 +144,14 @@ void init_mail(const std::string& hostname, apr_pool_t* pool)
}
}
-void enable_mail(bool mail_enabled)
+// static
+void LLMail::enable(bool mail_enabled)
{
gMailEnabled = mail_enabled;
}
-std::string build_smtp_transaction(
+// static
+std::string LLMail::buildSMTPTransaction(
const char* from_name,
const char* from_address,
const char* to_name,
@@ -197,7 +205,8 @@ std::string build_smtp_transaction(
return header.str();
}
-bool send_mail(
+// static
+bool LLMail::send(
const std::string& header,
const std::string& message,
const char* from_address,
@@ -290,3 +299,56 @@ bool send_mail(
#endif
return true;
}
+
+
+// static
+std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id,
+ const LLUUID& to_agent_id,
+ U32 time,
+ const U8* secret,
+ size_t secret_size)
+{
+ size_t data_size = 4 + UUID_BYTES + UUID_BYTES;
+ // Convert input data into a binary blob
+ std::vector<U8> data;
+ data.resize(data_size);
+ // *NOTE: This may suffer from endian issues. Could be htonmemcpy.
+ memcpy(&data[0], &time, 4);
+ memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES);
+ memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES);
+
+ // Encrypt the blob
+ LLBlowfishCipher cipher(secret, secret_size);
+ size_t encrypted_size = cipher.requiredEncryptionSpace(data.size());
+ U8* encrypted = new U8[encrypted_size];
+ cipher.encrypt(&data[0], data_size, encrypted, encrypted_size);
+
+ // Base64 encoded and replace the pieces of base64 that are less compatible
+ // with e-mail local-parts.
+ // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
+ std::string address = LLBase64::encode(encrypted, encrypted_size);
+ LLString::replaceChar(address, '+', '-');
+ LLString::replaceChar(address, '/', '_');
+
+ // Strip padding = signs, see RFC
+ size_t extra_bytes = encrypted_size % 3;
+ size_t padding_size = 0;
+ if (extra_bytes == 0)
+ {
+ padding_size = 0;
+ }
+ else if (extra_bytes == 1)
+ {
+ padding_size = 2;
+ }
+ else if (extra_bytes == 2)
+ {
+ padding_size = 1;
+ }
+
+ address.resize(address.size() - padding_size);
+
+ delete [] encrypted;
+
+ return address;
+}
diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h
index af02264776..dc642b96d5 100644
--- a/indra/llmessage/llmail.h
+++ b/indra/llmessage/llmail.h
@@ -11,55 +11,84 @@
typedef struct apr_pool_t apr_pool_t;
-// if hostname is NULL, then the host is resolved as 'mail'
-void init_mail(const std::string& hostname, apr_pool_t* pool);
+class LLUUID;
-// Allow all email transmission to be disabled/enabled.
-void enable_mail(bool mail_enabled);
+class LLMail
+{
+public:
+ // if hostname is NULL, then the host is resolved as 'mail'
+ static void init(const std::string& hostname, apr_pool_t* pool);
-// returns TRUE if the call succeeds, FALSE otherwise.
-//
-// Results in:
-// From: "from_name" <from_address>
-// To: "to_name" <to_address>
-// Subject: subject
-// message
-BOOL send_mail(const char* from_name, const char* from_address,
- const char* to_name, const char* to_address,
- const char* subject, const char* message);
+ // Allow all email transmission to be disabled/enabled.
+ static void enable(bool mail_enabled);
-/**
- * @brief build the complete smtp transaction & header for use in an
- * mail.
- *
- * @param from_name The name of the email sender
- * @param from_address The email address for the sender
- * @param to_name The name of the email recipient
- * @param to_name The email recipient address
- * @param subject The subject of the email
- * @return Returns the complete SMTP transaction mail header.
- */
-std::string build_smtp_transaction(
- const char* from_name,
- const char* from_address,
- const char* to_name,
- const char* to_address,
- const char* subject);
+ // returns TRUE if the call succeeds, FALSE otherwise.
+ //
+ // Results in:
+ // From: "from_name" <from_address>
+ // To: "to_name" <to_address>
+ // Subject: subject
+ // message
+ static BOOL send(const char* from_name, const char* from_address,
+ const char* to_name, const char* to_address,
+ const char* subject, const char* message);
-/**
- * @brief send an email with header and body.
- *
- * @param header The email header. Use build_mail_header().
- * @param message The unescaped email message.
- * @param from_address Used for debugging
- * @param to_address Used for debugging
- * @return Returns true if the message could be sent.
- */
-bool send_mail(
- const std::string& header,
- const std::string& message,
- const char* from_address,
- const char* to_address);
+ /**
+ * @brief build the complete smtp transaction & header for use in an
+ * mail.
+ *
+ * @param from_name The name of the email sender
+ * @param from_address The email address for the sender
+ * @param to_name The name of the email recipient
+ * @param to_name The email recipient address
+ * @param subject The subject of the email
+ * @return Returns the complete SMTP transaction mail header.
+ */
+ static std::string buildSMTPTransaction(
+ const char* from_name,
+ const char* from_address,
+ const char* to_name,
+ const char* to_address,
+ const char* subject);
+
+ /**
+ * @brief send an email with header and body.
+ *
+ * @param header The email header. Use build_mail_header().
+ * @param message The unescaped email message.
+ * @param from_address Used for debugging
+ * @param to_address Used for debugging
+ * @return Returns true if the message could be sent.
+ */
+ static bool send(
+ const std::string& header,
+ const std::string& message,
+ const char* from_address,
+ const char* to_address);
+
+ // IM-to-email sessions use a "session id" based on an encrypted
+ // combination of from agent_id, to agent_id, and timestamp. When
+ // a user replies to an email we use the from_id to determine the
+ // sender's name and the to_id to route the message. The address
+ // is encrypted to prevent users from building addresses to spoof
+ // IMs from other users. The timestamps allow the "sessions" to
+ // expire, in case one of the sessions is stolen/hijacked.
+ //
+ // indra/tools/mailglue is responsible for parsing the inbound mail.
+ //
+ // secret: binary blob passed to blowfish, max length 56 bytes
+ // secret_size: length of blob, in bytes
+ //
+ // Returns: "base64" encoded email local-part, with _ and - as the
+ // non-alphanumeric characters. This allows better compatibility
+ // with email systems than the default / and + extra chars. JC
+ static std::string encryptIMEmailAddress(
+ const LLUUID& from_agent_id,
+ const LLUUID& to_agent_id,
+ U32 time,
+ const U8* secret,
+ size_t secret_size);
+};
extern const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE;
diff --git a/indra/llmessage/llnullcipher.cpp b/indra/llmessage/llnullcipher.cpp
index 53bb748415..0d28b5c393 100644
--- a/indra/llmessage/llnullcipher.cpp
+++ b/indra/llmessage/llnullcipher.cpp
@@ -8,33 +8,33 @@
#include "linden_common.h"
-#include "llcrypto.h"
+#include "llnullcipher.h"
///----------------------------------------------------------------------------
/// Class LLNullCipher
///----------------------------------------------------------------------------
-BOOL LLNullCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+U32 LLNullCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
if((src_len == dst_len) && src && dst)
{
memmove(dst, src, src_len);
- return TRUE;
+ return src_len;
}
- return FALSE;
+ return 0;
}
-BOOL LLNullCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+U32 LLNullCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
if((src_len == dst_len) && src && dst)
{
memmove(dst, src, src_len);
- return TRUE;
+ return src_len;
}
- return FALSE;
+ return 0;
}
-U32 LLNullCipher::requiredEncryptionSpace(U32 len)
+U32 LLNullCipher::requiredEncryptionSpace(U32 len) const
{
return len;
}
diff --git a/indra/llmessage/llnullcipher.h b/indra/llmessage/llnullcipher.h
new file mode 100644
index 0000000000..bc8c2f2fa3
--- /dev/null
+++ b/indra/llmessage/llnullcipher.h
@@ -0,0 +1,30 @@
+/**
+ * @file llnullcipher.h
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLNULLCIPHER_H
+#define LLNULLCIPHER_H
+
+#include "llcipher.h"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLNullCipher
+//
+// A class which implements LLCipher, but does not transform src
+// during encryption.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLNullCipher : public LLCipher
+{
+public:
+ LLNullCipher() {}
+ virtual ~LLNullCipher() {}
+ virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ virtual U32 requiredEncryptionSpace(U32 src_len) const;
+};
+
+#endif
diff --git a/indra/llmessage/llxorcipher.cpp b/indra/llmessage/llxorcipher.cpp
index 1fbbfec9e0..9ddcf091b2 100644
--- a/indra/llmessage/llxorcipher.cpp
+++ b/indra/llmessage/llxorcipher.cpp
@@ -8,7 +8,8 @@
#include "linden_common.h"
-#include "llcrypto.h"
+#include "llxorcipher.h"
+
#include "llerror.h"
///----------------------------------------------------------------------------
@@ -44,25 +45,26 @@ LLXORCipher& LLXORCipher::operator=(const LLXORCipher& cipher)
return *this;
}
-BOOL LLXORCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+U32 LLXORCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
- if(!src || !src_len || !dst || !dst_len || !mPad) return FALSE;
+ if(!src || !src_len || !dst || !dst_len || !mPad) return 0;
U8* pad_end = mPad + mPadLen;
- while(src_len--)
+ U32 count = src_len;
+ while(count--)
{
*dst++ = *src++ ^ *mHead++;
if(mHead >= pad_end) mHead = mPad;
}
- return TRUE;
+ return src_len;
}
-BOOL LLXORCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+U32 LLXORCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
// xor is a symetric cipher, thus, just call the other function.
return encrypt(src, src_len, dst, dst_len);
}
-U32 LLXORCipher::requiredEncryptionSpace(U32 len)
+U32 LLXORCipher::requiredEncryptionSpace(U32 len) const
{
return len;
}
diff --git a/indra/llmessage/llxorcipher.h b/indra/llmessage/llxorcipher.h
new file mode 100644
index 0000000000..1f0f58f62f
--- /dev/null
+++ b/indra/llmessage/llxorcipher.h
@@ -0,0 +1,49 @@
+/**
+ * @file llxorcipher.h
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLXORCIPHER_H
+#define LLXORCIPHER_H
+
+#include "llcipher.h"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLXORCipher
+//
+// Implementation of LLCipher which encrypts using a XOR pad.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLXORCipher : public LLCipher
+{
+public:
+ LLXORCipher(const U8* pad, U32 pad_len);
+ LLXORCipher(const LLXORCipher& cipher);
+ virtual ~LLXORCipher();
+ LLXORCipher& operator=(const LLXORCipher& cipher);
+
+ // Cipher functions
+ /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const;
+
+ // special syntactic-sugar since xor can be performed in place.
+ BOOL encrypt(U8* buf, U32 len) { return encrypt((const U8*)buf, len, buf, len); }
+ BOOL decrypt(U8* buf, U32 len) { return decrypt((const U8*)buf, len, buf, len); }
+
+#ifdef _DEBUG
+ // This function runs tests to make sure the crc is
+ // working. Returns TRUE if it is.
+ static BOOL testHarness();
+#endif
+
+protected:
+ void init(const U8* pad, U32 pad_len);
+ U8* mPad;
+ U8* mHead;
+ U32 mPadLen;
+};
+
+#endif