想法是我有4个字节[512]数组,我从C#中获取密钥,并用AES256加密一些信息。比我的同事,使用完全相同的4字节数组,使用相同的密钥派生过程,解密消息。
除了首先,它投掷"不良数据" C ++中的异常,与我不同的是可以预料,C#中的加密输出每次都不同。为什么会这样?
常量:
const uint ALG_CLASS_DATA_ENCRYPT = (3 << 13);
const uint ALG_TYPE_BLOCK = (3 << 9);
const uint ALG_SID_AES_256 = 16;
const uint CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256);
const uint KEYLENGTH = 0x01000000;
const uint CRYPT_EXPORTABLE = 0x00000001;
const uint ALG_CLASS_HASH = (4 << 13);
const uint ALG_TYPE_ANY = 0;
const uint ALG_SID_SHA_256 = 12;
const uint CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256);
const uint ENCRYPT_HASH_ALG = CALG_SHA_256;
const uint PROV_RSA_AES = 24;
const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
const string MS_ENH_RSA_AES_PROV = @"Microsoft Enhanced RSA and AES Cryptographic Provider";
const uint CRYPT_MODE_CBC = 1;
const uint KP_MODE = 4;
const uint KP_IV = 1;
我的代码:
IntPtr _hProv = new IntPtr();
IntPtr _phHash = new IntPtr();
IntPtr _phKey = new IntPtr();
bool result = CryptAcquireContext(ref _hProv, null, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
result = CryptCreateHash(_hProv, ENCRYPT_HASH_ALG, IntPtr.Zero, 0, ref _phHash);
byte[] bbb = new ASCIIEncoding().GetBytes("Test hash!");
result = CryptHashData(_phHash, bbb, (uint)bbb.Length, 0);
result = CryptDeriveKey(_hProv, CALG_AES_256, _phHash, KEYLENGTH, ref _phKey);
byte[] cryptMode = BitConverter.GetBytes(CRYPT_MODE_CBC);
result = SetXKeyParamKey(_phKey, KP_MODE, cryptMode);
byte[] ivBuff = new byte[16]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
result = SetXKeyParamKey(_phKey, KP_IV, ivBuff);
uint lenght = (uint)data.Length;
byte[] cln = new byte[data.Length + 128];
Array.Copy(data, cln, data.Length);
result = CryptEncrypt(_phKey, IntPtr.Zero, 1, 0, cln, ref lenght, (uint)(cln.Length + 128));
data = new byte[lenght];
Array.Copy(cln, data, lenght);
result = CryptReleaseContext(_hProv, 0);
return lenght;
签名:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, UInt32 dwProvType, UInt32 dwFlags);
[DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); //dwFlags Reserved. Must be 0.
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptCreateHash(IntPtr hProv, uint algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDeriveKey(IntPtr hProv, uint Algid, IntPtr hBaseData, uint flags, ref IntPtr phKey);
[DllImport(@"advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptEncrypt(IntPtr hKey, IntPtr hHash, int Final, uint dwFlags, byte[] pbData, ref uint pdwDataLen, uint dwBufLen);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam, [Out] IntPtr pbData, [In, Out] uint pdwDataLen, uint dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptSetKeyParam(IntPtr Key, uint Param, IntPtr Data, uint Flags);
private static bool SetXKeyParamKey(IntPtr Key, uint KeyParam, byte[] Data)
{
bool Result = false;
if (Data == null) // special case, e.g. for KP_X
{
Result = CryptSetKeyParam(Key, KeyParam, IntPtr.Zero, 0);
return Result;
}
IntPtr holder = Marshal.AllocHGlobal(12); // the same as DATA_BLOB
Marshal.WriteInt32(holder, 0, Data.Length); // first 4 bytes is the length of the buffer
IntPtr buffPtr = Marshal.AllocHGlobal(Data.Length); // ptr to buffer
Marshal.Copy(Data, 0, buffPtr, Data.Length); // copy real data to a newly-allocated buffer
Marshal.WriteInt64(holder, 4, (Int64)buffPtr); // holder now contains both size and ptr; assume that ptr takes 4 bytes
Result = CryptSetKeyParam(Key, KeyParam, holder, 0); // instead of real buffer, we must pass the holder
Marshal.FreeHGlobal(buffPtr); Marshal.FreeHGlobal(holder);
return Result;
}