简体   繁体   English

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

[英]RSA encryption from Flex client and Corresponding Decryption from Web service

I'm having a problem setting up RSA encryption/decryption mechanism between flex client and web service written in c#.我在 flex 客户端和用 c# 编写的 web 服务之间设置 RSA 加密/解密机制时遇到问题。 The idea is this: I'll encrypt some text from flex and then decrypt it from web service.想法是这样的:我将从 flex 中加密一些文本,然后从 web 服务中对其进行解密。 I'm using as3crypto library from google.我正在使用来自谷歌的 as3crypto 库。 It is encrypting/decrypting text properly.它正在正确加密/解密文本。 I also have the code on the web service side to encrypt/decrypt properly.我在 web 服务端也有代码可以正确加密/解密。 My problem is synchronizing them - basically sharing the public key to flex and keeping the private key to the web service.我的问题是同步它们 - 基本上共享公钥以 flex 并将私钥保留给 web 服务。

My flex "encrypt" function takes modulus and exponent of RSA to do text encryption, so how do i get these modulus and exponent attributes from the web service's RSACryptoServiceProvider, so they speak the same standard.我的 flex “加密” function 采用 RSA 的模数和指数来进行文本加密,那么我如何从 web 服务的 RSA CryptoServiceProvider 中获取这些模数和指数属性,因此它们使用相同的标准。 I tried the RSAKeyInfo.Modulus RSAKeyInfo.Exponent from the web service and fed them to the flex client.我尝试了 web 服务中的 RSAKeyInfo.Modulus RSAKeyInfo.Exponent 并将它们提供给 flex 客户端。 After doing encryption on flex I took the cipher text and fed it to decrypt method on web service, but it is giving me "bad data" error message.在对 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.

How do i make sure they are both using the same byte 64 or 128 byte encryption.我如何确保它们都使用相同的 64 字节或 128 字节加密。 ie the input from flex should fit to what is expected by the web service RSACryptoServiceProvider's decrypt method.即来自 flex 的输入应该符合 web 服务 RSACryptoServiceProvider 的解密方法所期望的。 (I'm assuming the size might be a problem, may be it's not - i'm lost) (我假设尺寸可能是个问题,可能不是 - 我迷路了)

Here is the code, first flex client followed by web service c# code这是代码,首先是 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));
            }

And web service part is as follows: 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;
        }

    }

I'm not quite sure if this RSA set up is the way to go... Any kinda comment / advice/ or recommended solution is welcome, thanks guys我不太确定这个 RSA 设置是否是通往 go 的方式...欢迎任何评论/建议/或推荐的解决方案,谢谢大家

Eureka.尤里卡。 Eureka!尤里卡! I got it.我知道了。

The problem was after decryption from web service, the encrypted byte array missed 0's in between, so that when changed to string it gets unreadable '????????'问题是从 web 服务解密后,加密的字节数组在两者之间缺少 0,因此当更改为字符串时,它变得不可读'????????' text.文本。 So I just put paddWithZeros() function to pad the decrypted byte array with 0's between bytes and it worked.所以我只是把 paddWithZeros() function 用字节之间的 0 填充解密的字节数组,它就起作用了。

Thanks Kevin, your solution gave me an insight into what things I should consider.谢谢凯文,你的解决方案让我了解了我应该考虑的事情。 So during decrypting I specify parameter fOAEP as false, so it would use PKCS#1 for padding (making both libraries use the same standard).因此,在解密期间,我将参数 fOAEP 指定为 false,因此它将使用 PKCS#1 进行填充(使两个库使用相同的标准)。

RSA.Decrypt(DataToDecrypt, DoOAEPPadding); // DoOAEPPadding = false

another error that i was getting is Bad Data exception.我得到的另一个错误是坏数据异常。 This was fixed when i shared the RSA cryptoServiceProvider's parameters (modulus and exponent) to actionScript methods.当我将 RSA cryptoServiceProvider 的参数(模数和指数)共享给 actionScript 方法时,此问题已得到修复。

I also changed the byte[] array of c# RSA attributes (like Modulus n, Exponent e, Private d..etc) to hexa string so that I'd be able to share with as3crypto library.我还将 c# RSA 属性(如 Modulus n、Exponent e、Private d..etc)的 byte[] 数组更改为十六进制字符串,以便能够与 as3crypto 库共享。

I'd love to share what worked for me;我很乐意分享对我有用的方法; save others some time.为他人节省一些时间。

<?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, dst, 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>

And the web service part of decryption looks like this:而解密的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;
        }
    }

I'll do some reading about padding schemes for RSA, see if there is any misconception.我将阅读一些有关 RSA 填充方案的信息,看看是否有任何误解。

Thanks谢谢

I use as3crypto and JAVA web-services.我使用 as3crypto 和 JAVA web-services。 Here are some thoughts:以下是一些想法:

a.一个。 I generated my public and private RSA keys via openssl我通过 openssl 生成了我的公钥和私钥 RSA

b.湾。 My client loads the public.cer file at application startup (if you just hardcoded them in from the generated key that works too).我的客户端在应用程序启动时加载 public.cer 文件(如果您只是从生成的密钥硬编码它们也可以)。

var pemString : String = new String(data.target.data);
var x509Cert : X509Certificate = new X509Certificate(pemString);
var publicRSAKey : RSAKey = x509Cert.getPublicKey();

c. c。 Encrypt my strings via通过加密我的字符串

var inputByteArray : ByteArray = Hex.toArray(Hex.fromString(inputString));
var outputByteArray : ByteArray = new ByteArray();
appSettingsModel.publicRSAKey.encrypt(inputByteArray, outputByteArray, inputByteArray.length);

d. d。 I didn't write the JAVA side of things but you aren't using JAVA anyways.我没有写 JAVA 方面的东西,但无论如何你都没有使用 JAVA。 I know that as3crypto uses PKCS1 padding by default:我知道 as3crypto 默认使用 PKCS1 填充:

RSAKEY.as 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;

This can be changed but I haven't tried it yet.这可以更改,但我还没有尝试过。 Based on your code it looks like you might be trying to decrypt with OAEP scheme, but I can't tell how you are setting that bool.根据您的代码,您可能正在尝试使用 OAEP 方案解密,但我不知道您是如何设置该布尔值的。 You may want to take a look at what padding scheme is being used with the bool as false and try to change one side or the other to match padding strategies.您可能想看看 bool 为 false 时使用的填充方案,并尝试更改一侧或另一侧以匹配填充策略。

Seems overly complicated.似乎过于复杂。 I've worked on some high security systems before, but this is ludicrous.我以前曾在一些高安全性系统上工作过,但这很荒谬。 Why would you need this kind of level of encryption at the text being sent unless you don't want the user to know the text he just inputted?除非您不希望用户知道他刚刚输入的文本,否则为什么在发送的文本中需要这种级别的加密?

Just use a strong SSL key (256bit is max for IE6, you could use 512 but only compatible with newer browsers) for the actual transfer protocol (I imagine HTTP) with a binary data format (AMF) and everything should be fine.只需使用强大的 SSL 密钥(IE6 最大为 256 位,您可以使用 512 但仅与较新的浏览器兼容)用于具有二进制数据格式(AMF)的实际传输协议(我想是 HTTP),一切都应该没问题。 I doubt your system is that important to leverage the use of encrypting text.我怀疑您的系统对于利用加密文本的使用是否重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM