05-06-2004 03:55
Encrypted Email Example
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.");
}
}

_____________________
--
~If you lived here, you would be home by now~