问题描述
||
我在用c#编写的flex客户端和Web服务之间设置RSA加密/解密机制时遇到问题。这个想法是这样的:我将通过flex加密一些文本,然后从Web服务解密它。我正在使用Google的as3crypto库。它正在正确地加密/解密文本。我在Web服务端也有用于正确加密/解密的代码。我的问题是同步它们-基本上共享公用密钥以进行伸缩,并保留Web服务的私钥。
我的flex \“ encrypt \”函数采用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,data.length);
decryptedText = Hex.fromArray(dst);
trace(\"Decrypted text: \" + Hex.toString(decryptedText));
}
而Web Service部分如下:
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 @R_878_4045@ion
//(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 @R_878_4045@ion
//(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,bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key @R_878_4045@ion. This only needs
//toinclude the public key @R_878_4045@ion.
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,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 @R_878_4045@ion. This needs
//to include the private key @R_878_4045@ion.
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设置是否可行...
欢迎提出任何意见/建议/或推荐的解决方案,
谢谢你们
解决方法
尤里卡!尤里卡!我知道了。
问题是从Web服务解密后,加密的字节数组之间丢失了0 \,因此当更改为字符串时,它变得无法读取\'????????? \'文本。因此,我只需要使用paddWithZeros()函数在字节之间使用0 \填充解密的字节数组就可以了。
谢谢Kevin,您的解决方案使我对应该考虑的问题有了深刻的了解。因此,在解密期间,我将参数fOAEP指定为false,因此它将使用PKCS#1进行填充(使两个库都使用相同的标准)。
RSA.Decrypt(DataToDecrypt,DoOAEPPadding); // DoOAEPPadding = false
我得到的另一个错误是错误数据异常。当我向actionScript方法共享RSA cryptoServiceProvider的参数(模数和指数)时,此问题已修复。
我还将c#RSA属性的byte []数组(如模数n,指数e,私有d..etc)更改为六进制字符串,以便可以与as3crypto库共享。
我很想分享对我有用的东西;节省一些时间。
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<s:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\"
xmlns:s=\"library://ns.adobe.com/flex/spark\"
xmlns:mx=\"library://ns.adobe.com/flex/mx\" minWidth=\"955\" minHeight=\"600\">
<fx:Script>
<![CDATA[
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.util.Hex;
private var currentResult:String;
private var encryptedText:String;
private var decryptedText:String;
private function encrypt(plainText:String):String {
var rsa:RSAKey = RSAKey.parsePublicKey(getModulus(),getExponent());
var data:ByteArray = Hex.toArray(Hex.fromString(plainText)); //returns byteArray of plainText
var dst:ByteArray = new ByteArray;
rsa.encrypt(data,dst,data.length);
currentResult = Hex.fromArray(dst);
encryptedText = currentResult;
trace (\"Cipher: \" + currentResult);
return currentResult;
}
private function getInput():ByteArray {
return null;
}
private function getModulus():String {
return \"b6a7ca9002b4df39af1ed39251a5d\"; //read this value from web service.
}
private function getExponent():String {
return \"011\"; //read this value from web service.
}
//For debugging and testing purposes
// private function decrypt(cipherText:String):String {
// var rsa:RSAKey = RSAKey.parsePrivateKey(getModulus(),getExponent(),getPrivate(),getP(),getQ(),getDMP1(),getDMQ1(),getCoeff());
// var data:ByteArray = Hex.toArray(cipherText);
// var dst:ByteArray = new ByteArray;
// rsa.decrypt(data,data.length);
// decryptedText = Hex.fromArray(dst);
//trace(\'decrypted : \' + decryptedText);
// return Hex.toString(decryptedText);
// }
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g.,services,value objects) here -->
</fx:Declarations>
<mx:VBox >
<s:Button label=\"Encrypt Text\" click=\"encrypt(\'my plain text\')\" />
<s:Button label=\"Decrypt Text\" click=\"decrypt({encryptedText})\" />
</mx:VBox>
</s:Application>
解密的Web服务部分如下所示:
static public string RSADecrypt(string cipherText)
{
UnicodeEncoding ByteConverter = new UnicodeEncoding();
byte[] DataToDecrypt = StringToByteArray(cipherText);
bool DoOAEPPadding = false;
try
{
byte[] decryptedData;
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
KeyInfo keyInfo = new KeyInfo();
RSAParameters RSAKeyInfo = keyInfo.getKey();
RSA.ImportParameters(RSAKeyInfo);
decryptedData = RSA.Decrypt(DataToDecrypt,DoOAEPPadding);
}
byte[] paddedOutput = paddWithZeros(decryptedData); //to sync with as3crypto
return (ByteConverter.GetString(paddedOutput));
}catch (CryptographicException e)
{
//handle error
return null;
}
}
我将对RSA的填充方案进行一些阅读,看看是否存在任何误解。
谢谢
,似乎过于复杂。我以前曾在一些高安全性系统上工作过,但这太可笑了。除非您不希望用户知道他刚刚输入的文本,为什么在发送的文本上需要这种加密级别?
只需对二进制数据格式(AMF)的实际传输协议(我想象为HTTP)使用强大的SSL密钥(对于IE6,最大为256位,您可以使用512,但仅与较新的浏览器兼容),并且一切都很好。我怀疑您的系统对利用加密文本的重要性是否如此重要。
,我使用as3crypto和JAVA Web服务。这里有一些想法:
一种。我通过openssl生成了公共和私有RSA密钥
b。我的客户端在应用程序启动时加载公共.cer文件(如果您只是从生成的密钥中对其进行了硬编码的话)。
var pemString : String = new String(data.target.data);
var x509Cert : X509Certificate = new X509Certificate(pemString);
var publicRSAKey : RSAKey = x509Cert.getPublicKey();
C。通过加密我的字符串
var inputByteArray : ByteArray = Hex.toArray(Hex.fromString(inputString));
var outputByteArray : ByteArray = new ByteArray();
appSettingsModel.publicRSAKey.encrypt(inputByteArray,outputByteArray,inputByteArray.length);
d。我没有写JAVA方面的东西,但是无论如何您都没有使用JAVA。我知道as3crypto默认使用PKCS1填充:
RSAKEY.as
private function _encrypt(op:Function,src:ByteArray,dst:ByteArray,length:uint,pad:Function,padType:int):void {
// adjust pad if needed
if (pad==null) pad = pkcs1pad;
这可以更改,但我还没有尝试过。根据您的代码,您似乎可能正在尝试使用OAEP方案进行解密,但是我无法确定您如何设置该布尔值。您可能想看看在bool上使用哪种填充方案为false,并尝试更改一侧或另一侧以匹配填充策略。