我尝试在 C# 中使用 Rijndael 加密一个字符串 (json) 并提出一个字符串,我可以将其提供给 PHP Web 服务。该 Web 服务反过来使用 IV 和主密钥(他们知道)对字符串进行解码。我必须编写可以与 PHP 服务对话的 C# 代码,我不控制/拥有 PHP 服务。
加密的PHP代码如下:
function encrypt($plaintext) {
$masterkey = 'masterKeyOfLength29Characters';
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $masterkey, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
return base64_encode($iv.$crypttext);
}
$param = array("key" => "value");
$encryptedString = rawurlencode(encrypt(json_encode($param)))
我必须将上面的代码转换为 C#,这样我才能加密我的 JSON 并将其提供给 PHP Web 服务。
有两个问题。第一个是主密钥长度,第二个(可能相关)是加密数据的 rawurlencode(我现在很难测试)。
var masterkey = "masterKeyOfLength29Characters";
var data = EncryptData(json, masterkey);
// Some code to URL Encode the data, I haven't gotten as far to test this
// since I can't encrypt with the key used in PHP, so I can't call the service
// to test the encoded string from my C# code.
data = HttpUtility.UrlEncode(data);
data = data.Replace("+", "%20");
public static string EncryptData(string json, string encryptionKey) {
Rijndael rj = Rijndael.Create();
rj.Mode = CipherMode.CBC;
rj.Padding = PaddingMode.PKCS7;
rj.BlockSize = 256;
rj.KeySize = 256;
rj.Key = Encoding.UTF8.GetBytes(encryptionKey); // ERROR here
rj.GenerateIV();
var encryptedJSON = EncryptStringToBytes(json, rj.Key, rj.IV);
var r1 = Convert.ToBase64String(rj.IV);
var r2 = Convert.ToBase64String(encryptedJSON);
return r1 + r2;
}
EncryptStringToBytes 进行一些检查并使用此代码(摘自互联网上的许多示例):
using (Rijndael rijAlg = Rijndael.Create()) {
// Basically I do the same here as above, and I could also generate
// the IV here, but then I'd had to return it too. I know I can clean this
// code up quite a bit, but I'd rather focus on getting it to work first ;)
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.BlockSize = 256;
rijAlg.KeySize = 256;
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream()) {
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
我会得到的错误:
Specified key is not a valid size for this algorithm.
所以,简而言之,问题是:
1) 为什么 PHP 代码在 Rijndael 256(CBC 模式)中接受长度为 29 的密钥,而我的 C# 不接受?我玩过模式,后来添加了填充,设置了 KeySize(已经是 256 默认值),我只是看不出我在这里做错了什么。
2)当我使用长度为 32 的密钥时,这个密钥被接受并且我的代码有效。我也可以在 C# 中解密它(但不能在 PHP 中测试它)。我想解决问题1,然后继续解决问题2,但也许有人可以在这里给我一些理解。加密的字符串在 IV 中包含 1 个“=”,在加密的 json 中包含 2 个“==”(在末尾)。我已经阅读了有关填充等的信息,但我想知道为什么在我收到的 PHP 示例中看不到“=”符号。同样,也许在解决问题 1 之后,这将不是问题。
非常感谢您的阅读,我希望我在这里不会太愚蠢。经过昨天一天的尝试,我感觉我尝试了许多不同的方法,但似乎都不起作用。