我正在尝试手动解密使用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();
}
}
}
}
}
}
答案 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(以位为单位)。