Project: Encryption in Various Languages

I recently had to come up with a way to pass around user information across many different web sites. In the end, we decided to pass encrypted bit of information in the querystring of the URL in each of the redirects. This required sites, hosted and programmed by different companies, to all be able to decrypt data. I had to come up with some sample code showing how encryption works in various programming languages.

The encryption method we choose was TripleDES because it is quote common. This is a form of private key encryption, meaning it involves a secret string (or key) that only the person encrypting the data, and the person decrypting the data should know.

Here are the encryption key and values i will be using for the rest of the samples:

Key: cPSQAC05GBXzMhRRz7tm8cqg+vHdHyN5
IV: jIShBJVBfXo=
Encrypted Value: 8yN73RDmMFuXo9ux8QKC6w==
Decrypted Value: blueberry

"Where did these come from," you might ask. This key was generated for me with the following VB.NET code sample. (It has been formatted so can easily drop it into Snippet Compiler to give it a go.) The encrypted value was also generated in VB.NET. While encryption samples are not shown on this page, you can grab them from the "Downloads" section.

Generating A Key (VB.NET):

imports System
imports System.Text
imports System.Security.Cryptography
public module MyModule
   sub Main
       Dim sa As SymmetricAlgorithm = SymmetricAlgorithm.Create("TripleDES")
       sa.GenerateKey()
       sa.GenerateIV()

       Console.WriteLine("Key: " & Convert.ToBase64String(sa.Key))
       Console.WriteLine("IV: " & Convert.ToBase64String(sa.IV))
       Console.ReadLine 'so you can see the output
   end sub
end module

Each time that code runs, it will produce a brand new, secure TripleDES key and IV. The IV part stands for initialization vector. The IV can be used to increase security by allowing you to use a same key to get different results. With TripleDES the value is actually optional and if not specified, the algorithm will usually use some part of the key itself. Exactly which part isn't always clear so in the interest of being as explicit as possible, we clearly specify this value.

You'll notice that before we spit out the key value, we converted it to a base64 string. Generally when you create a key, it will be a series of bits. These bits don't necessarily make up letters and numbers so they can be hard to work with. One way of visualizing these values is to view a hexadecimal representation. For example, our encrypted value could be rewitten as "3C404772CE784A826007508449619847." Instead, we use Base64 encoding [PDF: 107kB] because, as you can see, the value is shorter that way. The base64 version is only 24 characters long whereas the hexadecimal version is 32 characters long. We must remember to always decode these values before we use them.

Because this project started in .NET, i'll show you that decryption code first. The System.Security.Cryptography namespace gives us all the objects we need to do the dirty work. We use a symetric algorithm object for TripleDES because the same key is used for encrypting and decrypting (that's the symmetric part). Most of the methods work only with "streams" of data. You will notice the extra code in the sample required to put our string into a stream and then to get a string out again in the end.

VB.NET Decrypt Sample:

imports System
imports System.Text
imports System.Security.Cryptography
imports System.IO

public module MyModule
   sub Main
       'initialize our key
       Dim tripleDESKey As SymmetricAlgorithm = SymmetricAlgorithm.Create("TripleDES")
       tripleDESKey.Key = Convert.FromBase64String("cPSQAC05GBXzMhRRz7tm8cqg+vHdHyN5")
       tripleDESKey.IV = Convert.FromBase64String("jIShBJVBfXo=")
       
       'load our encrypted value into a memory stream
       Dim encryptedValue as String = "8yN73RDmMFuXo9ux8QKC6w=="
       Dim encryptedStream As MemoryStream = New MemoryStream()
       encryptedStream.Write(Convert.FromBase64String(encryptedValue), 0, Convert.FromBase64String(encryptedValue).Length)
       encryptedStream.Position = 0
   
       'set up a stream to do the decryption
       Dim cs As CryptoStream = New CryptoStream(EncryptedStream, tripleDESKey.CreateDecryptor, CryptoStreamMode.Read)
       Dim decryptedStream As MemoryStream = New MemoryStream()        
       Dim buf() As Byte = New Byte(2048) {}
       Dim bytesRead As Integer
       
       'keep reading from encrypted stream via the crypto stream
       'and store that in the decrypted stream
       bytesRead = cs.Read(buf, 0, buf.Length)
       While (bytesRead > 0)
           decryptedStream.Write(buf, 0, bytesRead)
           bytesRead = cs.Read(buf, 0, buf.Length)
       End While

       'reassemble the decrypted stream into a string    
       Dim decryptedValue As String = Encoding.ASCII.GetString(DecryptedStream.ToArray())
       
       Console.WriteLine(decryptedValue.ToString())
       Console.ReadLine() 'so you can see it
   end sub
end module

Next i'll show an ASP sample written in VBScript. ASP has no native objects to do encryption. We used a third party component called ASPEncrypt from Persits Software. The component allows us to create a CryptoManager object that is responsible for generating all the objects that actually to the work. All cryptography functions happen within a CrytpoContext object. It is that object which we use to generate the CryptoKey that will do the decryption. You can also create Blobs with the CryptoManager object which allows you to easily decode our base64 encoded strings. To see everthing the object can do, check out their online documentation.

ASP/VBScript Decrypt Sample:

<%
   OPTION EXPLICIT

   Const calg3DES=26115
   
   Dim EncryKey, EncryIV, EncryptedString
   EncryKey="cPSQAC05GBXzMhRRz7tm8cqg+vHdHyN5"
   EncryIV="jIShBJVBfXo="
   EncryptedString="8yN73RDmMFuXo9ux8QKC6w=="

   'initialize encryption objects
   Dim CM, CryptoContext
   Set CM=Server.CreateObject("Persits.CryptoManager")
   Set CryptoContext=CM.openContext("",true)

   'init key    
   Dim CryptoKey, KeyBlob, IVBlob    
   Set KeyBlob=CM.CreateBlob
   KeyBlob.Base64=EncryKey
   Set IVBlob=CM.CreateBlob
   IVBlob.Base64=EncryIV
       
   Set CryptoKey=CryptoContext.ImportRawKey(KeyBlob, calg3DES, true)
   CryptoKey.SetIV IVBlob
       
   Set KeyBlob=Nothing
   Set IVBlob=Nothing
   
   'dectypt value
   Dim oTextBlob, DecryptedString
   Set oTextBlob=CM.CreateBlob
   oTextBlob.Base64=EncryptedString
       DecryptedString = CryptoKey.DecryptText(oTextBlob)
   Set oTextBlob=Nothing
   
   Response.Write DecryptedString
   ' you should get "blueberry"
   
   'clean up
   Set CryptoKey=Nothing
   Set CryptoContext=Nothing
   Set CM=Nothing
%>

When we jump to perl, we need to know one more piece of information. We need to know which cipher mode we used to encrypt the data. The most common form is cipher block chaining (CBC), which our VB.NET and ASPEncrypt objects had defaulted to. Therefore, the functions we require can be found in the Crypt::CBC modules. We also need the Crypt::DES and Crypt::DES_EDE3 modules. The MIME::Base64 module will take care of working with the base64 encoded strings. These can all easily be found in the CPAN library.

Perl Decrypt Sample:

use MIME::Base64;
use Crypt::CBC;
#will also need Crypt::DES and Crypt::DES_EDE3 installed
 
use strict;
use warnings;
 
# values the same for all requests
my $key64 = "cPSQAC05GBXzMhRRz7tm8cqg+vHdHyN5";
my $iv64 = "jIShBJVBfXo=";
my $encryptedString = "8yN73RDmMFuXo9ux8QKC6w==";
 
# change everything to bytes
my $keybytes = decode_base64($key64);
my $ivbytes = decode_base64($iv64);
my $encryptedStringBytes = decode_base64($encryptedString);
 
my $cipher = Crypt::CBC->new(
   {
       key => $keybytes,
       iv => $ivbytes,
       cipher => 'DES_EDE3',
       regenerate_key => 0
   }
);
 
my $decryptString = $cipher->decrypt($encryptedStringBytes);
print "$decryptString\n";
# you should get "blueberry"
 

PHP provides access to encryption routines via the mcrypt library. This is not typically part of the standard PHP installation but can be downloaded and installed fairly easily.

All of the PHP decryption happens in one line of code with a call to mcrypt_decrypt. An important thing to note is the special trimming of the returned value. That is because PHP does not seems to support a basic form of padding which all the other languages do. The data gets padded because DES encryption (hence TripleDES) require the data they encrypt to be in eight byte chunks. If the actual number of bytes is not a multiple of eight, the data must be padded. The other languages used a method called "PKCS #5" padding. Basically that means that if the data is x-bytes sort of a multiple of eight, we pad on x-bytes each with a value of x. If we wanted to encrypt the word "house" we would actually be encrypting "house\3\3\3." When PHP encrypts, it just adds null bytes; so when it decrypts, it only removes null bytes. This means we remove those padding bytes ourselves. The trim statement with the "\x00..\x1F" parameter will remove all the low-value, unprintable characters that may have been added.

PHP Decrypt Sample:

<?php
$key64 = "cPSQAC05GBXzMhRRz7tm8cqg+vHdHyN5";
$iv64 = "jIShBJVBfXo=";
$encryptedString64 = "8yN73RDmMFuXo9ux8QKC6w==";
$keybytes = base64_decode($key64);
$ivbytes = base64_decode($iv64);

$encryptedStringbytes = base64_decode($encryptedString64);

// use mcrypt library for encryption
$decryptRaw = mcrypt_decrypt(MCRYPT_3DES, $keybytes, $encryptedStringbytes, MCRYPT_MODE_CBC, $ivbytes);
$decryptString=trim($decryptRaw,"\x00..\x1F");
print "$decryptString<br/>";
// should display "blueberry"
?>

If you plan to encrypt and decrypt data with different programming languages, you need to know what encryption algorithm you are using, what type of encoding you are using, which cipher block mode you are using, and how your data will be padded. For even more detail on DES encryption, check out The DES Algorithm Illustrated.

Downloads

home - blog - me@matthewflickinger.com