Compare password hashes between C# and ColdFusion (CFMX_COMPAT)

I looked through the Railo code as someone else here mentioned in comments.

Following is CFMX_Compat ported to C# from the Railo Java source. See below for an example of usage.

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace RailoUtil
{
    // SOURCE: Railo Source Code License LGPL v2
    // http://wiki.getrailo.org/wiki/RailoLicense
    public class RailoCFMXCompat
    {
        private String m_Key;
        private int m_LFSR_A = 0x13579bdf;
        private int m_LFSR_B = 0x2468ace0;
        private int m_LFSR_C = unchecked((int)0xfdb97531);
        private int m_Mask_A = unchecked((int)0x80000062);
        private int m_Mask_B = 0x40000020;
        private int m_Mask_C = 0x10000002;
        private int m_Rot0_A = 0x7fffffff;
        private int m_Rot0_B = 0x3fffffff;
        private int m_Rot0_C = 0xfffffff;
        private int m_Rot1_A = unchecked((int)0x80000000);
        private int m_Rot1_B = unchecked((int)0xc0000000);
        private int m_Rot1_C = unchecked((int)0xf0000000);

        public byte[] transformString(String key, byte[] inBytes)
        {
            setKey(key);
            int length = inBytes.Length;
            byte[] outBytes = new byte[length];
            for (int i = 0; i < length; i++)
            {
                outBytes[i] = transformByte(inBytes[i]);
            }
            return outBytes;
        }

        private byte transformByte(byte target)
        {
            byte crypto = 0;
            int b = m_LFSR_B & 1;
            int c = m_LFSR_C & 1;
            for (int i = 0; i < 8; i++)
            {
                if (0 != (m_LFSR_A & 1))
                {
                    m_LFSR_A = m_LFSR_A ^ m_Mask_A >> 1 | m_Rot1_A;
                    if (0 != (m_LFSR_B & 1))
                    {
                        m_LFSR_B = m_LFSR_B ^ m_Mask_B >> 1 | m_Rot1_B;
                        b = 1;
                    }
                    else
                    {
                        m_LFSR_B = m_LFSR_B >> 1 & m_Rot0_B;
                        b = 0;
                    }
                }
                else
                {
                    m_LFSR_A = (m_LFSR_A >> 1) & m_Rot0_A;
                    if (0 != (m_LFSR_C & 1))
                    {
                        m_LFSR_C = m_LFSR_C ^ m_Mask_C >> 1 | m_Rot1_C;
                        c = 1;
                    }
                    else
                    {
                        m_LFSR_C = m_LFSR_C >> 1 & m_Rot0_C;
                        c = 0;
                    }
                }

                crypto = (byte)(crypto << 1 | b ^ c);
            }

            target ^= crypto;
            return target;
        }

        private void setKey(String key)
        {
            int i = 0;
            m_Key = key;
            if (String.IsNullOrEmpty(key)) key = "Default Seed";
            char[] Seed = new char[key.Length >= 12 ? key.Length : 12];
            Array.Copy(m_Key.ToCharArray(), Seed, m_Key.Length);
            int originalLength = m_Key.Length;
            for (i = 0; originalLength + i < 12; i++)
                Seed[originalLength + i] = Seed[i];

            for (i = 0; i < 4; i++)
            {
                m_LFSR_A = (m_LFSR_A <<= 8) | Seed[i + 4];
                m_LFSR_B = (m_LFSR_B <<= 8) | Seed[i + 4];
                m_LFSR_C = (m_LFSR_C <<= 8) | Seed[i + 4];
            }
            if (0 == m_LFSR_A) m_LFSR_A = 0x13579bdf;
            if (0 == m_LFSR_B) m_LFSR_B = 0x2468ace0;
            if (0 == m_LFSR_C) m_LFSR_C = unchecked((int)0xfdb97531);
        }
    }
}

Here is a usage example that Hex-encodes the encrypted text, and then decrypts the same thing.

RailoCFMXCompat cfmx = new RailoCFMXCompat();
UTF8Encoding encoding = new UTF8Encoding();

//encrypt my string
byte[] encrypted = cfmx.transformString("mySecretKey", encoding.GetBytes("clear text"));
string encryptedHex = BitConverter.ToString(encrypted); //72-07-AA-1B-89-CB-01-96-4F-51

//decrypt my string
byte[] encryptedBytes = HexToBytes("72-07-AA-1B-89-CB-01-96-4F-51");
byte[] decrypted = cfmx.transformString("mySecretKey", encryptedBytes);
string cleartext = encoding.GetString(decrypted);

Leave a Comment