mirror of
https://github.com/FirestormViewer/phoenix-firestorm.git
synced 2026-08-14 08:53:53 +00:00
#5078 Remove dead llblowfish and llmail code plus related tests
Signed-off-by: Rye <rye@alchemyviewer.org>
This commit is contained in:
@@ -15,7 +15,6 @@ set(llmessage_SOURCE_FILES
|
||||
llassetstorage.cpp
|
||||
llavatarname.cpp
|
||||
llavatarnamecache.cpp
|
||||
llblowfishcipher.cpp
|
||||
llbuffer.cpp
|
||||
llbufferstream.cpp
|
||||
llcachename.cpp
|
||||
@@ -37,7 +36,6 @@ set(llmessage_SOURCE_FILES
|
||||
lliopipe.cpp
|
||||
lliosocket.cpp
|
||||
llioutil.cpp
|
||||
llmail.cpp
|
||||
llmessagebuilder.cpp
|
||||
llmessageconfig.cpp
|
||||
llmessagereader.cpp
|
||||
@@ -94,7 +92,6 @@ set(llmessage_HEADER_FILES
|
||||
llassetstorage.h
|
||||
llavatarname.h
|
||||
llavatarnamecache.h
|
||||
llblowfishcipher.h
|
||||
llbuffer.h
|
||||
llbufferstream.h
|
||||
llcachename.h
|
||||
@@ -124,7 +121,6 @@ set(llmessage_HEADER_FILES
|
||||
lliosocket.h
|
||||
llioutil.h
|
||||
llloginflags.h
|
||||
llmail.h
|
||||
llmessagebuilder.h
|
||||
llmessageconfig.h
|
||||
llmessagereader.h
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/**
|
||||
* @file llblowfishcipher.cpp
|
||||
* @brief Wrapper around OpenSSL Blowfish encryption algorithm.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llblowfishcipher.h"
|
||||
#include <openssl/evp.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;
|
||||
}
|
||||
|
||||
// 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_new();
|
||||
if (!context)
|
||||
{
|
||||
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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);
|
||||
LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
|
||||
<< " keylen " << keylen
|
||||
<< " iv_len " << iv_length
|
||||
<< LL_ENDL;
|
||||
|
||||
int output_len = 0;
|
||||
int temp_len = 0;
|
||||
if (!EVP_EncryptUpdate(context,
|
||||
dst,
|
||||
&output_len,
|
||||
src,
|
||||
src_len))
|
||||
{
|
||||
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL;
|
||||
goto BF_ENCRYPT_ERROR;
|
||||
}
|
||||
|
||||
// There may be some final data left to encrypt if the input is
|
||||
// not an exact multiple of the block size.
|
||||
if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len))
|
||||
{
|
||||
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL;
|
||||
goto BF_ENCRYPT_ERROR;
|
||||
}
|
||||
output_len += temp_len;
|
||||
|
||||
EVP_CIPHER_CTX_free(context);
|
||||
return output_len;
|
||||
|
||||
BF_ENCRYPT_ERROR:
|
||||
EVP_CIPHER_CTX_free(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual
|
||||
U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
|
||||
{
|
||||
LL_ERRS() << "LLBlowfishCipher decrypt unsupported" << LL_ENDL;
|
||||
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;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -1,395 +0,0 @@
|
||||
/**
|
||||
* @file llmail.cpp
|
||||
* @brief smtp helper functions.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmail.h"
|
||||
|
||||
#include "llwin32headers.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "apr_pools.h"
|
||||
#include "apr_network_io.h"
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llbase32.h" // IM-to-email address
|
||||
#include "llblowfishcipher.h"
|
||||
#include "llerror.h"
|
||||
#include "llhost.h"
|
||||
#include "llsd.h"
|
||||
#include "llstring.h"
|
||||
#include "lluuid.h"
|
||||
#include "net.h"
|
||||
|
||||
//
|
||||
// constants
|
||||
//
|
||||
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
|
||||
|
||||
static bool gMailEnabled = true;
|
||||
static apr_pool_t* gMailPool;
|
||||
static apr_sockaddr_t* gSockAddr;
|
||||
static apr_socket_t* gMailSocket;
|
||||
|
||||
bool connect_smtp();
|
||||
void disconnect_smtp();
|
||||
|
||||
//#if LL_WINDOWS
|
||||
//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr;
|
||||
//#else
|
||||
//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr;
|
||||
//#endif
|
||||
|
||||
// Define this for a super-spammy mail mode.
|
||||
//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1
|
||||
|
||||
bool connect_smtp()
|
||||
{
|
||||
// Prepare an soket to talk smtp
|
||||
apr_status_t status;
|
||||
status = apr_socket_create(
|
||||
&gMailSocket,
|
||||
gSockAddr->sa.sin.sin_family,
|
||||
SOCK_STREAM,
|
||||
APR_PROTO_TCP,
|
||||
gMailPool);
|
||||
if(ll_apr_warn_status(status)) return false;
|
||||
status = apr_socket_connect(gMailSocket, gSockAddr);
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
status = apr_socket_close(gMailSocket);
|
||||
ll_apr_warn_status(status);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void disconnect_smtp()
|
||||
{
|
||||
if(gMailSocket)
|
||||
{
|
||||
apr_status_t status = apr_socket_close(gMailSocket);
|
||||
ll_apr_warn_status(status);
|
||||
gMailSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true on success.
|
||||
// message should NOT be SMTP escaped.
|
||||
// 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,
|
||||
const LLSD& headers)
|
||||
{
|
||||
std::string header = buildSMTPTransaction(
|
||||
from_name,
|
||||
from_address,
|
||||
to_name,
|
||||
to_address,
|
||||
subject,
|
||||
headers);
|
||||
if(header.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string message_str;
|
||||
if(message)
|
||||
{
|
||||
message_str = message;
|
||||
}
|
||||
bool rv = send(header, message_str, to_address, from_address);
|
||||
if(rv) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLMail::init(const std::string& hostname, apr_pool_t* pool)
|
||||
{
|
||||
gMailSocket = NULL;
|
||||
if(hostname.empty() || !pool)
|
||||
{
|
||||
gMailPool = NULL;
|
||||
gSockAddr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
gMailPool = pool;
|
||||
|
||||
// collect all the information into a socaddr sturcture. the
|
||||
// documentation is a bit unclear, but I either have to
|
||||
// specify APR_UNSPEC or not specify any flags. I am not sure
|
||||
// which option is better.
|
||||
apr_status_t status = apr_sockaddr_info_get(
|
||||
&gSockAddr,
|
||||
hostname.c_str(),
|
||||
APR_UNSPEC,
|
||||
25,
|
||||
APR_IPV4_ADDR_OK,
|
||||
gMailPool);
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLMail::enable(bool mail_enabled)
|
||||
{
|
||||
gMailEnabled = mail_enabled;
|
||||
}
|
||||
|
||||
// Test a subject line for RFC2822 compliance.
|
||||
static bool valid_subject_chars(const char *subject)
|
||||
{
|
||||
for (; *subject != '\0'; subject++)
|
||||
{
|
||||
unsigned char c = *subject;
|
||||
|
||||
if (c == '\xa' || c == '\xd' || c > '\x7f')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLMail::buildSMTPTransaction(
|
||||
const char* from_name,
|
||||
const char* from_address,
|
||||
const char* to_name,
|
||||
const char* to_address,
|
||||
const char* subject,
|
||||
const LLSD& headers)
|
||||
{
|
||||
if(!from_address || !to_address)
|
||||
{
|
||||
LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or"
|
||||
<< " from address." << LL_ENDL;
|
||||
return std::string();
|
||||
}
|
||||
if(!valid_subject_chars(subject))
|
||||
{
|
||||
LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: "
|
||||
<< "to=<" << to_address
|
||||
<< ">, from=<" << from_address << ">"
|
||||
<< LL_ENDL;
|
||||
return std::string();
|
||||
}
|
||||
std::ostringstream from_fmt;
|
||||
if(from_name && from_name[0])
|
||||
{
|
||||
// "My Name" <myaddress@example.com>
|
||||
from_fmt << "\"" << from_name << "\" <" << from_address << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
// <myaddress@example.com>
|
||||
from_fmt << "<" << from_address << ">";
|
||||
}
|
||||
std::ostringstream to_fmt;
|
||||
if(to_name && to_name[0])
|
||||
{
|
||||
to_fmt << "\"" << to_name << "\" <" << to_address << ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
to_fmt << "<" << to_address << ">";
|
||||
}
|
||||
std::ostringstream header;
|
||||
header
|
||||
<< "HELO lindenlab.com\r\n"
|
||||
<< "MAIL FROM:<" << from_address << ">\r\n"
|
||||
<< "RCPT TO:<" << to_address << ">\r\n"
|
||||
<< "DATA\r\n"
|
||||
<< "From: " << from_fmt.str() << "\r\n"
|
||||
<< "To: " << to_fmt.str() << "\r\n"
|
||||
<< "Subject: " << subject << "\r\n";
|
||||
|
||||
if(headers.isMap())
|
||||
{
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
for(; iter != end; ++iter)
|
||||
{
|
||||
header << (*iter).first << ": " << ((*iter).second).asString()
|
||||
<< "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
header << "\r\n";
|
||||
return header.str();
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLMail::send(
|
||||
const std::string& header,
|
||||
const std::string& raw_message,
|
||||
const char* from_address,
|
||||
const char* to_address)
|
||||
{
|
||||
if(!from_address || !to_address)
|
||||
{
|
||||
LL_INFOS() << "send_mail reject: missing to and/or from address."
|
||||
<< LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove any "." SMTP commands to prevent injection (DEV-35777)
|
||||
// we don't need to worry about "\r\n.\r\n" because of the
|
||||
// "\n" --> "\n\n" conversion going into rfc2822_msg below
|
||||
std::string message = raw_message;
|
||||
std::string bad_string = "\n.\n";
|
||||
std::string good_string = "\n..\n";
|
||||
while (1)
|
||||
{
|
||||
auto index = message.find(bad_string);
|
||||
if (index == std::string::npos) break;
|
||||
message.replace(index, bad_string.size(), good_string);
|
||||
}
|
||||
|
||||
// convert all "\n" into "\r\n"
|
||||
std::ostringstream rfc2822_msg;
|
||||
for(U32 i = 0; i < message.size(); ++i)
|
||||
{
|
||||
switch(message[i])
|
||||
{
|
||||
case '\0':
|
||||
break;
|
||||
case '\n':
|
||||
// *NOTE: this is kinda busted if we're fed \r\n
|
||||
rfc2822_msg << "\r\n";
|
||||
break;
|
||||
default:
|
||||
rfc2822_msg << message[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!gMailEnabled)
|
||||
{
|
||||
LL_INFOS() << "send_mail reject: mail system is disabled: to=<"
|
||||
<< to_address << ">, from=<" << from_address
|
||||
<< ">" << LL_ENDL;
|
||||
// Any future interface to SMTP should return this as an
|
||||
// error. --mark
|
||||
return true;
|
||||
}
|
||||
if(!gSockAddr)
|
||||
{
|
||||
LL_WARNS() << "send_mail reject: mail system not initialized: to=<"
|
||||
<< to_address << ">, from=<" << from_address
|
||||
<< ">" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!connect_smtp())
|
||||
{
|
||||
LL_WARNS() << "send_mail reject: SMTP connect failure: to=<"
|
||||
<< to_address << ">, from=<" << from_address
|
||||
<< ">" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostringstream smtp_fmt;
|
||||
smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n";
|
||||
std::string smtp_transaction = smtp_fmt.str();
|
||||
size_t original_size = smtp_transaction.size();
|
||||
apr_size_t send_size = original_size;
|
||||
apr_status_t status = apr_socket_send(
|
||||
gMailSocket,
|
||||
smtp_transaction.c_str(),
|
||||
(apr_size_t*)&send_size);
|
||||
disconnect_smtp();
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
LL_WARNS() << "send_mail socket failure: unable to write "
|
||||
<< "to=<" << to_address
|
||||
<< ">, from=<" << from_address << ">"
|
||||
<< ", bytes=" << original_size
|
||||
<< ", sent=" << send_size << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE)
|
||||
{
|
||||
LL_WARNS() << "send_mail message has been shown to fail in testing "
|
||||
<< "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE
|
||||
<< " bytes. The next log about success is potentially a lie." << LL_ENDL;
|
||||
}
|
||||
LL_DEBUGS() << "send_mail success: "
|
||||
<< "to=<" << to_address
|
||||
<< ">, from=<" << from_address << ">"
|
||||
<< ", bytes=" << original_size
|
||||
<< ", sent=" << send_size << LL_ENDL;
|
||||
|
||||
#if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND
|
||||
LL_INFOS() << rfc2822_msg.str() << LL_ENDL;
|
||||
#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)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
return "blowfish-not-supported-on-windows";
|
||||
#else
|
||||
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 htolememcpy.
|
||||
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);
|
||||
|
||||
std::string address = LLBase32::encode(encrypted, encrypted_size);
|
||||
|
||||
// Make it more pretty for humans.
|
||||
LLStringUtil::toLower(address);
|
||||
|
||||
delete [] encrypted;
|
||||
|
||||
return address;
|
||||
#endif
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* @file llmail.h
|
||||
* @brief smtp helper functions.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMAIL_H
|
||||
#define LL_LLMAIL_H
|
||||
|
||||
typedef struct apr_pool_t apr_pool_t;
|
||||
|
||||
#include "llsd.h"
|
||||
|
||||
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);
|
||||
|
||||
// Allow all email transmission to be disabled/enabled.
|
||||
static void enable(bool mail_enabled);
|
||||
|
||||
/**
|
||||
* @brief send an email
|
||||
* @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_address The email recipient address
|
||||
* @param subject The subject of the email
|
||||
* @param headers optional X-Foo headers in an llsd map.
|
||||
* @return 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,
|
||||
const LLSD& headers = LLSD());
|
||||
|
||||
/**
|
||||
* @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_address The email recipient address
|
||||
* @param subject The subject of the email
|
||||
* @param headers optional X-Foo headers in an llsd map.
|
||||
* @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,
|
||||
const LLSD& headers = LLSD());
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
#endif
|
||||
@@ -1,193 +0,0 @@
|
||||
/**
|
||||
* @file llareslistener_test.cpp
|
||||
* @author Mark Palange
|
||||
* @date 2009-02-26
|
||||
* @brief Tests of llareslistener.h.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
|
||||
#endif
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "../llareslistener.h"
|
||||
// STL headers
|
||||
#include <iostream>
|
||||
// std headers
|
||||
// external library headers
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
// other Linden headers
|
||||
#include "llsd.h"
|
||||
#include "llares.h"
|
||||
#include "../test/lltut.h"
|
||||
#include "llevents.h"
|
||||
#include "tests/wrapllerrs.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Dummy stuff
|
||||
*****************************************************************************/
|
||||
LLAres::LLAres():
|
||||
// Simulate this much of the real LLAres constructor: we need an
|
||||
// LLAresListener instance.
|
||||
mListener(new LLAresListener("LLAres", this))
|
||||
{}
|
||||
LLAres::~LLAres() {}
|
||||
void LLAres::rewriteURI(const std::string &uri,
|
||||
LLAres::UriRewriteResponder *resp)
|
||||
{
|
||||
// This is the only LLAres method I chose to implement.
|
||||
// The effect is that LLAres returns immediately with
|
||||
// a result that is equal to the input uri.
|
||||
std::vector<std::string> result;
|
||||
result.push_back(uri);
|
||||
resp->rewriteResult(result);
|
||||
}
|
||||
|
||||
LLAres::QueryResponder::~QueryResponder() {}
|
||||
void LLAres::QueryResponder::queryError(int) {}
|
||||
void LLAres::QueryResponder::queryResult(char const*, size_t) {}
|
||||
LLQueryResponder::LLQueryResponder() {}
|
||||
void LLQueryResponder::queryResult(char const*, size_t) {}
|
||||
void LLQueryResponder::querySuccess() {}
|
||||
void LLAres::UriRewriteResponder::queryError(int) {}
|
||||
void LLAres::UriRewriteResponder::querySuccess() {}
|
||||
void LLAres::UriRewriteResponder::rewriteResult(const std::vector<std::string>& uris) {}
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct data
|
||||
{
|
||||
LLAres dummyAres;
|
||||
};
|
||||
typedef test_group<data> llareslistener_group;
|
||||
typedef llareslistener_group::object object;
|
||||
llareslistener_group llareslistenergrp("llareslistener");
|
||||
|
||||
struct ResponseCallback
|
||||
{
|
||||
std::vector<std::string> mURIs;
|
||||
bool operator()(const LLSD& response)
|
||||
{
|
||||
mURIs.clear();
|
||||
for (LLSD::array_const_iterator ri(response.beginArray()), rend(response.endArray());
|
||||
ri != rend; ++ri)
|
||||
{
|
||||
mURIs.push_back(*ri);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
set_test_name("test event");
|
||||
// Tests the success and failure cases, since they both use
|
||||
// the same code paths in the LLAres responder.
|
||||
ResponseCallback response;
|
||||
std::string pumpname("trigger");
|
||||
// Since we're asking LLEventPumps to obtain() the pump by the desired
|
||||
// name, it will persist beyond the current scope, so ensure we
|
||||
// disconnect from it when 'response' goes away.
|
||||
LLTempBoundListener temp(
|
||||
LLEventPumps::instance().obtain(pumpname).listen("rewriteURIresponse",
|
||||
boost::bind(&ResponseCallback::operator(), &response, _1)));
|
||||
// Now build an LLSD request that will direct its response events to
|
||||
// that pump.
|
||||
const std::string testURI("login.bar.com");
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["uri"] = testURI;
|
||||
request["reply"] = pumpname;
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
ensure_equals(response.mURIs.size(), 1);
|
||||
ensure_equals(response.mURIs.front(), testURI);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<2>()
|
||||
{
|
||||
set_test_name("bad op");
|
||||
WrapLLErrs capture;
|
||||
LLSD request;
|
||||
request["op"] = "foo";
|
||||
std::string threw = capture.catch_llerrs([&request](){
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
});
|
||||
ensure_contains("LLAresListener bad op", threw, "bad");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<3>()
|
||||
{
|
||||
set_test_name("bad rewriteURI request");
|
||||
WrapLLErrs capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
std::string threw = capture.catch_llerrs([&request](){
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
});
|
||||
ensure_contains("LLAresListener bad req", threw, "missing");
|
||||
ensure_contains("LLAresListener bad req", threw, "reply");
|
||||
ensure_contains("LLAresListener bad req", threw, "uri");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<4>()
|
||||
{
|
||||
set_test_name("bad rewriteURI request");
|
||||
WrapLLErrs capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["reply"] = "nonexistent";
|
||||
std::string threw = capture.catch_llerrs([&request](){
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
});
|
||||
ensure_contains("LLAresListener bad req", threw, "missing");
|
||||
ensure_contains("LLAresListener bad req", threw, "uri");
|
||||
ensure_does_not_contain("LLAresListener bad req", threw, "reply");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<5>()
|
||||
{
|
||||
set_test_name("bad rewriteURI request");
|
||||
WrapLLErrs capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["uri"] = "foo.bar.com";
|
||||
std::string threw = capture.catch_llerrs([&request](){
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
});
|
||||
ensure_contains("LLAresListener bad req", threw, "missing");
|
||||
ensure_contains("LLAresListener bad req", threw, "reply");
|
||||
ensure_does_not_contain("LLAresListener bad req", threw, "uri");
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ include(bugsplat)
|
||||
set(test_SOURCE_FILES
|
||||
io.cpp
|
||||
llapp_tut.cpp
|
||||
llblowfish_tut.cpp
|
||||
llbuffer_tut.cpp
|
||||
lldoubledispatch_tut.cpp
|
||||
llevents_tut.cpp
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.A„Ä3ŒLÜE ``òøÝKÛ@¼ûÇ;M[ÚBë·ø„>ËÊC—'
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
01234567890123456789012345678901234
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Test Perl Crypt::CBC Blowfish algorithm and initial parameter settings
|
||||
# for compatibility with OpenSSL's Blowfish algorithm/settings.
|
||||
#
|
||||
# Used by outbound LSL email (openssl C library) and mailglue (Perl library)
|
||||
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);
|
||||
@@ -1,141 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "lltut.h"
|
||||
|
||||
#include "llblowfishcipher.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 std::string& filename,
|
||||
const std::string& data)
|
||||
{
|
||||
LLFILE* fp = LLFile::fopen(filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
// sometimes test is run inside the indra directory
|
||||
std::string path = "test/";
|
||||
path += filename;
|
||||
fp = LLFile::fopen(path, "rb");
|
||||
}
|
||||
if (!fp)
|
||||
{
|
||||
LL_WARNS() << "unable to open " << filename << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string good;
|
||||
good.resize(256);
|
||||
size_t got = fread(&good[0], 1, 256, fp);
|
||||
LL_DEBUGS() << "matchFile read " << got << LL_ENDL;
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user