merge -r 57761:57967 im-email-session-3, removes database load from IM to email session tracking, introduces new format for email return addresses

master
James Cook 2007-02-15 20:24:08 +00:00
parent 4feabe4a9c
commit 12ac04231b
22 changed files with 725 additions and 77 deletions

View File

@ -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;
}

19
indra/llcommon/llbase64.h Normal file
View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1 @@
.A„Ä3ŒLÜE ``òøÝKÛ@¼ûÇ;M[ÚBë·ø„>ËÊC—'

BIN
indra/test/blowfish.2.bin Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
01234567890123456789012345678901234

74
indra/test/blowfish.pl Executable file
View File

@ -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);

View File

@ -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));
}
}