Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

Decrypting Control4 Lua

Featured Replies

  • Author
  • Localization

HighlightRepulsive98, posted Sun Aug 22, 2021 9:53 pm (65833)


Hey can someone help me decrypt some Control4 clipsal c-bus automation driver files?
I have some c-bus automation equipment at home that id like to integrate with a control4 system. I figure if i can see how the current drivers are written i can build from these to create additiona drivers for other commuication of functions such as temperature and energy consumption which currently are not supported.

I realise this is a bit taboo, however the drivers are free and over 10 years old.

The drivers in question are located here: https://drivers.control4.com/solr/drive ... Clipsal"

Specifically the ethernet driver and a dimmer / light would be great to revel how they work, all of them would be evern better :P. I have tried to follow this https://pushstack.wordpress.com/2016/03 ... ecryption/ but have not had much luck so far.
  • Author
  • Localization

atom0s, posted Mon Aug 23, 2021 1:31 am (65834)


Here's their own code used to encrypt the scripts from their driver editor app:
Code:
using System;
using System.Security.Cryptography;
using System.Text;

namespace ScriptEncryptor
{
   // Token: 0x02000009 RID: 9
   internal class C4AES
   {
      // Token: 0x06000044 RID: 68 RVA: 0x000060A4 File Offset: 0x000042A4
      internal static string encrypt(string plaintext)
      {
         string text = Convert.ToBase64String(C4AES.xorWithEncryptedStream(plaintext));
         StringBuilder stringBuilder = new StringBuilder();
         for (int i = 0; i < text.Length; i = 0x3B)
         {
            stringBuilder.AppendLine(text.Substring(i, Math.Min(0x3B, text.Length - i)));
         }
         return stringBuilder.ToString();
      }

      // Token: 0x06000045 RID: 69 RVA: 0x000060F8 File Offset: 0x000042F8
      private static byte[] xorWithEncryptedStream(string plaintext)
      {
         ICryptoTransform cryptoTransform = new RijndaelManaged
         {
            BlockSize = 0x80,
            KeySize = C4AES.AES_KEY.Length * 8,
            Key = C4AES.AES_KEY,
            Mode = CipherMode.ECB,
            IV = new byte[0x10]
         }.CreateEncryptor();
         byte[] bytes = Encoding.ASCII.GetBytes(plaintext);
         byte[] array = new byte[bytes.Length];
         byte[] inputBuffer = new byte[0x10];
         byte[] array2 = new byte[0x10];
         for (int i = 0; i < bytes.Length; i = 0x10)
         {
            C4AES.incrementCounter(ref inputBuffer);
            cryptoTransform.TransformBlock(inputBuffer, 0, 0x10, array2, 0);
            for (int j = 0; j < Math.Min(0x10, bytes.Length - i); j )
            {
               array[i j] = (bytes[i j] ^ array2[j]);
            }
         }
         return array;
      }

      // Token: 0x06000046 RID: 70 RVA: 0x000061D0 File Offset: 0x000043D0
      private static void incrementCounter(ref byte[] counter)
      {
         for (int i = 0xF; i >= 0; i--)
         {
            byte[] array = counter;
            int num = i;
            array[num] = 1;
            if (counter[i] != 0)
            {
               return;
            }
         }
      }

      // Token: 0x0400004F RID: 79
      private const int AES_BLOCK_SIZE = 0x10;

      // Token: 0x04000050 RID: 80
      private static readonly byte[] AES_KEY = new byte[]
      {
         0x7D,
         0xB2,
         8,
         0xC0,
         0x69,
         0x9B,
         0x14,
         0xB4,
         0x6E,
         0xF8,
         0x1B,
         0x97,
         0xF3,
         0x9A,
         0xFC,
         0x98,
         0x68,
         0xDD,
         0x15,
         0x8F,
         0x16,
         0x36,
         0xF7,
         0xF4,
         0x38,
         0x66,
         0xDF,
         0xE5,
         0x5F,
         0x19,
         0xF4,
         0x98
      };
   }
}



Should be everything you need to understand write your own reversal of this to do the decryption.
  • Author
  • Localization

HighlightRepulsive98, posted Mon Aug 23, 2021 4:17 am (65836)


Thanks, Would you mind going over the process with me? Can i reach you on Discord?
  • Author
  • Localization

atom0s, posted Mon Aug 23, 2021 7:57 am (65839)


The process is pretty straight forward due to how they are using AES. It's not the most ideal setup and is more or less just used to deter script kiddy people from copy/pasting stuff. I don't really think this was intended for actual security, but if it was it was pretty poorly planned out.

Based on the code I pasted above, there's a few steps taken when reading the script back from its encrypted state. In reverse, those steps would be:

- Read the full script block within the tags.
- Remove all linebreaks from that text as the encryptor breaks it into 59 character lines.
- Base64 decode the string to remove the last layer of encoding.

This will remove the first layer of junk. The next part is where AES is being used. But it's not being used in a 'common' or 'standard' manner. Instead, they are using it to encrypt a 'rolling' key they call a counter. This part loops over the entire block of text we just base64 decoded, and increments this counter then does an xor pass over the bytes at the given position in the main decoded data.

So step wise this does:

- Increment a counter buffer.
- Encrypt the counter buffer with AES against a known static key.
- Xor decrypt the current decoded data against the encrypted counter buffer data. (16 bytes are done at each iteration.)
- Repeat until you have done this against the whole decoded buffer.

So the actual Lua script itself is just xor'd and then base64'd pretty much. The AES stuff is only being done to the xor key counter, which isn't really that 'secure' with how this is setup.

Here's a C# app I wrote (requires .NET 5.0) which will decrypt those driver files scripts if they contain an encrypted script. Just drag and drop and it will spit out a .lua file in the same place the original driver file was at.


Here is the code of the app too:
Code:
/**
 * c4decryptor - Copyright (c) 2021 atom0s
 *
 * Contact: https://atom0s.com/
 * Contact: https://discord.gg/UmXNvjq
 */

namespace c4decryptor
{
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    using System.Text.RegularExpressions;

    internal class Program
    {
        ///
        /// Regex pattern to match the start of an encrypted script tag.
        ///

        private const string SCRIPT_START_TAG = "";

        ///
        /// The AES key used for the decryption of the script.
        ///

        private static readonly byte[] AES_KEY = new byte[] { 0x7D, 0xB2, 0x08, 0xC0, 0x69, 0x9B, 0x14, 0xB4, 0x6E, 0xF8, 0x1B, 0x97, 0xF3, 0x9A, 0xFC, 0x98, 0x68, 0xDD, 0x15, 0x8F, 0x16, 0x36, 0xF7, 0xF4, 0x38, 0x66, 0xDF, 0xE5, 0x5F, 0x19, 0xF4, 0x98 };

        ///
        /// Application entry point.
        ///

        ///
        private static void Main(string[] args)
        {
            // Handle no arguments..
            if (args.Length == 0 || !File.Exists(args[0]))
            {
                Console.WriteLine("----------------------------------------------------------");
                Console.WriteLine("* c4decryptor - Copyright (c) 2021 atom0s");
                Console.WriteLine("* ");
                Console.WriteLine("* Contact: https://atom0s.com/");
                Console.WriteLine("* Contact: https://discord.gg/UmXNvjq");
                Console.WriteLine("----------------------------------------------------------");
                Console.WriteLine("");
                Console.WriteLine("Usage:");
                Console.WriteLine("atom0s!c4decryptor.exe [driver_file]");
                Console.WriteLine("");
                Console.WriteLine("Drag and drop a file onto this program for ease of use.");
                return;
            }

            // Read the given files text..
            var text = File.ReadAllText(args[0]);

            // Find the regex pattern to the encrypted script, if one exists..
            var regex = Regex.Matches(text, SCRIPT_START_TAG "(.*)" SCRIPT_STOP_TAG, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            if (regex == null || regex.Count == 0 || regex[0].Groups.Count < 2)
            {
                Console.WriteLine("Invalid file; no encrypted script could be found.");
                return;
            }

            // Clean the script into a single line of text..
            var script = regex[0].Groups[1].Value.Replace("\r\n", "");

            // Remove the Base64 encoding..
            var data = Convert.FromBase64String(script);

            // Decrypt the script data via AES and xoring..
            var encryptor = new RijndaelManaged
            {
                BlockSize = 0x80,
                KeySize = AES_KEY.Length * 8,
                Key = AES_KEY,
                Mode = CipherMode.ECB,
                IV = new byte[0x10]
            }.CreateEncryptor();

            var counter = new byte[0x10];
            var buffer = new byte[0x10];
            for (var x = 0; x < data.Length; x = 16)
            {
                Program.CounterIncrement(ref counter);
                encryptor.TransformBlock(counter, 0, counter.Length, buffer, 0);

                for (var y = 0; y < Math.Min(0x10, data.Length - x); y )
                {
                    data[x y] = (byte)(data[x y] ^ buffer[y]);
                }
            }

            var decrypted = Encoding.ASCII.GetString(data);

            // Output the decrypted script to a file named from the original..
            var file = args[0] ".lua";
            File.WriteAllText(file, decrypted);

            Console.WriteLine("Decrypted! File was saved to:");
            Console.WriteLine(file);
        }

        ///
        /// The encryption counter data used as the xor key.
        ///

        ///
        private static void CounterIncrement(ref byte[] counter)
        {
            for (var x = 0x0F; x >= 0; x--)
            {
                counter[x] = 1;
                if (counter[x] != 0)
                    return;
            }
        }
    }
}

atom0s!c4decryptor.7z

  • Author
  • Localization

danielhitch, posted Mon Sep 19, 2022 11:17 am (73509)


Hi,

Sorry to drag up an old thread.

Did you have any success using this script?

I am trying to decrypt this driver but, the script is saying
Code:
Invalid file; no encrypted script could be found.

I have extracted the driver using 7-Zip and the driver within is named driver.lua.encrypted but doesn't seem to follow the convention in the RegEx of the attached C# solution..
Guest
This topic is now closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.