0

I have a ColdFusion page that decrypts some data from another application. The ColdFusion code is pretty simple:

decrypt(theString,encryptKey,algorithmType,encodeType)

The algorithm type is RC4 and the encode type is hex. For whatever reason I'm having quite a bit of trouble getting this to work in .net. Are there any resources available for this kind of thing, or is there a fairly straightforward answer?

Update:

I've started by using an RC4 class found here: RC4 Encryption in C#. Although I've changed the encoding to Ascii, the results still are not matching.

public static class RC4
{
   public static string Encrypt(string key, string data)
   {
      Encoding unicode = Encoding.Unicode;

      return Convert.ToBase64String(Encrypt(unicode.GetBytes(key), unicode.GetBytes(data)));
   }

   public static string Decrypt(string key, string data)
   {
      Encoding unicode = Encoding.Unicode;

      return unicode.GetString(Encrypt(unicode.GetBytes(key), Convert.FromBase64String(data)));
   }

   public static byte[] Encrypt(byte[] key, byte[] data)
   {
      return EncryptOutput(key, data).ToArray();
   }

   public static byte[] Decrypt(byte[] key, byte[] data)
   {
      return EncryptOutput(key, data).ToArray();
   }

   private static byte[] EncryptInitalize(byte[] key)
   {
      byte[] s = Enumerable.Range(0, 256)
        .Select(i => (byte)i)
        .ToArray();

      for (int i = 0, j = 0; i < 256; i++)
      {
         j = (j + key[i % key.Length] + s[i]) & 255;

         Swap(s, i, j);
      }

      return s;
   }

   private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
   {
      byte[] s = EncryptInitalize(key);

      int i = 0;
      int j = 0;

      return data.Select((b) =>
      {
         i = (i + 1) & 255;
         j = (j + s[i]) & 255;

         Swap(s, i, j);

         return (byte)(b ^ s[(s[i] + s[j]) & 255]);
      });
   }

   private static void Swap(byte[] s, int i, int j)
   {
      byte c = s[i];

      s[i] = s[j];
      s[j] = c;
   }
}
Leigh
  • 28,765
  • 10
  • 55
  • 103
Josh
  • 41
  • 2
  • Can you be more specific about the problems you are having? – rossum Mar 24 '17 at 21:59
  • What have you tried? It does not look like that algorithm is part of the core libraries, but a quick search turned up a few custom implementations .. assuming you need to maintain RC4 for backward compatibility reasons? – Leigh Mar 24 '17 at 22:11
  • Oddly, RC4 exists o the CF documentation for Encrypt, but not Decrypt. I'm not sure why that would be. – Josh Mar 27 '17 at 00:24
  • That is just a documentation error. It is valid for both. – Leigh Mar 27 '17 at 02:09

1 Answers1

0

Update:

If the "encodeType" is actually base64 (not hex), then it is even simpler. Modify the Encrypt() function encode the result as base64. Then change the Decrypt() function to decode both values from base64.

public static string Encrypt(string base64Key, string plainText)
{

    return Convert.ToBase64String(Encrypt(Convert.FromBase64String(base64Key), Encoding.UTF8.GetBytes(plainText)));
}

public static string Decrypt(string base64Key, string base64Encrypted)
{
    return Encoding.UTF8.GetString(Encrypt(Convert.FromBase64String(base64Key), Convert.FromBase64String(base64Encrypted)));
}

I've changed the encoding to Ascii.

Close, but that still will not decode the input correctly. So the class will ultimately try and encrypt/decrypt the wrong binary, causing it to fail. To fully replicate the CF functions you need understand how they decode the parameters:

You need to modify the C# class to do the same thing.

  1. Start by creating helper functions that convert a byte[] to hex AND convert hex to a byte[]:

    public static string ByteArrayToHex(byte[] ba)
    {
        string hex = BitConverter.ToString(ba);
        return hex.Replace("-", "");
    }
    
    public static byte[] HexToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                         .ToArray();
    }
    
  2. Modify the Decrypt() function to decode the key as base64 and the encrypted text as hex. Finally, return the decrypted value as a UTF-8 string.

    public static string Decrypt(string base64Key, string hexValue)
    {
        return Encoding.UTF8.GetString(Encrypt(Convert.FromBase64String(base64Key), HexToByteArray(hexValue)));
    }
    
  3. Modify the Encrypt function to decode the key as base64 and the plain text as UTF-8. Then return the encrypted value as hex.

    public static string Encrypt(string base64Key, string plainText)
    {
    
        return ByteArrayToHex(Encrypt(Convert.FromBase64String(base64Key), Encoding.UTF8.GetBytes(plainText)));
    }
    

With those small changes, the C# code will produce the same result as the CF functions.

NB: I would recommend reading up on known issues with RC4 and consider switching to a more secure algorithm like AES.

Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103
  • Almost perfect. To make this work, I removed the hex subs and replaced them with Base64, like this, from the decrypt function: return Encoding.UTF8.GetString(Encrypt(Convert.FromBase64String(base64Key), Convert.FromBase64String(hexValue))); Then it worked perfectly. Thank you!!! – Josh Mar 27 '17 at 02:45
  • Ah, okay. The question description said the decrypt function was receiving a hex string, ie "*...the encode type is hex*. However, as you figured out - the binary is what matters, not the encoding. As long as both sides decode/encode the values correctly, it does not really make a difference what you use (base64, hex, etcetera). – Leigh Mar 27 '17 at 03:05