I am creating a C# app that authenticates via a node.js server. I am using RSA for this purpose. I generated a public and private key for the server using crypto. Every time the client connects to the server, it generates a key pair for itself. The client gets the server public key from an endpoint. I have used XML strings as well as PEM strings, but neither of them worked. (using RSACryptoServiceProvider) When the server attempted to decrypt it, it threw an OAEP decoding error. I am trying to decrypt the message with the paired private key.
I have viewed other threads but they were not very helpful.
Here's the code for the server. It encrypts/decrypts with the built-in crypto module. (I have tested this with a node.js client and a node.js server, and it works.)
var encrypt = function(input, publicKey) {
var buffer = Buffer.from(input);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
var decrypt = function(input, privateKey) {
var buffer = Buffer.from(input, "base64");
var decrypted = crypto.privateDecrypt(privateKey, buffer);
return decrypted.toString("utf8");
};
module.exports = {
encrypt,
decrypt
}
Edit: I made a test C# console app that takes an input string and encrypts it with my node.js server's public key.
public const string pubKey = "<RSAKeyValue>public key etc etc</RSAKeyValue>";
private static void Main(string[] args)
{
string enc = encrypt(pubKey, args[0]);
Console.WriteLine(enc);
}
public static string encrypt(string publicKey, string decrypted)
{
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(publicKey);
byte[] bytesPlainTextData = Encoding.UTF8.GetBytes(decrypted);
byte[] bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
string cipherText = Convert.ToBase64String(bytesCipherText);
return cipherText;
}
It gave me the result VnzRc4yhIa9XcSDvHyDkwCNHFG6Ps2dddyCD4RHE4jIqvMl56DhmIJWprLRZle9EpZ/3Zq4fDkkplHUGBidoH+9VkPV/2+sV6P+C+4u6yisV5zTarZfjcvsShwBp/9z4YfOE7kQZVRENhvflrRw6GutxtDz0lO4KhvdvQztm0u7JmUB9ynM7XFYXOKT391InBs2eqRh+JRfJzTfhFqn3Bt8K/kKNE1xkvQV0GK7U1qSpWOWfB+0hdwNkUEQpT26jU93bAcex1SVwfbj4PJQMH6Wxzx2s6u4fcOzf9ELEgel/Fuj5b0UKHHE48B/zBmnoDsS3twt/8TJb9jbCU8S3ES/hKwndkS809bSoJl6TkBXErlOLCDpay3AO23+NjPGwSl1JvnFUVgTqAABd/yAcsokjIgxkbRqAvhC/js5Oh3y9wJwc9Z7V1ImPGcifIWsEBuH/8lerJdYw7ABB/eUZosC+tQkzvjr4H9urupM0mk6Zd+92sJaG/COrwOAPkiiM6lJK9ealRrlPMEKv39aWVr+brlQzN8zyoT+a0oGsYSPt9B/P3CJhbkbHqw9e1u9TZ7q9Ba7x/oqeRBmpRfFrcjegGFQkYViYkd1bswNF3KumqhBCsw4VeTkYmRNCKrLZdZyJ5BLSfvc+PTPOzDPVgOZb1InacmIWOqkapRbeELc=
Then, I did a simple console.log(decrypt(stringAbove, privateKey));
It still gives me the following error:
Error: error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
There are multiple types of padding, and apparently the encryption is trying to use PKCS1 (I guess), and the decryption defaults to OAEP.
In crypto.privateDecrypt you can set the padding to eg. padding: crypto.constants.RSA_PKCS1_PADDING and it should work.
You should go for OAEP on both ends if possible (and it should be), in which case your Node code is already ok as the default is OAEP, and C# should be set to OAEP too.
Edit: I mixed it up first, but the point is, you can set the padding type on either end, and they must match. :)
Related
I have a node server and and passing up usernames and passwords from unity. here is what I have so far. I am still trying to learn and understand encryption and there are so many types and Im just confused. The code below will successfully encrypt and decrypt the string. Is this code a good code to use for something like this or is there a better alternative? What type of encryption is this actually using? How would I decrypt this on node js? Any additional example, links, or comments would be much appreciated. Thanks!
public string encrypt(string toEncrypt) {
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "ThisIsAKey"; // This is the key used to encrypt and decrypt can be anything.
var provider = new RSACryptoServiceProvider(cspParams);
byte[] tempencryptedBytes = provider.Encrypt(System.Text.Encoding.UTF8.GetBytes(toEncrypt), true);
string encrypted = Convert.ToBase64String(tempencryptedBytes); // convert to base64string for storage
Debug.Log("encrypted: " + encrypted);
// Get the value stored in RegString and decrypt it using the key.
return encrypted;
}
public string decrypt(string toDecrypt) {
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "ThisIsAKey"; // This is the key used to encrypt and decrypt can be anything.
var provider = new RSACryptoServiceProvider(cspParams);
string decrypted = System.Text.Encoding.UTF7.GetString(provider.Decrypt(Convert.FromBase64String(toDecrypt), true));
Debug.Log("decrypted: " + decrypted);
return decrypted;
}
EDIT: SHA256 code that i used added here. It doesnt output the correct string value.
SHA256 sha256 = SHA256Managed.Create();
byte[] bytes = System.Text.Encoding.UTF8.GetBytes("randy");
byte[] hash = sha256.ComputeHash(bytes);
string result = "";
for (int i = 0; i < hash.Length; i++) {
result += String.Format("{0:x2}", i);
}
Debug.Log("hash: " + result);
string result2 = Convert.ToBase64String(hash);
Debug.Log("hash: " + result2);
If something is good to be used depends on the context.
If you need to pass a username / password combination then RSA encryption may indeed be used, preferably in addition to TLS transport security for the connection. If you just need to verify a username or password then you may need a password hash (or PBKDF) instead. The .NET version of PBKDF2 can be found in this badly named class.
Even if all the cryptographic algorithms are secure then your system may still not be secure. For instance, if you cannot trust the public key that you are encrypting with then you may be encrypting with a public key of an attacker.
So your code is using this specific encrypt call using a boolean to select the encryption algorithm. As the boolean is set to true that means that RSA with OAEP is being used, using the default SHA-1 hash function internally (which is secure for OAEP encryption, even if SHA-1 isn't). It's better to use the newer call where you can specify the padding without the boolean anti-pattern. In that case you can also specify the internal hash function to be used.
RSA with OAEP is specified in PKCS#1 v2.2, which is specified in turn in RFC 8017. This will even specify the byte order to be used (RSA operates on numbers in the end, which can be encoded to bytes in different ways). As long as you use a compliant library in any runtime and know how to encode / decode the plaintext and ciphertext (when using text) then you should be able to decrypt using any runtime that implements RSA with OAEP, if you have the matching private key of course.
As a general rule, passwords shouldn't be decryptable. You should hash the password (using something like SHA256), then compare that to a stored hash in your Node.js code. Never store or transfer passwords plaintext or in a method that can be converted back to the original password.
In C#, hashing will look something like:
string toHash = "PasswordToBehashed";
SHA256 sha = new SHA256();
byte[] tempencryptedBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(toHash));
For reference, see the SHA256 class and an example using MD5 instead of SHA256.
I need help in retrieving AES128-EBC encrypted string under Universal Windows Application.
I have a password in string that is used as a key. With it's 32 bits length MD5 hash value I would like to encrypt text with AES128-EBC.
Now I am using this for creating MD5Hash:
public string GetMD5Hash(String strMsg)
{
string strAlgName = HashAlgorithmNames.Md5;
IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm
string strAlgNameUsed = objAlgProv.AlgorithmName;
IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);
if (buffHash.Length != objAlgProv.HashLength)
{
throw new Exception("There was an error creating the hash");
}
string hex = CryptographicBuffer.EncodeToHexString(buffHash);
return hex;
}
And this code for encryption:
public string Encrypt(string input, string pass)
{
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
CryptographicKey key;
string encrypted = "";
byte[] keyhash = Encoding.ASCII.GetBytes(GetMD5Hash(pass));
key = provider.CreateSymmetricKey(CryptographicBuffer.CreateFromByteArray(keyhash));
IBuffer data = CryptographicBuffer.CreateFromByteArray(Encoding.Unicode.GetBytes(input));
encrypted = CryptographicBuffer.EncodeToBase64String(CryptographicEngine.Encrypt(key, data, null));
return encrypted;
}
The cause why I am using SymmetricAlgorithmNames.AesEcbPkcs7 is when I am using SymmetricAlgorithmNames.AesEcb the output string is empty. I don't understand why.
My question is: Does my code create an AES128-ECB encryption? Because I not really sure it does. Because the software that is waiting for that encrypted data not recognizes it, so it cannot decrypt it.
My question is: Does my code create an AES128-ECB encryption? Because I not really sure it does. Because the software that is waiting for that encrypted data not recognizes it, so it cannot decrypt it.
Yes, your code create an AES encryption with ECB cipher mode and PKCS7 padding. If I correctly understand your problem, you said this works with AesEcbPkcs7, but failed using AesEcb, your software for decryption doesn't work for this.
The difference between AesEcbPkcs7 and AesEcb is, AesEcbPkcs7 use PKCS#7 block padding modes, and PKCS #7 algorithms automatically pads the message to an appropriate length, so you don’t need to pad the cipher to a multiple of the block-size of the algorithm you are using. So if you insist to use AesEcb to encrypt, I recommend to use `AesEcbPkcs7, otherwise an exception: The supplied user buffer is not valid for the requested operation.
So I guess, one possibility here in your decryption software, it may have the ability to use AesEcbPkcs7, but it doesn't implement the decrytion of AesEcb. Here I tested decryption based on your code, this code can decrypt AesEcb correctly:
public string Decrypt(string input, string pass)
{
var keyHash = Encoding.ASCII.GetBytes(GetMD5Hash(pass));
// Create a buffer that contains the encoded message to be decrypted.
IBuffer toDecryptBuffer = CryptographicBuffer.DecodeFromBase64String(input);
// Open a symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider aes = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcb);
// Create a symmetric key.
var symetricKey = aes.CreateSymmetricKey(keyHash.AsBuffer());
var buffDecrypted = CryptographicEngine.Decrypt(symetricKey, toDecryptBuffer, null);
string strDecrypted = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, buffDecrypted);
return strDecrypted;
}
Another possibility I think you catch the exception when using AesEcb and the user buffer is not valid for the requested operation and handled it when you call your Encrypt(string input, string pass) method, the encryption failed actually.
I have a server written in Java which sends converts its RSA key to the XML format used by .NET before sending it to the client:
public String getPublicKeyXML() {
try {
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec publicKey = factory.getKeySpec(this.keyPair.getPublic(), RSAPublicKeySpec.class);
byte[] modulus = publicKey.getModulus().toByteArray();
byte[] exponent = publicKey.getPublicExponent().toByteArray();
String modulusStr = Base64.encodeBytes(modulus);
String exponentStr = Base64.encodeBytes(exponent);
String format =
"<RSAKeyValue>" +
"<Modulus>%s</Modulus>" +
"<Exponent>%s</Exponent>" +
"</RSAKeyValue>";
return String.format(format, modulusStr, exponentStr);
} catch (Exception e) {
this.server.logException(e);
return "";
}
}
The client, written in C#, then loads the key and uses it to encrypt a 256 bit AES key:
public static byte[] encrypt(string xmlKey, byte[] bytes)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlKey);
byte[] cipherBytes = rsa.Encrypt(bytes, false);
rsa.Clear();
return cipherBytes;
}
The server is then supposed to decrypt the AES key using its private RSA key:
public byte[] decrypt(byte[] data) {
try {
PrivateKey privateKey = this.keyPair.getPrivate();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
} catch (Exception e) {
this.server.logException(e);
return new byte[0];
}
}
However, the server fails with an error stating "Data must not be longer than 384 bytes." Looking at the data to be decrypted, I noticed that it's 385 bytes. I tried increasing the RSA key length, and now the server tells me the data must be no longer than 512 bytes, while the encrypted data from the client is 513 bytes. Why is the encrypted data always one byte longer than expected?
EDIT:
Here's a sample XML-formatted key as is transmitted from the server to the client:
<RSAKeyValue><Modulus>ANsMd2dCF6RsD5v5qjlHEjHm0VWD99gSYHP+pvyU8OgNL9xM5+o+yMAxWISOwMii9vJk1IzYGf18Fj2sMb5BsInlG2boZHb6KHh7v8ObPa4MuwB/U63i8AVU3N/JTugaPH0TKvo1WNUooXEHT23nOk+vh1QipzgKQYGl68qU35vKmpNAa79l1spXA66LckTWal4art9T08Rxgn9cMWujlF+wh9EQKQoxxgj4gCoXWRDTFYjRo/Mp5xDPwNjloTs/vFCPLvY7oI+lVrHhrPyz1R473ZuEhZm+rSeGBcY9I8vhg0AIixN7KYBLhrIecmqoNZHi6LohjD2F9zhdLaTU0IIU8eeKpbEZ5eB1kYngMONBq3A/IoG0Qa/7EcSAMMspBEObffK9kCNzvnbFg5wLuy8EHNaK3nmnuTppgCwCyNqZyHeAbZaUBjNguLhHtqkHFiPJ063Xesj9UbSsCmlBliGTDXWfeJANnjGP6D3R+uLXVy9SZe+cY92JW3eZA2k//w==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
I have verified that the data sent is the same as the data being received.
Knocking off the last byte results in a BadPaddingException. I also tried knocking off the first byte, with the same result.
I found the problem. The BigInteger's toByteArray() function included a leading zero for some reason. I just removed the leading zeros from the array and it now works like a charm!
This will not fix the problem (I tested it to no avail), but I wanted to call to your attention that RSACryptoServiceProvider implements the IDisposable interface and therefore should be properly disposed of when complete. Your C# encrypt method can be written a bit better (and more concise!) as such:
public static byte[] encrypt(string xmlKey, byte[] bytes)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(xmlKey);
return rsa.Encrypt(bytes, false);
}
}
I'm having a problem setting up RSA encryption/decryption mechanism between flex client and web service written in c#. The idea is this: I'll encrypt some text from flex and then decrypt it from web service. I'm using as3crypto library from google. It is encrypting/decrypting text properly. I also have the code on the web service side to encrypt/decrypt properly. My problem is synchronizing them - basically sharing the public key to flex and keeping the private key to the web service.
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.
I tried the
RSAKeyInfo.Modulus
RSAKeyInfo.Exponent
from the web service and fed them to the flex client.
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.
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 . ie the input from flex should fit to what is expected by the web service RSACryptoServiceProvider's decrypt method.
(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
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:
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
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 '????????' text. So I just put paddWithZeros() function to pad the decrypted byte array with 0's between bytes and it worked.
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).
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.
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.
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:
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.
Thanks
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. I doubt your system is that important to leverage the use of encrypting text.
I use as3crypto and JAVA web-services. Here are some thoughts:
a. I generated my public and private RSA keys via openssl
b. My client loads the public .cer file at application startup (if you just hardcoded them in from the generated key that works too).
var pemString : String = new String(data.target.data);
var x509Cert : X509Certificate = new X509Certificate(pemString);
var publicRSAKey : RSAKey = x509Cert.getPublicKey();
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. I didn't write the JAVA side of things but you aren't using JAVA anyways. I know that as3crypto uses PKCS1 padding by default:
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. 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.
I'm trying to set up a simple server side RSA encryption of a small chunk of info which is to be decrypted on the client side. Just as a proof of concept I wrote a few lines to ensure that the public and private key could be loaded from xml. However, I'm struggling to make even the most simple stuff work on my machine:
byte[] bytes = Encoding.UTF8.GetBytes("Some text");
bool fOAEP = true;
// seeding a public and private key
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
var publicKey = rsa.ToXmlString(false);
var privateKey = rsa.ToXmlString(true);
//server side
RSACryptoServiceProvider rsaServer = new RSACryptoServiceProvider();
rsaServer.FromXmlString(privateKey);
var encrypted = rsaServer.Encrypt(bytes, fOAEP);
//client side
RSACryptoServiceProvider rsaClient = new RSACryptoServiceProvider();
rsaClient.FromXmlString(publicKey);
var decrypted = rsaClient.Decrypt(encrypted, fOAEP);
The last call to Decrypt throw a CryptographicException with the message "Error occurred while decoding OAEP padding.". I must be missing something totally obvious here. Do I need more setup of the rsa instances or maybe the initial rsa seeding instance?
You should use public key for encryption and private key for decryption.
Take a look here: RSACryptoServiceProvider decrypt with public key
Now, let's get back to the
RSACryptoServiceProvider class. The
Encrypt method ONLY encrypts using
the public key and the Decrypt method
only decrypts using the private key.