来自Flex客户端的RSA加密和来自Web服务的相应解密

问题描述

|| 我在用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,并尝试更改一侧或另一侧以匹配填充策略。