我有一个使用 Crypto API 生成 RC4 加密密钥的非托管应用程序。此非托管应用程序使用此 RC4 密钥加密某些数据。还有一个客户端非托管应用程序使用此 RC4 密钥来解密信息。
但是,对于这个客户端应用程序,我们正在发送一个会话密钥 -> 使用在客户端生成的 RSA 公钥(SIMPLEBLOB)加密的 RC4 密钥。加密会话密钥的生成过去是使用非托管代码完成的,但现在必须将其转换为 C#,因为需要在部分信任下从 Web 应用程序运行此代码。
密钥是使用生成的
CryptGenKey(hProv, CALG_RC4, KEY_LENGTH | CRYPT_EXPORTABLE, &hKey);
它被导出到文件系统使用
CryptExportKey(hKey, 0, OPAQUEKEYBLOB, 0, lpBuffer, &nSize);
(注意我能够使用这篇文章 http://www.codeproject.com/KB/security/plaintextsessionkey.aspx导出纯文本密钥)
客户端公钥是使用创建的
CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKeyPair);
使用导出客户端公钥
CryptExportKey(hKeyPair, 0, PUBLICKEYBLOB, 0, lpData, &nSize);
会话密钥是在服务器端使用创建的
客户端公钥是使用导入的
CryptImportKey(hProv, lpData, nSize, NULL, 0, &hPublicKey
会话密钥是通过使用客户端公钥加密 RC4 生成 SIMPLEBOB 格式来生成的
CryptExportKey(hKey, hPublicKey, SIMPLEBOB, 0, lpData, &nSize);
现在我的要求是在托管版本中执行上述步骤(步骤 1 和 2),这就是我正在做的事情:
//读取使用代码项目文章提取的纯文本密钥数据 byte[] keyMaterial = File.ReadAllBytes(@"C:\keyMaterial.txt");
// 导入客户端公钥
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "Container Name";
cspParams.KeyNumber = (int)KeyNumber.Exchange;
cspParams.ProviderType = 1;
cspParams.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider rsaClient = new RSACryptoServiceProvider(cspParams);
rsaClient.ImportCspBlob(File.ReadAllBytes(@"C:\client.key"));
//Generate a SIMPLEBLOB session key
byte[] session = GetRC4SessionBlobFromKey(keyMaterial, rsaClient);
//Encrypt a key using public key and write it in a SIMPLEBLOB format
public byte[] GetRC4SessionBlobFromKey(byte[] keyData, RSACryptoServiceProvider publicKey)
{
using(MemoryStream ms = new MemoryStream())
using(BinaryWriter w = new BinaryWriter(ms))
{
w.Write((byte) 0x01); // SIMPLEBLOB
w.Write((byte) 0x02); // Version 2
w.Write((byte) 0x00); // Reserved
w.Write((byte) 0x00); // Reserved
w.Write(0x00006801); // ALG_ID = RC4 for the encrypted key.
w.Write(0x0000a400); // CALG_RSA_KEYX
w.Write(publicKey.Encrypt(keyData, false));
w.Flush();
return ms.ToArray();
}
}
这会生成与其非托管版本相同大小的数据,但它不会像非托管版本的第 1 步和第 2 步那样生成正确的 SIMPLEBLOB 会话密钥。我在这段代码中做错了什么?