【发布时间】:2011-05-24 22:21:08
【问题描述】:
我在 flex 客户端和用 c# 编写的 Web 服务之间设置 RSA 加密/解密机制时遇到问题。想法是这样的:我将从 flex 中加密一些文本,然后从 Web 服务中对其进行解密。我正在使用来自谷歌的 as3crypto 库。它正在正确加密/解密文本。我也有网络服务端的代码来正确加密/解密。我的问题是同步它们 - 基本上共享公钥以 flex 并将私钥保留给 Web 服务。
我的 flex“加密”函数采用 RSA 的模数和指数来进行文本加密,那么我如何从 Web 服务的 RSACryptoServiceProvider 获取这些模数和指数属性,所以它们使用相同的标准。 我试过了 RSAKeyInfo.Modulus RSAKeyInfo.Exponent 来自 web 服务并将它们提供给 flex 客户端。 在对 flex 进行加密后,我获取了密文并将其提供给 web 服务上的解密方法,但它给了我“坏数据”错误消息。
System.Security.Cryptography.CryptographicException: Bad Data.
at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
at System.Security.Cryptography.Utils._DecryptKey(SafeKeyHandle hPubKey, Byte[] key, Int32 dwFlags)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
at Microsoft.Samples.Security.PublicKey.App.RSADecrypt(Byte[] DataToDecrypt, RSAParameters RSAKeyInfo, Boolean DoOAEPPadding) in C:\Users
\Me\Desktop\After Release\5-24-2011-webServiceCrypto\publickeycryptography\CS\PublicKeyCryptography\PublicKey.cs:line 219
Encryption failed.
我如何确保它们都使用相同的 64 字节或 128 字节加密。即来自 flex 的输入应该符合 Web 服务 RSACryptoServiceProvider 的解密方法所期望的。 (我假设尺寸可能是个问题,可能不是 - 我迷路了)
这是代码,首先是 flex 客户端,然后是 web 服务 c# 代码
private function encrypt():void {
var rsa:RSAKey = RSAKey.parsePublicKey(getModulus(), getExponent());
trace("Modulus Lenght: " + getModulus().length);
trace("Exponent Lenght : " + getExponent().length);
var data:ByteArray = getInput(); //returns byteArray of plainText
var dst:ByteArray = new ByteArray;
rsa.encrypt(data, dst, data.length);
trace("Enc Data: " + dst.toString() );
currentResult = Hex.fromArray(dst);
encryptedText = currentResult;
trace("Encrypted:: " + currentResult);
}
//For testing purposes
private function decrypt():void {
var rsa:RSAKey = RSAKey.parsePrivateKey(getModulus(), getExponent(), getPrivate(), getP(), getQ(), getDMP1(), getDMQ1(), getCoeff());
var data:ByteArray = Hex.toArray(encryptedText);
trace("Byte array: " + data.toString());
var dst:ByteArray = new ByteArray;
rsa.decrypt(data, dst, data.length);
decryptedText = Hex.fromArray(dst);
trace("Decrypted text: " + Hex.toString(decryptedText));
}
Web服务部分如下:
try
{
//Create a UnicodeEncoder to convert between byte array and string.
UnicodeEncoding ByteConverter = new UnicodeEncoding();
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes("Data to Encrypt");
byte[] encryptedData;
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
//Pass the data to DECRYPT, the private key information
//(using RSACryptoServiceProvider.ExportParameters(true),
//and a boolean flag specifying no OAEP padding.
decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true), false);
//Display the decrypted plaintext to the console.
Console.WriteLine("\n\nDecrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
}
}
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
Console.WriteLine("Modulus Lenghth :" + RSAKeyInfo.Modulus.Length);
Console.WriteLine("Exponent Length :" + RSAKeyInfo.Exponent.Length);
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());
return null;
}
}
我不太确定这种 RSA 设置是否适合... 欢迎任何评论/建议/或推荐的解决方案, 谢谢大家
【问题讨论】:
-
我删除了 Webservices 标签并用 Public-Key-Encryption 替换它;因为这似乎是标记这个问题的更重要的方式。
-
当用户有权访问密钥时,加密是无用的。您将永远无法实现比 SSL 更安全的解决方案,因此您不妨使用它...
-
感谢 flextras。 @drkstr- 用户有公钥但不知道私钥,那它怎么没用?而且我的网络服务是通过 https 公开的,因此可以实现一定程度的安全性。
-
现在我很好奇...这是某种需要加密的监管恶作剧吗?我可以想象客户端像你想要的那样加密数据并发送到 Web 服务器的情况。但是网络服务器没有解密密钥。其他一些机器偶尔会抓取该数据并对其进行解密。
-
它没用,因为客户端加密只会对已经拥有它的人隐藏数据。 @Marc 即使如此,在服务器端运行加密会更好。客户端加密唯一有意义的情况是 SSL 不可用,或者数据在发送到服务器之前需要在本地存储(如离线模式)。由于客户端上已经存在未加密的数据,并且 SSL 将对通过网络发送的任何内容进行加密,因此根本不需要在客户端运行任何类型的加密。
标签: c# wcf apache-flex actionscript-3 public-key-encryption