CODE
// Francis was here
// Encrypted Email Example
// This script implements an encryption library, as well as demonstrates how it
// can be used to send an encrypted email.
// Encryption is performed with repeated XORing against MD5Sums. Symmetric keys.
//
// The slowest part of this script is the conversion from base16 (MD5sum in a
// string) to base64 (UUENCODE - the closest to binary access provided by LSL)
// Your secret password
string password = "Imagine: In Florida the wind is rattling the chimes.";
// Channel we listen to, and access pin (Just pick a random integer)
integer magicCookie = -5481893734;
// If you always use this script name in the subject field, you can put as many
// different versions of this script in an object as you like.
string filterSubject = ""; // llGetScriptName()
string magicToken = "=^..^=";
integer DEBUG = TRUE;
string FAIL = "FAILURE_TO_AUTHENTICATE";
float timerEvent = 15; // Wake up ever 15 seconds to check for email
// Take a string that encodes a hex value (ie. md5sum), and convert it to base64
string base16ToBase64( string hexInput ) {
string base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string base16 = "0123456789abcdef";
integer curChar = 0;
integer curBits = 0;
integer overflow = 0;
integer overflowBits = 0;
string base64md5 = "";
// Peel of 4 bits at a time off hexInput, see if we have enough bits to convert
// to bas64, and continue
while ( curBits >= 6 || llStringLength(hexInput) ) {
integer hex = llSubStringIndex(base16, llGetSubString(hexInput, 0, 0));
hexInput = llDeleteSubString(hexInput, 0, 0);
curChar = (curChar * 16) | hex;
curBits += 4;
if ( curBits > 6 ) {
overflowBits = curBits - 6;
overflow = curChar & ((integer)llPow(2,overflowBits) - 1);
curChar = curChar / (integer)llPow(2,overflowBits);
curBits -= overflowBits;
}
if ( curBits == 6 ) {
base64md5 += llGetSubString( base64, curChar, curChar );
curChar /= 64;
curBits -= 6;
}
curChar = (curChar * (integer)llPow(2, overflowBits)) | overflow;
curBits += overflowBits;
overflow = 0;
overflowBits = 0;
}
if ( curBits ) {
curChar *= (integer) llPow(2, 6-curBits);
base64md5 += llGetSubString( base64, curChar, curChar );
}
base64md5 += "==";
return base64md5;
}
// Encrypt a message. The passphrase and the nonce are used to scramble the message
// and the nonce is stored in the encrypted message as plain-text
// The encrypted format is [nonce][message][md5sum]
string encrypt( string passPhrase, string nonce, string message ) {
string md5Cipher = "";
string encryptedMessage;
string md5sum;
integer i=0;
while ( llStringLength(md5Cipher) < llStringLength(message)*4) {
md5Cipher += llMD5String( passPhrase+nonce, i++ );
}
encryptedMessage = llXorBase64Strings( llStringToBase64(message), base16ToBase64(md5Cipher) );
md5sum = llMD5String( message+passPhrase+nonce, 0 );
return magicToken+ nonce +magicToken+ encryptedMessage +magicToken+ md5sum +magicToken;
}
// Decrypt a message encoded by the encrypt() function
string decrypt( string passPhrase, string buf ) {
integer index;
integer magicTokenLen = llStringLength( magicToken );
string md5sum;
string messageChecksum;
string message;
string encryptedMessage;
string nonce;
integer messageLength; // Actually, an overestimate.
string md5Cipher = "";
integer i=0;
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
// Chop off first token
buf = llGetSubString( buf, index+magicTokenLen, llStringLength(buf) - 1 );
// Extract nonce
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
nonce = llGetSubString( buf, 0, index - 1 );
// Chop off 2nd token
buf = llGetSubString( buf, index+magicTokenLen, llStringLength(buf) - 1 );
// Extract encrypted message
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
encryptedMessage = llGetSubString( buf, 0, index - 1 );
// Chop off 3rd token
buf = llGetSubString( buf, index+magicTokenLen, llStringLength(buf) - 1 );
// Extract md5sum
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
md5sum = llGetSubString( buf, 0, index - 1 );
messageLength = llStringLength(encryptedMessage) * 6 / 8 + 2;
while ( llStringLength(md5Cipher) < messageLength*4 ) {
md5Cipher += llMD5String( passPhrase+nonce, i++ );
}
message = llBase64ToString(llXorBase64Strings( encryptedMessage, base16ToBase64(md5Cipher) ) );
messageChecksum = llMD5String( message+passPhrase+nonce, 0 );
if ( md5sum != messageChecksum )
return FAIL;
return message;
}
// Get the nonce out of an encrypted message
string getNonce( string buf ) {
integer index;
integer magicTokenLen = llStringLength( magicToken );
string nonce;
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
// Chop off first token
buf = llGetSubString( buf, index+magicTokenLen, llStringLength(buf) - 1 );
// Find where nonce ends
index = llSubStringIndex( buf, magicToken );
if ( index == -1 )
return FAIL;
return llGetSubString( buf, 0, index - 1 );
}
// Note: Subject & nonce are sent plain-text, but their values are digitally
// signed by the encryption scheme.
sendEncryptedEmail( string addr, string subject, string nonce, string message ) {
string md5Cipher = "";
string encryptedMessage;
integer i=0;
encryptedMessage = encrypt( password+subject, nonce, message );
llEmail( addr, subject, encryptedMessage);
}
// Extract a string between dilineators =^..^= and authenticates & decrypts
// "=^..^=nonce=^..^=stuff=^..^=md5sum=^..^="
string decryptEmail( string subject, string body ) {
return decrypt( password+subject, body );
}
//**************************************************************************************************
// This function called upon receipt of an encrypted email
handleEncryptedMessage( string address, string subject, string nonce, string message ) {
llSay( 0, "Successfully received encrypted email from: " + address );
llSay( 0, "Subject: " + subject );
llSay( 0, "Message: " + message );
}
//**************************************************************************************************
init() {
llSetText( llGetScriptName(), <1,1,1>, 1 );
llSetTimerEvent( timerEvent );
}
default {
state_entry() {
init();
}
on_rez( integer code ) {
init();
}
email(string time, string address, string subject, string message, integer n) {
string authenticatedMsg = decryptEmail( subject, message );
if ( authenticatedMsg != FAIL ) { // Successful authentication
handleEncryptedMessage( address, subject, getNonce(message), authenticatedMsg );
}
else if ( DEBUG ) { // Received an email that does not authenticate
llSay( 0, "FAILED authentication from: " + address );
llSay( 0, "Subject: " + subject );
llSay( 0, "Message body: " + message );
}
llGetNextEmail( "", filterSubject );
}
timer(){
llGetNextEmail( "", filterSubject );
}
touch_start(integer total_number) {
llSay(0, "Email Addresss: " + (string)llGetKey() + "@lsl.secondlife.com");
}
}
Simple Encrypted Email Sender
This code snippet is mostly a duplication of the above script - it just makes for easy cutting & pasting to send a trivial email

CODE
// Francis was here
// Touch this prim to send an email
// Replace this email address with the prim containing the Encrypted Email Example
string emailAddr = "1a671408-4ea2-6e64-c8ab-7d775511446d@lsl.secondlife.com";
// Your secret password
string password = "Imagine: In Florida the wind is rattling the chimes.";
string magicToken = "=^..^=";
string nonce = "Salt.";
string subject = "Encrypted Email Example";
string message = "Hello, encryption.";
// Take a string that encodes a hex value (ie. md5sum), and convert it to base64
string base16ToBase64( string hexInput ) {
string base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string base16 = "0123456789abcdef";
integer curChar = 0;
integer curBits = 0;
integer overflow = 0;
integer overflowBits = 0;
string base64md5 = "";
// Peel of 4 bits at a time off hexInput, see if we have enough bits to convert
// to bas64, and continue
while ( curBits >= 6 || llStringLength(hexInput) ) {
integer hex = llSubStringIndex(base16, llGetSubString(hexInput, 0, 0));
hexInput = llDeleteSubString(hexInput, 0, 0);
curChar = (curChar * 16) | hex;
curBits += 4;
if ( curBits > 6 ) {
overflowBits = curBits - 6;
overflow = curChar & ((integer)llPow(2,overflowBits) - 1);
curChar = curChar / (integer)llPow(2,overflowBits);
curBits -= overflowBits;
}
if ( curBits == 6 ) {
base64md5 += llGetSubString( base64, curChar, curChar );
curChar /= 64;
curBits -= 6;
}
curChar = (curChar * (integer)llPow(2, overflowBits)) | overflow;
curBits += overflowBits;
overflow = 0;
overflowBits = 0;
}
if ( curBits ) {
curChar *= (integer) llPow(2, 6-curBits);
base64md5 += llGetSubString( base64, curChar, curChar );
}
base64md5 += "==";
return base64md5;
}
// Encrypt a message. The passphrase and the nonce are used to scramble the message
// and the nonce is stored in the encrypted message as plain-text
// The encrypted format is [nonce][message][md5sum]
string encrypt( string passPhrase, string nonce, string message ) {
string md5Cipher = "";
string encryptedMessage;
string md5sum;
integer i=0;
while ( llStringLength(md5Cipher) < llStringLength(message)*4) {
md5Cipher += llMD5String( passPhrase+nonce, i++ );
}
encryptedMessage = llXorBase64Strings( llStringToBase64(message), base16ToBase64(md5Cipher) );
md5sum = llMD5String( message+passPhrase+nonce, 0 );
return magicToken+ nonce +magicToken+ encryptedMessage +magicToken+ md5sum +magicToken;
}
// Note: Subject & nonce are sent plain-text, but their values are digitally
// signed by the encryption scheme.
sendEncryptedEmail( string addr, string subject, string nonce, string message ) {
string md5Cipher = "";
string encryptedMessage;
integer i=0;
encryptedMessage = encrypt( password+subject, nonce, message );
llEmail( addr, subject, encryptedMessage);
}
default {
state_entry() {
llSetText( llGetScriptName() +"\nTouch to send an encrypted email to\n" + emailAddr, <1,1,1>, 1 );
}
touch_start(integer total_number) {
llSay(0, "Sending Email...");
sendEncryptedEmail( emailAddr, subject, nonce, message );
llSay(0, "... done.");
}
}