Сравните хэши паролей между C# и ColdFusion (CFMX_COMPAT)

У меня есть хэш пароля, который хранится в таблице и помещается туда с помощью следующего сценария coldfusion:

#Hash(Encrypt(Form.UserPassword,GetSiteVars.EnCode))#

Я пытаюсь добавить некоторые внешние функции в приложение С#. Я хотел бы иметь возможность использовать уже существующие данные, чтобы я мог аутентифицировать пользователей. Кто-нибудь знает, как я могу воспроизвести приведенный выше код coldfusion на С#?

Спасибо за любые мысли.


person czuroski    schedule 26.04.2010    source источник
comment
Какой алгоритм шифрования он использует?   -  person SLaks    schedule 26.04.2010
comment
Ниже приведен код CFMX_Compat из проекта Railo, портированного на C#.   -  person Seibar    schedule 07.01.2011


Ответы (5)


Я оставлю исходный ответ ниже для исторической справки, но следует отметить, что это НЕ рабочий ответ на исходный вопрос.

Вместо этого посмотрите ответ @Terrapin, получивший наибольшее количество голосов, в этой теме в январе 2011 года. Я надеюсь, что ОП увидит это и сможет изменить принятый ответ. Черт, я даже отмечу моды, чтобы посмотреть, можно ли что-нибудь с этим поделать.


Чтобы основываться на ответе Эдварда Смита и последующих комментариях czuroski, вот мое решение.

Во-первых, вам нужна функция XOR в C#, которую я взял из здесь и немного изменен.

using System;
using System.Collections.Generic;
using System.Text;

namespace SimpleXOREncryption
{    
    public static class EncryptorDecryptor
    {
        public static string EncryptDecrypt(string textToEncrypt, int key)
        {            
            StringBuilder inSb = new StringBuilder(textToEncrypt);
            StringBuilder outSb = new StringBuilder(textToEncrypt.Length);
            char c;
            for (int i = 0; i < textToEncrypt.Length; i++)
            {
                c = inSb[i];
                c = (char)(c ^ key);
                outSb.Append(c);
            }
            return outSb.ToString();
        }   
    }
}

Затем возьмите результат XOR и закодируйте его в base-64. Получив эту строку, хешируйте ее с помощью MD5. Результат должен соответствовать результату исходного фрагмента кода:

#Hash(Encrypt(Form.UserPassword,GetSiteVars.EnCode))#
person Adam Tuttle    schedule 27.04.2010
comment
Спасибо - я пробовал это, но это все еще не работает. На самом деле ключ, который у меня есть, на самом деле является строкой, а не целым числом, поэтому я не знаю, отбрасывает ли это его или мне нужно использовать ключ для кодировки base-64. чтобы закодировать его в base-64, могу ли я просто использовать Convert.ToBase64String или нет? - person czuroski; 28.04.2010
comment
Согласно документам, переданная строка используется в качестве случайного начального числа для создания целочисленного значения ключа. К сожалению, у меня нет больше информации о том, как именно он получает это значение. Если бы я был на вашем месте, я бы рассмотрел (1) удаление шифрования из существующих паролей (достаточно просто с помощью одноразового скрипта) и (2) переписывание существующего кода CF, чтобы больше не использовать шифрование. Хеширования достаточно, и, на мой взгляд, шифрование в этом случае тратит процессор впустую. - person Adam Tuttle; 28.04.2010
comment
да, я согласен с тем, что процессор тратится впустую, но это предполагаемое приложение, и я не могу изменить это прямо сейчас. Поэтому я должен попытаться расшифровать его самостоятельно, но безуспешно. - person czuroski; 28.04.2010
comment
Если вам действительно нужно это сделать, взгляните на исходный код Railo (и информацию о лицензировании). Он имеет алгоритм CFMX_COMPAT, который вы можете перенести на C #. - person Leigh; 29.04.2010
comment
Для всех, кто читает, я отправил электронное письмо с czuroski в автономном режиме, и мы действительно получили порт C# классов Railo. - person Leigh; 19.05.2010
comment
Как сказал Ли выше, он смог помочь мне успешно запустить порт классов Railo. - person czuroski; 28.05.2010

Я просмотрел код Railo, как кто-то еще здесь упомянул в комментариях.

Ниже приведен порт CFMX_Compat на C# из исходного кода Railo Java. Ниже приведен пример использования.

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);
        }
    }
}

Вот пример использования, который Hex-кодирует зашифрованный текст, а затем расшифровывает то же самое.

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);
person Seibar    schedule 07.01.2011
comment
Этот порт C# кода Railo является реальным рабочим алгоритмом, который сопоставляется с CF Encrypt/Decrypt с использованием CFMX_COMPAT. Другие предоставленные алгоритмы на основе XOR (хотя и правильные в своем собственном контексте) несовместимы с шифрованием/дешифрованием ColdFusion. Это версия, которую вы захотите использовать. - person Shawn Holmes; 25.05.2012
comment
А как выглядит ваш метод HexToBytes? - person Wekerle Tibor; 03.08.2018

MD5 — это алгоритм хеширования по умолчанию для hash(). Я не программист на C#, но создать хэш MD5 для сравнения с результатом ColdFusion не составит труда.

Что касается encrypt(), есть ли причина, по которой вы шифруете имя пользователя перед его хешированием? Я не могу придумать никакой выгоды от этого, но это не значит, что ее нет. Я бы просто сделал:

Hash( UCase( GetPass.username ) )

Что должно быть легче воспроизвести на С#.

person mwcz    schedule 26.04.2010
comment
Я согласен, шифрование тривиально, в лучшем случае. - person Ian P; 26.04.2010
comment
Но его данные уже включают это, поэтому он ищет ответ, где он может использовать уже зашифрованные данные. - person Edward M Smith; 26.04.2010
comment
да - данные уже есть, так что я просто пытаюсь их использовать. - person czuroski; 26.04.2010

Одним из решений было бы, чтобы БД выполняла хэширование и шифрование, может быть проще...

person intnick    schedule 26.04.2010
comment
да - было бы проще. к сожалению, я не писал первоначальное приложение и не хочу его менять. - person czuroski; 26.04.2010

«Шифрование» по умолчанию в CF — это просто XOR:

зашифрованный текст = base64_encode (открытый текст ^ ключ)

Итак, для расшифровки:

открытый текст = base64_decode (зашифрованный текст) ^ ключ

Хэш по умолчанию, как уже упоминалось, — md5.

Редактировать:

Что ж, дальнейшие исследования показывают, что это неправда — это всего лишь один из широко распространенных мифов.

Я не могу найти никакой документации по фактическому алгоритму для метода шифрования CFMX_COMPAT.

Извините за погоню за дикими гусями.

person Edward M Smith    schedule 26.04.2010
comment
Я предполагаю, что все сводится к значению переменной EnCode. - person mwcz; 26.04.2010
comment
Правильно, это просто ключ. Я уверен, что у ОП есть доступ к нему в исходном коде CF. - person Edward M Smith; 26.04.2010
comment
Кажется, я не могу заставить это совпадать. Я попытался сузить его на тестовой странице CF, чтобы просто выполнить шифрование (и игнорировать хэш), но я все еще не могу заставить зашифрованное значение CF соответствовать моему зашифрованному значению С#. Я использовал прямое шифрование base64 в своем приложении С#. Я где-то видел, что CF также выполняет uuencode как часть шифрования — правда ли это? - person czuroski; 27.04.2010
comment
Вы выполняете XOR в C# и не получаете того же результата? - person Edward M Smith; 27.04.2010