手动解密使用MachineKey.Protect加密的数据

时间:2016-02-10 20:21:06

标签: c# asp.net .net iis encryption

我正在尝试手动解密使用MachineKey.Protect()加密的数据。我正在使用AES和SHA1算法。

        // unencrypted input in HEX: 010203
        // AES key in HEX: CCA0DC9874B3F9E679E0A576F77EDF9B121CAB2F9A363A4EAF99976F7B51FA89
        // want to decrypt this: A738E5F98920E37AB14C5F4332D4C7F0EC683680AAA0D34B806E75DECF04B7A3DB651E688B563F77BA107FB15990C88FB8023386

这是一个例子。

        // Some input data
        var input = new byte[] { 1, 2, 3 };

        // this just works fine
        var protectedData = System.Web.Security.MachineKey.Protect(input, "ApplicationCookie", "v1");

        // protectedData  in hex: A738E5F98920E37AB14C5F4332D4C7F0EC683680AAA0D34B806E75DECF04B7A3DB651E688B563F77BA107FB15990C88FB8023386

        // works
        var unprotectedInput = System.Web.Security.MachineKey.Unprotect(protectedData, "ApplicationCookie", "v1");

        // now lets do it manually
        // in web.config machineKey is configured: AES and SHA1

        var algorithm = new AesManaged();
        algorithm.Padding = PaddingMode.PKCS7;
        algorithm.Mode = CipherMode.CBC;
        algorithm.KeySize = 256;
        algorithm.BlockSize = 128;
        var validationAlgorithm = new HMACSHA1();

        // this is the key from web.config
        var key = HexToBinary("CCA0DC9874B3F9E679E0A576F77EDF9B121CAB2F9A363A4EAF99976F7B51FA89");

        using (SymmetricAlgorithm encryptionAlgorithm = algorithm)
        {
            encryptionAlgorithm.Key = key;
            int offset = encryptionAlgorithm.BlockSize / 8; //16
            int buffer1Count = validationAlgorithm.HashSize / 8; // 20
            int count = checked(protectedData.Length - offset - buffer1Count); // 16
            byte[] numArray = new byte[offset];
            Buffer.BlockCopy((Array)protectedData, 0, (Array)numArray, 0, numArray.Length);
            encryptionAlgorithm.IV = numArray; // in HEX: A738E5F98920E37AB14C5F4332D4C7F0
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (ICryptoTransform decryptor = encryptionAlgorithm.CreateDecryptor())
                {
                    using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(protectedData, offset, count);

                        // Padding is invalid and cannot be removed.
                        cryptoStream.FlushFinalBlock();
                        var result = memoryStream.ToArray();
                    }
                }
            }
        }

我收到异常(填充不对)。

我不知道还有什么可以尝试...

这是MachineKey.Protect的代码,https://msdn.microsoft.com/cs-cz/library/system.web.security.machinekey.protect(v=vs.110).aspx

    public byte[] Protect(byte[] clearData)
    {
      // this is AESManaged
      using (SymmetricAlgorithm encryptionAlgorithm = this._cryptoAlgorithmFactory.GetEncryptionAlgorithm())
      {
        // this is our key
        encryptionAlgorithm.Key = this._encryptionKey.GetKeyMaterial();
        if (this._predictableIV)
          encryptionAlgorithm.IV = CryptoUtil.CreatePredictableIV(clearData, encryptionAlgorithm.BlockSize);
        else
          encryptionAlgorithm.GenerateIV();
        byte[] iv = encryptionAlgorithm.IV;
        using (MemoryStream memoryStream = new MemoryStream())
        {
          memoryStream.Write(iv, 0, iv.Length);
          using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor())
          {
            using (CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, encryptor, CryptoStreamMode.Write))
            {
              cryptoStream.Write(clearData, 0, clearData.Length);
              cryptoStream.FlushFinalBlock();
              using (KeyedHashAlgorithm validationAlgorithm = this._cryptoAlgorithmFactory.GetValidationAlgorithm())
              {
                validationAlgorithm.Key = this._validationKey.GetKeyMaterial();
                byte[] hash = validationAlgorithm.ComputeHash(memoryStream.GetBuffer(), 0, checked ((int) memoryStream.Length));
                memoryStream.Write(hash, 0, hash.Length);
                return memoryStream.ToArray();
              }
            }
          }
        }
      }
    }

1 个答案:

答案 0 :(得分:0)

解密密钥错误。

MachineKey.Protect / UnProtect()在使用之前修改密钥。

它正在做这样的事情:

            public static byte[] DeriveKey(byte[] key, int keySize, string primaryPurpose, params string[] specificPurposes)
            {
                var secureUtf8Encoding = new UTF8Encoding(false, true);
                var hash = new HMACSHA512(key);

                using (hash)
                {
                    var label = secureUtf8Encoding.GetBytes(primaryPurpose);

                    byte[] context;

                    using (var memoryStream = new MemoryStream())
                    {
                        using (var binaryWriter = new BinaryWriter(memoryStream, secureUtf8Encoding))
                        {
                            foreach (var str in specificPurposes)
                                binaryWriter.Write(str);
                            context = memoryStream.ToArray();
                        }
                    }

                    return DeriveKeyImpl(hash, label, context, keySize);
                }
            }

            public static byte[] DeriveKeyImpl(HMAC hmac, byte[] label, byte[] context, int keyLengthInBits)
            {
                int count1 = label != null ? label.Length : 0;
                int count2 = context != null ? context.Length : 0;
                byte[] buffer = new byte[checked(4 + count1 + 1 + count2 + 4)];
                if (count1 != 0)
                    Buffer.BlockCopy((Array)label, 0, (Array)buffer, 4, count1);
                if (count2 != 0)
                    Buffer.BlockCopy((Array)context, 0, (Array)buffer, checked(5 + count1), count2);
                WriteUInt32ToByteArrayBigEndian(checked((uint)keyLengthInBits), buffer, checked(5 + count1 + count2));
                int dstOffset = 0;
                int val1 = keyLengthInBits / 8;
                byte[] numArray = new byte[val1];
                uint num = 1;
                while (val1 > 0)
                {
                    WriteUInt32ToByteArrayBigEndian(num, buffer, 0);
                    byte[] hash = hmac.ComputeHash(buffer);
                    int count3 = Math.Min(val1, hash.Length);
                    Buffer.BlockCopy((Array)hash, 0, (Array)numArray, dstOffset, count3);
                    checked { dstOffset += count3; }
                    checked { val1 -= count3; }
                    checked { ++num; }
                }
                return numArray;
            }

指定正确的目的非常重要。对于标准的MachineKey.Protect,主要原因是" User.MachineKey.Protect"。此示例的密钥大小为256(以位为单位)。