Thursday, May 6, 2010

XPages: Simple string encrypter/decrypter

I needed a simple encryption routine today. I found this article with accompanying code.

Here's the routine ported to Server Side JavaScript:
function StringEncrypter( encryptionScheme:String, encryptionKey:String ){
try{
encryptionScheme = encryptionScheme || this.DESEDE_ENCRYPTION_SCHEME;
encryptionKey = encryptionKey || this.DEFAULT_ENCRYPTION_KEY;
if( encryptionKey.length < 24 ){
throw new java.lang.Exception(
'Encryption key was less than 24 characters.' );
}
var keyAsBytes = encryptionKey.getBytes( this.UNICODE_FORMAT );

switch( encryptionScheme ){
case this.DESEDE_ENCRYPTION_SCHEME:
this.keySpec = new javax.crypto.spec.DESedeKeySpec( keyAsBytes ); break;
case this.DES_ENCRYPTION_SCHEME:
this.keySpec = new javax.crypto.spec.DESKeySpec( keyAsBytes ); break;
default:
throw new java.lang.Exception(
"Encryption scheme not supported: " + encryptionScheme );
}

this.keyFactory = javax.crypto.SecretKeyFactory.getInstance( encryptionScheme );
this.cipher = javax.crypto.Cipher.getInstance( encryptionScheme );
} catch( e ){ /* your exception handling */ }
}

StringEncrypter.prototype = {
DESEDE_ENCRYPTION_SCHEME: "DESede",
DES_ENCRYPTION_SCHEME: "DES",
DEFAULT_ENCRYPTION_KEY:
"The ships hung in the sky in much the same way that bricks don't.",
UNICODE_FORMAT: "UTF8",

keySpec: null,
keyFactory: null,
cipher: null,

encrypt: function( unencryptedString ){
if( !unencryptedString ){ return ''; }

try {
var key = this.keyFactory.generateSecret( this.keySpec );
this.cipher.init( javax.crypto.Cipher.ENCRYPT_MODE, key );
var clearText = unencryptedString.getBytes( this.UNICODE_FORMAT );
var cipherText = this.cipher.doFinal( clearText );

var base64encoder = new sun.misc.BASE64Encoder();
return base64encoder.encode( cipherText );
} catch( e ){ /* your exception handling */ }
},
decrypt: function( encryptedString ){
if( !encryptedString ){ return ''; }

try {
var key = this.keyFactory.generateSecret( this.keySpec );
this.cipher.init( javax.crypto.Cipher.DECRYPT_MODE, key );
var base64decoder = new sun.misc.BASE64Decoder();
var clearText = base64decoder.decodeBuffer( encryptedString );
var cipherText = this.cipher.doFinal( clearText );

return new java.lang.String( cipherText );
} catch( e ){ /* your exception handling */ }
}
}
Example usage:

Encryption
var encrypter = new StringEncrypter();
encrypter.encrypt( unencryptedString );
Decryption
var encrypter = new StringEncrypter();
encrypter.decrypt( encryptedString );
As you can see from the constructor, you can specify your own encryption key/choose from two encryption methods.

I simply ported the code, so if you want more details, read the article from which I snagged the code.

5 comments:

fabio said...

Hi!

Do you know how to create a scheme in Xpages to interpret a entry value? I am using metadataresource (in custom control's properties)and need to validate the entry field.
Thanks,
Fábio

Tommy Valand said...

I'm not exactly sure what you're asking about..

Are you talking about properties in the Property definition for a custom control?

In the validation pane for the property, you can write a custom validation for the property.

E.g. return (value == 'blue' || 'red')

In the above example, only blue or red would be accepted (you get a dialog with the text return (value == 'blue' || 'red'), and the value is blanked).

The above example is silly, as one would use a combobox for the custom property to select red or blue, but you get my drift..

If it's something else you're asking about, please try to explain in other/more words :)

Bill Hanson said...

Hi Tommy,

Once again, your code has put me on the fast track! I have tested this solution via a web browser, and everything works as expected. But when I run it in the Notes client, I receive the following exception:

Error while executing JavaScript action expression
ECL Permission Denied (java.lang.RuntimePermission accessClassInPackage.sun.misc)

I've seen this:

http://dontpanic82.blogspot.com/2010/09/need-help-ecl-exception-when-using-java.html

and this:

http://www-10.lotus.com/ldd/ddwiki.nsf/dx/XPages_in_the_Notes_Client-Security

Nothing new there.

The thing that confuses me is that I signed the code and have full rights in the ECL, so under what account is this code running? I can't allow -Default- or -No Signature- to run unrestricted.

Have you found a solution for this yet?

Tommy Valand said...

To work around the problem, you could maybe write the java code that I linked to in a jar, put it on the server, and call the java code from SSJS.

From the wiki:
move the code that requires the permission to a trusted location, jvm/lib/ext, mark the code as privileged, and then call it from the untrusted XPage.

I haven't made any XPages applications for the Notes Client, so I'm not too familiar with Java policies/etc.

Bill Hanson said...

I thought about doing that, but once again my challenge is to get a Lotus application to run everywhere (web & Notes, server & local replica). Going the .jar route would result in having to touch all of our Notes clients.

Worst case is that I farm this out to a backend agent that uses a NotesDocument or my old LotusScript class to encrypt/decrypt the info.

I'll let you know if I find anything interesting.