summaryrefslogtreecommitdiff
path: root/indra
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
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')
-rw-r--r--indra/llcommon/llbase64.cpp43
-rw-r--r--indra/llcommon/llbase64.h19
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp1
-rw-r--r--indra/llcommon/llstring.h10
-rw-r--r--indra/llinventory/llinventory.cpp2
-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
-rw-r--r--indra/newview/llstartup.cpp2
-rw-r--r--indra/newview/llviewerprecompiledheaders.h1
-rw-r--r--indra/test/blowfish.1.bin1
-rw-r--r--indra/test/blowfish.2.binbin0 -> 40 bytes
-rw-r--r--indra/test/blowfish.digits.txt1
-rwxr-xr-xindra/test/blowfish.pl74
-rw-r--r--indra/test/llblowfish_tut.cpp125
22 files changed, 725 insertions, 77 deletions
diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp
new file mode 100644
index 0000000000..88e9d960a2
--- /dev/null
+++ b/indra/llcommon/llbase64.cpp
@@ -0,0 +1,43 @@
+/**
+ * @file llbase64.cpp
+ * @brief Wrapper for apr base64 encoding that returns a std::string
+ * @author James Cook
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llbase64.h"
+
+#include <string>
+
+#include "apr-1/apr_base64.h"
+
+
+// static
+std::string LLBase64::encode(const U8* input, size_t input_size)
+{
+ std::string output;
+ if (input
+ && input_size > 0)
+ {
+ // Yes, it returns int.
+ int b64_buffer_length = apr_base64_encode_len(input_size);
+ char* b64_buffer = new char[b64_buffer_length];
+
+ // This is faster than apr_base64_encode() if you know
+ // you're not on an EBCDIC machine. Also, the output is
+ // null terminated, even though the documentation doesn't
+ // specify. See apr_base64.c for details. JC
+ b64_buffer_length = apr_base64_encode_binary(
+ b64_buffer,
+ input,
+ input_size);
+ output.assign(b64_buffer);
+ delete[] b64_buffer;
+ }
+ return output;
+}
+
diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h
new file mode 100644
index 0000000000..6e8b817ba7
--- /dev/null
+++ b/indra/llcommon/llbase64.h
@@ -0,0 +1,19 @@
+/**
+ * @file llbase64.h
+ * @brief Wrapper for apr base64 encoding that returns a std::string
+ * @author James Cook
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLBASE64_H
+#define LLBASE64_h
+
+class LLBase64
+{
+public:
+ static std::string encode(const U8* input, size_t input_size);
+};
+
+#endif
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index c21b8f19a4..796cd9f9f4 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -171,6 +171,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
else
{
// *FIX: memory inefficient.
+ // *TODO: convert to use LLBase64
ostr << pre << "<binary encoding=\"base64\">";
int b64_buffer_length = apr_base64_encode_len(buffer.size());
char* b64_buffer = new char[b64_buffer_length];
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index a381af74d0..6e9ea0b5a0 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -904,7 +904,7 @@ void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T r
//static
template<class T>
-void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab )
+void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
{
llassert( spaces_per_tab >= 0 );
@@ -913,19 +913,19 @@ void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& string, size_
LLStringBase<T> out_str;
// Replace tabs with spaces
- for (size_type i = 0; i < string.length(); i++)
+ for (size_type i = 0; i < str.length(); i++)
{
- if (string[i] == TAB)
+ if (str[i] == TAB)
{
for (size_type j = 0; j < spaces_per_tab; j++)
out_str += SPACE;
}
else
{
- out_str += string[i];
+ out_str += str[i];
}
}
- string = out_str;
+ str = out_str;
}
//static
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 124f22d5cf..2e3db2308f 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -13,7 +13,7 @@
#include "llinventory.h"
#include "lldbstrings.h"
-#include "llcrypto.h"
+#include "llxorcipher.h"
#include "llsd.h"
#include "message.h"
#include <boost/tokenizer.hpp>
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
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 4ff07e9976..7bd6c9ad82 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -25,7 +25,6 @@
#include "audiosettings.h"
#include "llcachename.h"
#include "llviewercontrol.h"
-#include "llcrypto.h"
#include "lldir.h"
#include "lleconomy.h"
#include "llerrorcontrol.h"
@@ -46,6 +45,7 @@
#include "llversion.h"
#include "llvfs.h"
#include "llwindow.h" // for shell_open
+#include "llxorcipher.h" // saved password, MAC address
#include "message.h"
#include "v3math.h"
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index 50b84babd1..e08c040855 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -151,7 +151,6 @@
#include "llcachename.h"
#include "llcallbacklisth.h"
#include "llcircuit.h"
-#include "llcrypto.h"
#include "lldatapacker.h"
#include "lldbstrings.h"
#include "lldispatcher.h"
diff --git a/indra/test/blowfish.1.bin b/indra/test/blowfish.1.bin
new file mode 100644
index 0000000000..61286e45e3
--- /dev/null
+++ b/indra/test/blowfish.1.bin
@@ -0,0 +1 @@
+.A„Ä3ŒLÜE ``òøÝKÛ@¼ûÇ;M[ÚBë·ø„>ËÊC—' \ No newline at end of file
diff --git a/indra/test/blowfish.2.bin b/indra/test/blowfish.2.bin
new file mode 100644
index 0000000000..ef72d96bbf
--- /dev/null
+++ b/indra/test/blowfish.2.bin
Binary files differ
diff --git a/indra/test/blowfish.digits.txt b/indra/test/blowfish.digits.txt
new file mode 100644
index 0000000000..fce1fed943
--- /dev/null
+++ b/indra/test/blowfish.digits.txt
@@ -0,0 +1 @@
+01234567890123456789012345678901234
diff --git a/indra/test/blowfish.pl b/indra/test/blowfish.pl
new file mode 100755
index 0000000000..7940d87aa6
--- /dev/null
+++ b/indra/test/blowfish.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+# *TODO: specify test count here
+use Test::More qw(no_plan);
+
+use Crypt::CBC;
+use MIME::Base64;
+
+my $init_vector = "\x00" x 8;
+# my $key = pack("H*", "ef5a8376eb0c99fe0dafa487d15bec19cae63d1e25fe31d8d92f7ab0398246d70ee733108e47360e16359654571cf5bab6c3375b42cee4fa");
+# my $key = "d263eb8a78034e40";
+ #"8d082918aa369174";
+my $key = "\x00" x 16;
+
+my $cipher = Crypt::CBC->new( { cipher => 'Blowfish',
+ regenerate_key => 0,
+ key => $key,
+ iv => $init_vector,
+ header => 'none',
+ prepend_iv => 0,
+ keysize => 16 } );
+
+#my $blocks = $cipher->blocksize();
+#print "blocksize $blocks\n";
+
+my $len;
+my $input = "01234567890123456789012345678901234\n";
+#my $input = "a whale of a tale I tell you lad, a whale of a tale for me, a whale of a tale and the fiddlers three";
+$len = length($input);
+is ($len, 36, "input length");
+
+$len = length($key);
+is ($len, 16, "key length");
+
+
+my $encrypted = $cipher->encrypt($input);
+is (length($encrypted), 40, "encrypted length");
+
+open(FH, "blowfish.1.bin");
+my $bin = scalar <FH>;
+is ($encrypted, $bin, "matches openssl");
+close(FH);
+
+my $base64 = encode_base64($encrypted);
+is ($base64, "LkGExDOMTNxFIGBg8gP43UvbQLz7xztNWwYF2kLrtwT4hD7LykOXJw==\n",
+ "base64 output");
+
+my $unbase64 = decode_base64($base64);
+is( $encrypted, $unbase64, "reverse base64" );
+
+my $output = $cipher->decrypt($unbase64);
+is ($input, $output, "reverse encrypt");
+
+$key = pack("H[32]", "526a1e07a19dbaed84c4ff08a488d15e");
+$cipher = Crypt::CBC->new( { cipher => 'Blowfish',
+ regenerate_key => 0,
+ key => $key,
+ iv => $init_vector,
+ header => 'none',
+ prepend_iv => 0,
+ keysize => 16 } );
+$encrypted = $cipher->encrypt($input);
+is (length($encrypted), 40, "uuid encrypted length");
+$output = $cipher->decrypt($encrypted);
+is ($input, $output, "uuid reverse encrypt");
+
+open(FH, "blowfish.2.bin");
+$bin = scalar <FH>;
+close(FH);
+is( $encrypted, $bin, "uuid matches openssl" );
+
+print encode_base64($encrypted);
diff --git a/indra/test/llblowfish_tut.cpp b/indra/test/llblowfish_tut.cpp
new file mode 100644
index 0000000000..8f0912d98d
--- /dev/null
+++ b/indra/test/llblowfish_tut.cpp
@@ -0,0 +1,125 @@
+/**
+ * @file llblowfish_tut.cpp
+ * @author James Cook, james@lindenlab.com
+ * @date 2007-02-04
+ *
+ * Data files generated with:
+ * openssl enc -bf-cbc -in blowfish.digits.txt -out blowfish.1.bin -K 00000000000000000000000000000000 -iv 0000000000000000 -p
+ * openssl enc -bf-cbc -in blowfish.digits.txt -out blowfish.2.bin -K 526a1e07a19dbaed84c4ff08a488d15e -iv 0000000000000000 -p
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+#include "lltut.h"
+
+#include "llblowfishcipher.h"
+
+#include <string>
+#include <stdio.h>
+#include "lluuid.h"
+
+namespace tut
+{
+ class LLData
+ {
+ public:
+ unsigned char* mInput;
+ int mInputSize;
+
+ LLData()
+ {
+ // \n to make it easier to create text files
+ // for testing with command line openssl
+ mInput = (unsigned char*)"01234567890123456789012345678901234\n";
+ mInputSize = 36;
+ }
+
+ bool matchFile(const char* filename,
+ const std::string& data)
+ {
+ FILE* fp = fopen(filename, "rb");
+ if (!fp)
+ {
+ // sometimes test is run inside the indra directory
+ std::string path = "test/";
+ path += filename;
+ fp = fopen(path.c_str(), "rb");
+ }
+ if (!fp)
+ {
+ llwarns << "unabled to open " << filename << llendl;
+ return false;
+ }
+
+ std::string good;
+ good.resize(256);
+ size_t got = fread(&good[0], 1, 256, fp);
+ lldebugs << "matchFile read " << got << llendl;
+ fclose(fp);
+ good.resize(got);
+
+ return (good == data);
+ }
+ };
+ typedef test_group<LLData> blowfish_test;
+ typedef blowfish_test::object blowfish_object;
+ // Create test with name that can be selected on
+ // command line of test app.
+ tut::blowfish_test blowfish("blowfish");
+
+ template<> template<>
+ void blowfish_object::test<1>()
+ {
+ LLUUID blank;
+ LLBlowfishCipher cipher(&blank.mData[0], UUID_BYTES);
+
+ U32 dst_len = cipher.requiredEncryptionSpace(36);
+ ensure("encryption space 36",
+ (dst_len == 40) );
+
+ // Blowfish adds an additional 8-byte block if your
+ // input is an exact multiple of 8
+ dst_len = cipher.requiredEncryptionSpace(8);
+ ensure("encryption space 8",
+ (dst_len == 16) );
+ }
+
+ template<> template<>
+ void blowfish_object::test<2>()
+ {
+ LLUUID blank;
+ LLBlowfishCipher cipher(&blank.mData[0], UUID_BYTES);
+
+ std::string result;
+ result.resize(256);
+ U32 count = cipher.encrypt(mInput, mInputSize,
+ (U8*) &result[0], 256);
+
+ ensure("encrypt output count",
+ (count == 40) );
+ result.resize(count);
+
+ ensure("encrypt null key", matchFile("blowfish.1.bin", result));
+ }
+
+ template<> template<>
+ void blowfish_object::test<3>()
+ {
+ // same as base64 test id
+ LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e");
+ LLBlowfishCipher cipher(&id.mData[0], UUID_BYTES);
+
+ std::string result;
+ result.resize(256);
+ U32 count = cipher.encrypt(mInput, mInputSize,
+ (U8*) &result[0], 256);
+
+ ensure("encrypt output count",
+ (count == 40) );
+ result.resize(count);
+
+ ensure("encrypt real key", matchFile("blowfish.2.bin", result));
+ }
+}