Подтвердить что ты не робот

Получение текущего машинного ключа ASP.NET

Мне кажется, я хочу получить машинный ключ ASP.NET для текущего приложения. Это, конечно, легко, если машинный ключ указан в файле конфигурации, но если он настроен на автоматическое создание, то, похоже, не существует общедоступного метода для его получения.

В принципе, я хочу, чтобы я мог написать зашифрованный /MACed cookie для себя, как это делает поставщик ASP.NET Forms Authentication.

Есть ли у кого-нибудь указатели или идеи?

4b9b3361

Ответ 1

г. Любопытно было любопытно также получить машинный ключ. Свойства на MachineKeySection не являются хорошими, поскольку они получают обнуление после инициализации, которое происходит, прежде чем вы сможете их прочитать с отражением.

После небольшого копания в текущей структуре 4.5 получается, что автоматически сгенерированные ключи хранятся в массиве байтов HttpApplication.s_autogenKeys. Ключ проверки - первые 64 байта, за которым следует 24 байта ключа дешифрования.

Если вы не выбираете новый материал криптографии в структуре 4.5, то есть вы не установили <httpRuntime targetFramework="4.5"> в свой web.config (это случай, если у вас есть приложение, которое вы создали с предыдущей версией рамки), то вы добираетесь до таких клавиш:

        byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);

        int validationKeySize = 64;
        int decryptionKeySize = 24;

        byte[] validationKey = new byte[validationKeySize];
        byte[] decryptionKey = new byte[decryptionKeySize];

        Buffer.BlockCopy(autogenKeys, 0, validationKey, 0, validationKeySize);
        Buffer.BlockCopy(autogenKeys, validationKeySize, decryptionKey, 0, decryptionKeySize);

        // This is the IsolateApps bit, which is set for both keys
        int pathHash = StringComparer.InvariantCultureIgnoreCase.GetHashCode(HttpRuntime.AppDomainAppVirtualPath);
        validationKey[0] = (byte)(pathHash & 0xff);
        validationKey[1] = (byte)((pathHash & 0xff00) >> 8);
        validationKey[2] = (byte)((pathHash & 0xff0000) >> 16);
        validationKey[3] = (byte)((pathHash & 0xff000000) >> 24);

        decryptionKey[0] = (byte)(pathHash & 0xff);
        decryptionKey[1] = (byte)((pathHash & 0xff00) >> 8);
        decryptionKey[2] = (byte)((pathHash & 0xff0000) >> 16);
        decryptionKey[3] = (byte)((pathHash & 0xff000000) >> 24);

По умолчанию для обоих ключей есть AutoGenerate,IsolateApps; бит IsolateApps требует, чтобы вы скопировали первые четыре байта хэша пути приложения к началу ключа.

Если вы выбрали криптографические улучшения в fx4.5, вам придется копать MachineKeyMasterKeyProvider, чтобы получить действительные ключи.

Получение ключей без HttpApplication

HttpApplication получает свои ключи, вызывая собственный метод в webengine4.dll из SetAutogenKeys(). Мы также можем позвонить в DLL. Все, что нам нужно знать, это наш путь применения.

Скажем, что мы хотим получить автоматически сгенерированные ключи для корневого приложения "/".

Использование LinqPad:

[DllImport(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\webengine4.dll")]
internal static extern int EcbCallISAPI(IntPtr pECB, int iFunction, byte[] bufferIn, int sizeIn, byte[] bufferOut, int sizeOut);

void Main()
{
    string appPath = "/";
    byte[] genKeys = new byte[1024];
    byte[] autogenKeys = new byte[1024];

    int res = EcbCallISAPI(IntPtr.Zero, 4, genKeys, genKeys.Length, autogenKeys, autogenKeys.Length);

    if (res == 1) {
        // Same as above
        int validationKeySize = 64;
        int decryptionKeySize = 24;

        byte[] validationKey = new byte[validationKeySize];
        byte[] decryptionKey = new byte[decryptionKeySize];

        Buffer.BlockCopy(autogenKeys, 0, validationKey, 0, validationKeySize);
        Buffer.BlockCopy(autogenKeys, validationKeySize, decryptionKey, 0, decryptionKeySize);

        int pathHash = StringComparer.InvariantCultureIgnoreCase.GetHashCode(appPath);
        validationKey[0] = (byte)(pathHash & 0xff);
        validationKey[1] = (byte)((pathHash & 0xff00) >> 8);
        validationKey[2] = (byte)((pathHash & 0xff0000) >> 16);
        validationKey[3] = (byte)((pathHash & 0xff000000) >> 24);

        decryptionKey[0] = (byte)(pathHash & 0xff);
        decryptionKey[1] = (byte)((pathHash & 0xff00) >> 8);
        decryptionKey[2] = (byte)((pathHash & 0xff0000) >> 16);
        decryptionKey[3] = (byte)((pathHash & 0xff000000) >> 24);

        Console.WriteLine("DecryptionKey: {0}", decryptionKey.Aggregate(new StringBuilder(), (acc, c) => acc.AppendFormat("{0:x2}", c), acc => acc.ToString()));
        Console.WriteLine("ValidationKey: {0}", validationKey.Aggregate(new StringBuilder(), (acc, c) => acc.AppendFormat("{0:x2}", c), acc => acc.ToString()));
    }
}

Получение ключей от MachineKeyMasterKeyProvider

Ключи для нового материала fx4.5 доступны путем создания экземпляра MachineKeyMasterKeyProvider с помощью внутреннего конструктора , а затем передачи autogenKeys байт, полученный как в приведенном выше коде. Поставщик имеет методы GetEncryptionKey и GetValidationKey, чтобы перейти к фактическим клавишам.

Ответ 2

Если вы используете .NET 4, то MachineKey класс. Он не дает вам сырой доступ к фактическому ключу, но он предоставляет методы для кодирования и декодирования данных с использованием тех же алгоритмов, что и класс FormsAuthentication, а также варианты добавления проверки с помощью HMAC.

Ответ 4

Спасибо г-ну Любому,

на основе ваших указателей я получил следующее:

private byte[] _validationKey;
private byte[] _decryptionKey;

public static byte[] GetKey(object provider, string name)
{
  var validationKey = provider.GetType().GetMethod(name).Invoke(provider, new object[0]);
  return (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(validationKey, new object[0]);
}

protected override void OnLoad(EventArgs e)
{
    var machineKey = typeof(MachineKeySection).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single(a => a.Name == "GetApplicationConfig").Invoke(null, new object[0]);

    var type = Assembly.Load("System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").GetTypes().Single(a => a.Name == "MachineKeyMasterKeyProvider");

    var instance = type.Assembly.CreateInstance(
        type.FullName, false,
        BindingFlags.Instance | BindingFlags.NonPublic,
        null, new object[] { machineKey, null, null, null, null }, null, null);

    var validationKey = type.GetMethod("GetValidationKey").Invoke(instance, new object[0]);
    var key = (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(validationKey, new object[0]);


    _validationKey = GetKey(instance, "GetValidationKey");
    _decryptionKey = GetKey(instance, "GetEncryptionKey");
}

Ответ 5

Добавьте следующую конфигурационную информацию в файл web.config. Убедитесь, что вы заменили информацию своей собственной информацией.

<system.web>
<machineKey validationKey="E4451576F51E0562D91A1748DF7AB3027FEF3C2CCAC46D756C833E1AF20C7BAEFFACF97C7081ADA4648918E0B56BF27D1699A6EB2D9B6967A562CAD14767F163" 
            decryptionKey="6159C46C9E288028ED26F5A65CED7317A83CB3485DE8C592" validation="HMACSHA256" decryption="AES" />
</system.web>

validationkey и decryptionkey, проверка и дешифрование должны зависеть от вашего сервера и протокола.

Ответ 6

Для .Net 4.5 здесь приведен код

//using System.Reflection
//using System.Web.Configuration

byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);

Type t = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.MachineKeyMasterKeyProvider");
ConstructorInfo ctor = t.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];

Type ckey = typeof(System.Web.Security.DefaultAuthenticationEventArgs).Assembly.GetType("System.Web.Security.Cryptography.CryptographicKey");
ConstructorInfo ckeyCtor = ckey.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
Object ckeyobj = ckeyCtor.Invoke(new object[] { autogenKeys });
object o = ctor.Invoke(new object[] { new MachineKeySection(), null, null, ckeyobj, null });
var encKey = t.GetMethod("GetEncryptionKey").Invoke(o, null);
byte[] encBytes = ckey.GetMethod("GetKeyMaterial").Invoke(encKey, null) as byte[];
var vldKey = t.GetMethod("GetValidationKey").Invoke(o, null);
byte[] vldBytes = ckey.GetMethod("GetKeyMaterial").Invoke(vldKey, null) as byte[];
string decryptionKey = BitConverter.ToString(encBytes);
decryptionKey = decryptionKey.Replace("-", "");
string validationKey = BitConverter.ToString(vldBytes);
validationKey = validationKey.Replace("-", "");

Ответ 7

Вам действительно нужен ключ? Или просто для шифрования и дешифрования данных?

System.Web.Security.FormsAuthentication(.NET 2.0) имеет общедоступные методы шифрования/дешифрования. Они используют System.Web.Configuration.MachineKeySection EncryptOrDecryptData, ByteArrayToHexString и HexStringToByteArray для шифрования и дешифрования данных.

EncryptOrDecryptData обрабатывает загрузку/настройку данных ключа из конфигурационных файлов /AutoGenerate по мере необходимости.

Шифрование и расшифровка должны быть доступны через загрузку исходного кода или отражатель и легко конвертированы в вашу цель.

Ответ 8

У меня была такая же проблема, и мне нужно было получить машинный ключ из работающего веб-приложения (не используя функции криптографии .NET 4.5), из-за которого я не мог изменить код, поэтому я создал простой .aspx файл, который извлекает ключ и выгружает его в файл, а затем помещает его в корневой каталог приложения и получает доступ к нему с помощью браузера (без необходимости касаться запущенного приложения).

<%@ Page Language="C#"
var runTimeType = typeof(System.Web.HttpRuntime);
var autogenKeysField = runTimeType.GetField("s_autogenKeys", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
var autogenKeys = (byte[])autogenKeysField.GetValue(null);
var machineKeySection = new System.Web.Configuration.MachineKeySection();

var autogenKeyProperty = typeof(System.Web.Configuration.MachineKeySection).GetProperty("AutogenKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var decryptionKeyField = typeof(System.Web.Configuration.MachineKeySection).GetField("_DecryptionKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var validationKeyField = typeof(System.Web.Configuration.MachineKeySection).GetField("_ValidationKey", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

// This needs to be done to make machineKeySection refresh it data
var touch = (bool)autogenKeyProperty.GetValue(machineKeySection);
var decryptionKey = (byte[])decryptionKeyField.GetValue(machineKeySection);
var validationKey = (byte[])validationKeyField.GetValue(machineKeySection);

var autogenKeyString = BitConverter.ToString(autogenKeys).Replace("-", string.Empty);
var encryptionKeyString = BitConverter.ToString(decryptionKey).Replace("-", string.Empty);
var validationKeyString = BitConverter.ToString(validationKey).Replace("-", string.Empty);

using (var writer = new System.IO.StreamWriter("c:/somewhere/withwriteaccess/MachineKey.config")) {
    writer.Write(string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<machineKey decryptionKey=\"{0}\" validationKey=\"{1}\" />", encryptionKeyString, validationKeyString));
}
%>