Silverlight 4.0 在Silverlight中使用RijndaelManaged加密

Silverlight 4.0 在Silverlight中使用RijndaelManaged加密,silverlight-4.0,cryptography,rijndaelmanaged,webservices-client,aes,Silverlight 4.0,Cryptography,Rijndaelmanaged,Webservices Client,Aes,我正在实现一个webservice客户端,它需要使用128位Rijndael加密请求。由于Silverlight中不存在RijndaelManaged类,因此我遵循以下建议: 这里讨论了这一点: 结果是,我得到的结果是正确的,我的意思是,我使用RijndaelManaged得到的结果是一样的,只针对前32个字符128位,正好是块大小。我搞不清楚我做错了什么。我的.Net实现RijndaelManaged如下所示: private static byte[] Encrypt(byte[] Plai

我正在实现一个webservice客户端,它需要使用128位Rijndael加密请求。由于Silverlight中不存在RijndaelManaged类,因此我遵循以下建议: 这里讨论了这一点:

结果是,我得到的结果是正确的,我的意思是,我使用RijndaelManaged得到的结果是一样的,只针对前32个字符128位,正好是块大小。我搞不清楚我做错了什么。我的.Net实现RijndaelManaged如下所示:

private static byte[] Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
{
    byte[] InitialVectorBytes = Encoding.UTF8.GetBytes(InitialVector);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.ECB;
    SymmetricKey.Padding = PaddingMode.PKCS7;
    SymmetricKey.BlockSize = 128;
    ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream();
    CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
    CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
    CryptoStream.FlushFinalBlock();
    byte[] CipherTextBytes = MemStream.ToArray();
    MemStream.Close();
    CryptoStream.Close();

    return CipherTextBytes;
}
而我的Silverlight是:

private string Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
{
    AesManaged SymmetricKey = new AesManaged();
    byte[] InitialVectorBytes = SymmetricKey.IV;
    //NOTE- because Mode and Padding don't exist in AESManaged for Silverlight, I have to do the padding myself
    //for an empty InitalVector (which is my case)
    for (int i = 0; i < InitialVectorBytes.Length; i++) InitialVectorBytes[i] = 0;
    SymmetricKey.BlockSize = 128;
    ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream();
    CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
    CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
    CryptoStream.FlushFinalBlock();
    byte[] CipherTextBytes = MemStream.ToArray();
    MemStream.Close();
    CryptoStream.Close();

    return CipherTextBytes;
}

不清楚您是否真的在清除IV。您是将其作为字节数组获取,然后清除它,但我不确定IV属性在返回它之前是否复制了内部值。我会用这个:

SymmetricKey.BlockSize = 128;
SymmetricKey.IV = new byte[SymmetricKey.BlockSize / 8];
顺便说一下,我也不再对参数和局部变量使用PascalCase了。通常的惯例是对非常量变量使用camelCase

编辑:示例代码,演示您的代码如何不真正改变IV:

AesManaged aes = new AesManaged();
byte[] iv = aes.IV;
iv[0] = 1;
iv[1] = 2;
Console.WriteLine(BitConverter.ToString(iv));      
Console.WriteLine(BitConverter.ToString(aes.IV));
样本输出:

01-02-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B
D8-48-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B

换言之,更改数组中的值并不是真正更改IV。

不清楚您是否真的在清除IV。您将其作为字节数组获取,然后清除它,但我不确定IV属性是否在返回内部值之前复制了内部值。我会用这个:

SymmetricKey.BlockSize = 128;
SymmetricKey.IV = new byte[SymmetricKey.BlockSize / 8];
顺便说一下,我也不再对参数和局部变量使用PascalCase了。通常的惯例是对非常量变量使用camelCase

编辑:示例代码,演示您的代码如何不真正改变IV:

AesManaged aes = new AesManaged();
byte[] iv = aes.IV;
iv[0] = 1;
iv[1] = 2;
Console.WriteLine(BitConverter.ToString(iv));      
Console.WriteLine(BitConverter.ToString(aes.IV));
样本输出:

01-02-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B
D8-48-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B

换句话说,更改数组中的值并不能真正改变IV。

您的.NET版本对AES使用EBC模式,而Silverlight版本使用CBC模式。第一个输出块在两个版本中都是相同的,因为在ECB模式下不使用初始化向量,而在CBC模式下,初始化向量为零。在CBC模式下,每个块与前一个块异或,第一个块与初始化向量异或,然后加密,而在EBC模式下,每个块按原样加密。

您的.NET版本对AES使用EBC模式,而Silverlight版本使用CBC。第一个输出块在两个版本中都是相同的,因为在ECB模式下不使用初始化向量,而在CBC模式下,初始化向量为零。在CBC模式下,每个块与前一个块异或,第一个块与初始化向量异或,然后加密,而在EBC模式下,每个块按原样加密。

@Jon_Skeet感谢提示,这不是问题,因为初始向量用于稍后创建加密器,而我得到的结果是相同的。谢谢你的建议。@magarcias:哪一个初始向量?你认为是空的那个,还是实际上是空的那个?@Jon_skeet。我尝试过设置初始向量和密钥,或者在CreateEncryptor调用中使用它们,或者按照您的建议初始化向量。所有选项都给出相同的结果,显然它们是等价的:SymmetricKey.Key=KeyBytes;SymmetricKey.IV=初始向量字节;ICryptoTransform Encryptor=SymmetricKey.CreateEncryptor;和:ICryptoTransform Encryptor=SymmetricKey.createEncryptoryBytes,InitialVectorBytes@margarcias:是不是已经将InitialVectorBytes设置为零初始化数组?如果你遵循正常的.NET命名约定,你的代码会更清晰,顺便说一句。@Jon_Skeet谢谢你的提示,这不是问题,因为初始向量用于以后创建加密程序,我得到的结果是相同的。谢谢你的建议。@magarcias:哪一个初始向量?你认为是空的那个,还是实际上是空的那个?@Jon_skeet。我尝试过设置初始向量和密钥,或者在CreateEncryptor调用中使用它们,或者按照您的建议初始化向量。所有选项都给出相同的结果,显然它们是等价的:SymmetricKey.Key=KeyBytes;SymmetricKey.IV=初始向量字节;ICryptoTransform Encryptor=SymmetricKey.CreateEncryptor;和:ICryptoTransform Encryptor=SymmetricKey.createEncryptoryBytes,InitialVectorBytes@margarcias:是不是已经将InitialVectorBytes设置为零初始化数组?顺便说一句,如果您遵循正常的.NET命名约定,代码会更清晰。