Is there an alternative of SignedCMS in WinRT? - c#

And again I ran into trouble while porting a .NET Desktop App to a Windows Store App...
Long story short, I have a ZIP File with an encrypted and signed XML File and a certificate in it. The decryption is working (more or less) but now I have to "unsign" the XML and I'm stuck.
In the .NET App the unsigning is done with System.Security.Cryptography.Pkcs.SignedCms but that class does not exist in WinRt (as always...)
Is there any alternative in WinRT?
here is some of the code used in the .NET App:
public static byte[] CheckAndRemoveSignature(byte[] data, X509Certificate2Collection certStore, out SignedCms out_signature)
{
SignedCms signedMessage = new SignedCms();
signedMessage.Decode(data);
if ((certStore != null) && (certStore.Count > 0))
signedMessage.CheckSignature(certStore, true);
else
signedMessage.CheckSignature(true);
out_signature = signedMessage;
// return data without signature
return signedMessage.ContentInfo.Content;
}
I already searched a lot, but the only thing I found, that could have helped me was this post. Unfortunately the marked answer does not provide any helpful information :(
Windows 8 Metro cryptography - using SignedCms Pkcs7
I would really appreciate some help here :)
Edit
The essential problem is to get the original xml data out of the signed byte array.
Or, more specifically I need the functionality of these few lines of code in WinRT
SignedCms signedMessage = new SignedCms();
signedMessage.Decode(data);
byte[] result = signedMessage.ContentInfo.Content;
I tried the example from pepo, but I get a MalformedContent Exception
private byte[] CheckAndRemoveSignature(byte[] data)
{
try
{
// load using bouncyCastle
CmsSignedData sig = new CmsSignedData(data);
// var allSigsValid = VerifySignatures(sig);
byte[] content = sig.SignedContent.GetContent() as byte[];
return content;
}
catch (Exception ex)
{
cryptOutput.Text += "Error removing Signature: " + ex;
return data;
}
I get this exception:
Org.BouncyCastle.Cms.CmsException: Malformed content. ---> System.ArgumentException: unknown object in factory: DerApplicationSpecific
at Org.BouncyCastle.Asn1.Cms.ContentInfo.GetInstance(Object obj)
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Asn1InputStream aIn)
--- End of inner exception stack trace ---
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Asn1InputStream aIn)
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Stream input)
at Org.BouncyCastle.Cms.CmsSignedData..ctor(Byte[] sigBlock)
at TestApp.MainPage.CheckAndRemoveSignature(Byte[] data)
Code from Desktop App where the XML-File is signed:
private byte[] signInternal(byte[] data, X509Certificate2 signatureCert, bool signatureOnly)
{
CAPICOM.SignedData signedData = new CAPICOM.SignedDataClass();
CAPICOM.Utilities u = new CAPICOM.UtilitiesClass();
signedData.set_Content(u.ByteArrayToBinaryString(data));
GC.Collect();
CAPICOM.Signer signer = new CAPICOM.Signer();
signer.Options = CAPICOM.CAPICOM_CERTIFICATE_INCLUDE_OPTION.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;
CAPICOM.CertificateClass certClass = new CAPICOM.CertificateClass();
certClass.Import(Convert.ToBase64String(signatureCert.Export(X509ContentType.SerializedCert)));
signer.Certificate = certClass;
GC.Collect();
if (this.validateCert(signatureCert))
return (byte[])Convert.FromBase64String(signedData.Sign(signer, signatureOnly, CAPICOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64));
else
return new byte[] { };
}
Solution
In the end it turned out that there was a big problem with encoding, that I did not think was noteworthy. The answer from pepo is working, however I will post my version, to show how it works if you get the file from a zip folder:
// get bytes from zip
byte[] data = getFileContentAsByteArray(zipBytes, ze.FileName);
var dataString = Encoding.UTF8.GetString(data, 0, data.Length);
// check and remove signature
bool isValid;
byte[] withoutSig = CheckAndRemoveSignature(dataString, out isValid);
private byte[] CheckAndRemoveSignature(string data, out bool isValid)
{
isValid = false;
// using bouncyCastle
try
{
var bytes = Convert.FromBase64String(data);
// assign data to CmsSignedData
CmsSignedData sig = new CmsSignedData(bytes);
// check if signature is valid
var allSigsValid = VerifySignaturesBC(sig);
if (allSigsValid.Equals(true)) { isValid = true; }
// get signature from cms
byte[] content = sig.SignedContent.GetContent() as byte[];
return content;
}
catch (Exception ex) { cryptOutput.Text += "Error in 'BouncyCastle unsign' " + ex; return null; }
}

Based on comments I understand that you have a PKCS#7 structure (SignedCms) and the content of that structure is XmlDocument.
Because there is no SignedCms in WinRT API you have two choices. Either use some ASN.1 library and parse PKCS#7 manually looking for content or use i.e. BouncyCastle which has SignedCms implemented and can parse that strusture.
You asked for an example using bouncyCastle. Here it is.
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.X509.Store;
using System.Collections;
using System.Security.Cryptography.Pkcs;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// make some pkcs7 signedCms to work on
SignedCms p7 = new SignedCms(new System.Security.Cryptography.Pkcs.ContentInfo(new byte[] { 0x01, 0x02 }));
p7.ComputeSignature(new CmsSigner(), false);
// encode to get signedCms byte[] representation
var signedCms = p7.Encode();
// load using bouncyCastle
CmsSignedData sig = new CmsSignedData(signedCms);
var allSigsValid = VerifySignatures(sig);
byte[] content = sig.SignedContent.GetContent() as byte[];
}
// taken from bouncy castle SignedDataTest.cs
private static bool VerifySignatures(
CmsSignedData sp)
{
var signaturesValid = true;
IX509Store x509Certs = sp.GetCertificates("Collection");
SignerInformationStore signers = sp.GetSignerInfos();
foreach (SignerInformation signer in signers.GetSigners())
{
ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
IEnumerator certEnum = certCollection.GetEnumerator();
certEnum.MoveNext();
Org.BouncyCastle.X509.X509Certificate cert = (Org.BouncyCastle.X509.X509Certificate)certEnum.Current;
signaturesValid &= signer.Verify(cert);
}
return signaturesValid;
}
}
}
As for the ASN.1 library, I have only worked with bouncyCastle which has ASN.1 parser or ASN.1 editor which is a very useful GUI application for showing structure of PKCS#7, certificates etc. So I can recommend only those two.

You’re probably looking for something like Windows.Security.Cryptography.Certificates.CmsAttachedSignature.VerifySignature() and it's 'Content' property
See here

Related

Signature verification in c# with bouncy castle api

I'm attempting to make use of the Bouncy Castle apis to verify the signature of a clear signed message. (I've got signing, encryption, and decryption working, but some of the things I need to verify won't have been encrypted so I need to be able to do these separately).
I want to verify the signature, and if it is verified then return just the message text (without signature).
My function at the moment is the following;
public string GetVerifiedMessage(string signedCleartext, PgpPublicKey publicKey)
{
var inputStream = PgpUtilities.GetDecoderStream(ReadAsStream(signedCleartext));
var outStr = new MemoryStream();
inputStream.CopyTo(outStr);
outStr.Close();
var objectFactory = new PgpObjectFactory(inputStream);
var signatureList = (PgpSignatureList) objectFactory.NextPgpObject();
var signature = signatureList[0];
var literalData = (PgpLiteralData) objectFactory.NextPgpObject();
var data = literalData.GetInputStream();
signature.InitVerify(publicKey);
var memoryStream = new MemoryStream();
int ch;
while ((ch = data.ReadByte()) >= 0)
{
signature.Update((byte) ch);
memoryStream.WriteByte((byte) ch);
}
if (!signature.Verify())
{
throw new Exception("Signature was not verified");
}
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
This is based off the examples in the bouncy castle codebase and elsewhere, although I have had to vary them to do this in memory rather than writing to files.
When running this, I get an error because the objectFactory does not contain any pgp objects. I have verified that third party tools can verify the signature on the example message I'm using.
I've tried a few variations - not copying to outStr gives an "Unknown object in stream 45" exception on trying to get the PgpObject, which is annoying as in it's current form it is useless.
Can anyone point out where I'm going wrong?

Extract properties from a CRL file using C#

I'd like to write a program which monitors CRL (Certificate Revocation List) expiration date.
Therefore, I'd like to read the following properties from a CRL file:
1) Effective Date
2) Next Update
3) Next CRL Publish
How can I accomplish my task?
I've only managed to find types for X509Certificate2, X509Chain, x509RevocationMode etc..
you can use the class X509Certificate2 to get information needed.
example:To handle one certification file
X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile(fname);
x509.Import(rawData);
var validDate= x509 . NotBefore;
var expireDate = x509.NotAfter;
//Reads a file.
internal static byte[] ReadFile (string fileName)
{
FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
int size = (int)f.Length;
byte[] data = new byte[size];
size = f.Read(data, 0, size);
f.Close();
return data;
}
reference:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2(v=vs.110).aspx
Edit:
You can use the BouncyCastle.Crypto library to handle CRL.
Download the library and reference the BouncyCastle.Crypto.dll
or instal the nuget package:
Install-Package BouncyCastle
//reference library BouncyCastle.Crypto
//http://www.bouncycastle.org/csharp/
//Load CRL file and access its properties
public void GetCrlInfo(string fileName, Org.BouncyCastle.Math.BigInteger serialNumber, Org.BouncyCastle.X509.X509Certificate cert)
{
try
{
byte[] buf = ReadFile(fileName);
X509CrlParser xx = new X509CrlParser();
X509Crl ss = xx.ReadCrl(buf);
var nextupdate = ss.NextUpdate;
var isRevoked = ss.IsRevoked(cert);
Console.WriteLine("{0} {1}",nextupdate,isRevoked);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Although, the question is answered, I would add that there is another good open project that extends native .NET Framework to work with cryptography objects which are missing in the .NET: https://github.com/Crypt32/pkix.net
In regards to CRL, I developed an X509CRL2 class in a similar way to built-in X509Certificate2: X509CRL2 Class. The usage is pretty simple:
// reference System.Security.Cryptography.X509Certificates namespace
var crl = new X509CRL2(#"C:\temp\crlfile.crl");
// Effective date:
var effective = crl.ThisUpdate;
// next update:
var nextupdate = crl.NextUpdate;
// next publish:
var nextPublishExtension = crl.Extensions["1.3.6.1.4.1.311.21.4"];
if (nextPublishExtension != null) { nextPublishExtension.Format(1); }
I support CRL files in multiple formats, including pure binary, Base64 or even in hex.
By using this class you can not only read CRL properties, but you can generate Version 2 CRLs.
Note: pkix.net library relies on my another open project https://github.com/Crypt32/Asn1DerParser.NET which is used to parse ASN structures.
in addition to M.Hassan post ;
Using BouncyCastle.X509 you must convert the System.Security... X509Certificate2 to BouncyCastle certificate, the missing function between initial code and edit could be :
using System.Security.Cryptography.X509Certificates;
public static Org.BouncyCastle.X509.X509Certificate Convert(X509Certificate2 certificate)
{
var certificateParser = new Org.BouncyCastle.X509.X509CertificateParser();
var rawData = certificate.GetRawCertData();
var bouncyCertificate = certificateParser.ReadCertificate(rawData);
return bouncyCertificate;
}
We can use CertEnroll win32 APIs. The code can be
var bytes = File.ReadAllBytes(crlFile);
var base64 = System.Convert.ToBase64String(bytes);
CX509CertificateRevocationList crl = new CX509CertificateRevocationList();
crl.InitializeDecode(base64, EncodingType.XCN_CRYPT_STRING_BASE64_ANY);
Add the following to the csproj for including certEnrol
<ItemGroup>
<COMReference Include="CERTENROLLLib">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>728ab348-217d-11da-b2a4-000e7bbb2b09</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>

Bouncy castle error: Unable to cast object of type RsaPrivateCrtKeyParameters to type ElGamalKeyParameters

I am having difficulties with decryption of a GPG file using Bouncy Castle. I have the encrypted file and I have a private key and the password for the private key. I can successfully decrypt the file using the desktop software GPG4win Kleopatra so I have the correct private key and the gpg file is valid.
However when our application reaches the line of code which attempts to decrypt the data with Bouncy Castle, I receive this error:
Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters' to type 'Org.BouncyCastle.Crypto.Parameters.ElGamalKeyParameters'.
I am decrypting the same file using the same private key with Kleopatra so this has got to be something I can resolve by perhaps changing the private key file to the expected format or setting some options in Bouncy Castle.
The private key file is a plain text file beginning with the lines:
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v2.0.17 (MingW32)
Here is a flattened out version of the decryption code. Apologies if I have missed anything out:
PgpEncryptionKeys encryptionKeys = new PgpEncryptionKeys(publicKey, privateKey, passPhrase);
Stream encryptedStream = new StreamReader(encryptedFileName).BaseStream;
Stream encodedFile = PgpUtilities.GetDecoderStream(inputStream);
PgpObjectFactory factory = new PgpObjectFactory(encodedFile);
PgpObject pgpObject = factory.NextPgpObject();
PgpEncryptedDataList encryptedDataList;
if (pgpObject is PgpEncryptedDataList)
{
encryptedDataList = (PgpEncryptedDataList)pgpObject;
}
else
{
encryptedDataList = (PgpEncryptedDataList)factory.NextPgpObject();
}
PgpPublicKeyEncryptedData myEncryptedData = null;
PgpPublicKeyEncryptedData publicKeyED = null;
foreach (PgpPublicKeyEncryptedData encryptedData in encryptedDataList.GetEncryptedDataObjects())
{
if (encryptedData != null)
{
myEncryptedData = encryptedData;
break;
}
}
Stream clearStream = myEncryptedData.GetDataStream(privateKey);
PgpObjectFactory clearFactory = new PgpObjectFactory(clearStream);
PgpObject message = clearFactory.NextPgpObject();
if (message is PgpCompressedData)
{
message = ProcessCompressedMessage(message);
PgpLiteralData literalData = (PgpLiteralData)message;
using (Stream outputFile = File.Create(outputFilePath))
{
using (Stream literalDataStream = literalData.GetInputStream())
{
Streams.PipeAll(literalDataStream, outputFile);
}
}
}
The exception occurs on this line:
Stream clearStream = myEncryptedData.GetDataStream(privateKey);
I hope you can suggest something for me to try. I can provide any further details I might have missed.
Thanks!

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#. 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.

C# RSA with no padding

I'm busy trying to port Java code that looks like this
Cipher rsa = Cipher.getInstance("RSA/ECB/nopadding");
rsa.init(Cipher.DECRYPT_MODE, RSAPrivateKey);
decryptedData = rsa.doFinal(data, 0, 128);
to C#, but as it seems the RSACryptoServiceProvider, forces you to either use OEAP or PKCS1 padding. I know no padding isn't secure, but in this case Im working with a closed source client, so I can't do anything about that. Is there any way around this padding issue?
You might want to get the code from BouncyCastle, http://www.bouncycastle.org/csharp/, and modify the code from the link below, and ensure that it can use the encryption that you list above.
http://www.java2s.com/Code/Java/Security/Whatisinbouncycastlebouncycastle.htm
BouncyCastle will help us to make nopadding RSA encryption.
public string RsaEncryptWithPublic(string clearText, string publicKey)
{
// analogue of Java:
// Cipher rsa = Cipher.getInstance("RSA/ECB/nopadding");
try
{
var bytesToEncrypt = Encoding.ASCII.GetBytes(clearText);
var encryptEngine = new RsaEngine(); // new Pkcs1Encoding (new RsaEngine());
using (var txtreader = new StringReader("-----BEGIN PUBLIC KEY-----\n" + publicKey+ "\n-----END PUBLIC KEY-----"))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyParameter);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
catch
{
return "";
}
}
also dont forget to put it at top:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;

Categories

Resources