Converting an ActionScript 2 Class to ActionScript 3

I am trying to be able to encrypt data in ColdFusion, and decrypt it using Flex (or more specifically, ActionScript 3). After some searching, I found a set of ActionScript 2 classes for encryption. They are open source and (as best I could tell) have no license attached to them.

I was specifically interested in Rijndael (AKA AES) encryption, because that is supported natively in ColdFusion via the Encrypt and Decrypt functions.

My first step was to take the Rijndael.as file from the ASCrypt component and see if I could get it working in Flex 2. It took about two hours, but the conversion was relatively smooth. These are some of the steps I took:

  1. Add a Package Definition: The ActionScript class did not include a package definition. The original class definition was like this:


    class com.meychi.ascrypt.Rijndael

    I modified this, first adding a package description to the AS file, like this:


    package com.meychi.ascrypt{

    And then modifying the class description like this:


    public class Rijndael {

  2. Defining an Array: This wasn't throwing compile errors, but I changed it anyway. A few of the instance variables were arrays, and were defined like this:


    private var Rcon:Array = [0x01, 0x02, ... ];

    It seemed odd to me that they weren't explicitly using a constructor, so I changed it to this:


    private var Rcon:Array = new Array(0x01, 0x02, ...);

    I'm not sure if the first syntax is supported for backward compatibility reasons, or if it a preferred approach, or whatever. I don't have a specific reason for making this change, it was made while I was trying to debug another error (It didn't address that other error, mind you)

  3. Null Checking: This one I don't have a specific solution for either. The original constructor was like this:


    public function Rijndael(keySize:Number, blockSize:Number){
    if (keySize != null) this.keySize = keySize;
    ....
    }

    The conditional "keySize != null" always threw compiler errors. I tried adding a code block and using an "is" operator to compare (because that's how compare against database nulls in SQL). The code would be like this:


    public function Rijndael(keySize:Number, blockSize:Number){
    if ( !(keySize is null) ){
    this.keySize = keySize;
    }
    ....
    }

    That would compile okay, but throw run-time errors. Eventually, I just removed the check to see if keySize is null. It appears to me that the listed arguments (keySize and blockSize) are both required. If you try to use the constructor w/o passing them in, you get an error (I believe at compile time). If you try to pass in a null value, it gives an error (I believe at run-time) saying that 'null' is not a valid Number.

    Based on those two reasons, my solution was to remove the null check altogether:


    public function Rijndael(keySize:Number, blockSize:Number){
    this.keySize = keySize;
    ...
    }

    I feel like I'm missing something obvious here, but it worked.

  4. Void vs void: ActionScript (Like JavaScript, Java, et all) is case sensitive. The original function had a few private functions with a specified returntype of Void (With a capital V). This was throwing compile errors. I changed it to 'void' (all lowercase). The old way:


    private function byteSub(state:Array, dir:String):Void {

    And the corrected way:


    private function byteSub(state:Array, dir:String):void {

    I wonder why that was accepted in ActionScript 2. I don't know ActionScript 2 very well, so.. your guess is as good as mine, perhaps better.

  5. Variable Declared Multiple Times: I had a few spots where a variable was declared multiple times within a function. Like this:


    if(dir == "encrypt")
    var S:Array = this.SBox;
    else
    var S:Array = this.SBoxInverse;

    The second declaration was throwing a compiler error. My first solution was along the right path (but wrong). I added an explicit var at the top of the function and remove var from the assignments:


    var S:Array;

    if(dir == "encrypt")
    S:Array = this.SBox;
    else
    S:Array = this.SBoxInverse;

    This was still throwing compile errors. Do you see what I did wrong? It was trying to solve this error that made me change the array declarations (See item 2) on the private class variables (but that change had no affect). My problem here was that I was specifying a 'type' in the assignment. Instead of S:Array = this.SBox I should have specified "S = this.sBox". Like this:


    var S:Array;

    if(dir == "encrypt") {
    S= this.SBox;
    } else {
    S = this.SBoxInverse;
    }

    (I like to use code blocks wherever possible, so when I was changing the code, I added the curly brace code blocks as relevant including this if else statement )

  6. Loop counters Declared Twice or not declared at all: The original code had a bunch of for loops in it. Nothing out of the ordinary with that. The loops were often set up like this:


    for (var j:Number = 0; j<this.Nb; j++) {
    ...
    }

    You'll notice that the loop counter 'j' is defined as part of the loop. That's fine and dandy. But, with multiple loops using the same counter, the second loop was throwing a 'variable already defined' type of error. I just moved the declaration out of the loop:


    var j:Number;

    for (j = 0; j<this.Nb; j++) {

    In one case, the loop counter variable was not defined at all. I assume this was a typo in the original code. I just added a definition at the top of the method (just like I did for j above).


After those changes, the AS file started working. You can test the code like this:



<mx:Script>
<![CDATA[
import com.meychi.ascrypt.Rijndael;            

public var rijndael_test:Rijndael = new Rijndael (128, 128);
public var rijndael_text:String = "Rijndael:keysize192/24chars";
public var rijndael_key:String = "123456789012345612345678";

public var rijndael_hash:String = rijndael_test.encrypt(rijndael_text, rijndael_key, "ECB");
            
public function EncryptString():void{
encrypted.text = rijndael_hash;                
decrypted.text = rijndael_test.decrypt(rijndael_hash, rijndael_key, "ECB");
}
]]>

</mx:Script>

<mx:Label x="36" y="20" text="Label" width="600" id="encrypted"/>
<mx:Label x="36" y="40" text="Label" width="600" id="decrypted"/>
<mx:Button x="76" y="140" label="RunEncrypt" click="{EncryptString()}"/>

That is, roughly, the same sample from the original ASCrypt component, I just added code to assign the results to labels instead of using trace.

After all is said and done, Encryption using AES and ColdFusion is producing different results than encryption using this Rijndael.as file. ColdFusion threw an error on the key specified above, saying it was invalid.

I suspect it has something to do with the keysize and blocksize, which are configurable in the ActionScript class, but are not in ColdFusion. Anyone have any thoughts on that?

I'm releasing my code changes under the same license that the original was released under (that is to say, none at all )

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Alex Cook's Gravatar Hey do you have the old AS 2.0 class somewhere? Could you possibly forward that to me? The link to it is dead and I really wish I had the installer for it!

Alex
# Posted By Alex Cook | 5/1/07 6:57 PM
# Posted By grymmace | 5/5/08 11:36 AM
grymmace's Gravatar Also, for the various algorithms use the WayBackMachine to view the old meychi.com:
http://web.archive.org/web/20070312155637/http://w...

My WinZip could not process the .zip files, I had to rely on windows' 'open compressed folder' thing.
# Posted By grymmace | 5/5/08 11:58 AM
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.