EncryptedXml DecryptDocument method throws "Bad Data" exception - c#

I wrote a code block for Encrypt/Decrypt Streams.
The code is working in my local machine.
But when I publish my code on web
The Decryption functions throws "Bad Data" exception
Here is the my Encrypton and Decryption functions
private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = password;
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
RijndaelManaged sessionKey = null;
try
{
if (xmlDoc == null)
throw new ArgumentNullException("xmlDoc");
if (rsaKey == null)
throw new ArgumentNullException("rsaKey");
if (elementToEncrypt == null)
throw new ArgumentNullException("elementToEncrypt");
sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256;
EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
edElement.KeyInfo = new KeyInfo();
KeyInfoName kin = new KeyInfoName();
kin.Value = KeyName;
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
if (sessionKey != null)
{
sessionKey.Clear();
}
rsaKey.Clear();
MemoryStream stream = new MemoryStream();
xmlDoc.Save(stream);
stream.Position = 0;
Encoding encodeing = System.Text.UnicodeEncoding.Default;
return stream;
}
catch (Exception e)
{
if (sessionKey != null)
{
sessionKey.Clear();
}
rsaKey.Clear();
throw (e);
}
}
private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = password;
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
EncryptedXml exml = null;
try
{
if (xmlDoc == null)
throw new ArgumentNullException("xmlDoc");
if (rsaKey == null)
throw new ArgumentNullException("rsaKey");
exml = new EncryptedXml(xmlDoc);
exml.AddKeyNameMapping(KeyName, rsaKey);
exml.DecryptDocument();
rsaKey.Clear();
MemoryStream outStream = new MemoryStream();
xmlDoc.Save(outStream);
outStream.Position = 0;
return outStream;
}
catch (Exception e)
{
rsaKey.Clear();
throw (e);
}
}
the exception is thrown on "exml.DecryptDocument();" line.
Do you have any idea about problem and the solution?
Edit:
in MSDN page, there is remark which is as follows
To use XML Encryption with X.509 certificates, you must have the
Microsoft Enhanced Cryptographic Provider installed and the X.509
certificate must use the Enhanced Provider. If you do not have the
Microsoft Enhanced Cryptographic Provider installed or the X.509
certificate does not use the Enhanced Provider, a
CryptographicException with an "Unknown Error" will be thrown when you
decrypt an XML document.
Do you have any idea about "Microsoft Enhanced Cryptographic Provider" and "X.509 certificate"?
And Can my problem be related to this those?

The reason the Decryption functions throws "Bad Data" exception when trying to Decrypt on another PC is that the CspParameters is linked to the session on the PC where the Encryption was run.
The cspParams object will need to be embedded and encrypted in the XML to enable Decryption on another PC. Luckily there is EncryptionProperty we can use for this.
private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = password;
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
RijndaelManaged sessionKey = null;
try
{
if (xmlDoc == null)
throw new ArgumentNullException("xmlDoc");
if (rsaKey == null)
throw new ArgumentNullException("rsaKey");
if (elementToEncrypt == null)
throw new ArgumentNullException("elementToEncrypt");
sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256;
EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
// Save some more information about the key using the EncryptionProperty element.
// Create a new "EncryptionProperty" XmlElement object.
var property = new XmlDocument().CreateElement("EncryptionProperty", EncryptedXml.XmlEncNamespaceUrl);
// Set the value of the EncryptionProperty" XmlElement object.
property.InnerText = RijndaelManagedEncryption.EncryptRijndael(Convert.ToBase64String(rsaKey.ExportCspBlob(true)),
"Your Salt string here");
// Create the EncryptionProperty object using the XmlElement object.
var encProperty = new EncryptionProperty(property);
// Add the EncryptionProperty object to the EncryptedKey object.
ek.AddProperty(encProperty);
edElement.KeyInfo = new KeyInfo();
KeyInfoName kin = new KeyInfoName();
kin.Value = KeyName;
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
if (sessionKey != null)
{
sessionKey.Clear();
}
rsaKey.Clear();
MemoryStream stream = new MemoryStream();
xmlDoc.Save(stream);
stream.Position = 0;
Encoding encodeing = System.Text.UnicodeEncoding.Default;
return stream;
}
catch (Exception)
{
if (sessionKey != null)
{
sessionKey.Clear();
}
rsaKey.Clear();
throw;
}
}
private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = password;
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
var keyInfo = xmlDoc.GetElementsByTagName("EncryptionProperty")[0].InnerText;
rsaKey.ImportCspBlob(
Convert.FromBase64String(RijndaelManagedEncryption.DecryptRijndael(keyInfo,
"Your Salt string here")));
EncryptedXml exml = null;
try
{
if (xmlDoc == null)
throw new ArgumentNullException("xmlDoc");
if (rsaKey == null)
throw new ArgumentNullException("rsaKey");
exml = new EncryptedXml(xmlDoc);
exml.AddKeyNameMapping(KeyName, rsaKey);
exml.DecryptDocument();
rsaKey.Clear();
MemoryStream outStream = new MemoryStream();
xmlDoc.Save(outStream);
outStream.Position = 0;
return outStream;
}
catch (Exception)
{
rsaKey.Clear();
throw;
}
}
Have a look here for the RijndaelManagedEncryption class.

Do not reinvent cryptography protocols. You will get it wrong. Case in point, mishandling the RSA key stored in the CSPs and expect them to magically appear on any machine.
To encrypt data in transfer, use SSL/TLS. .Net offers it out-of-the-box with SslStream. For WCF see How to: Configure an IIS-hosted WCF service with SSL.

Related

Decrypt a pdf file using bouncy castle using 3des algorithm

i need to decrypt a pdf file using bouncy castle libreries.
I use c#.
I can encrypt a pdf file using the following code:
public static byte[] CmsEncrypt3DES(string InFilePath, string CertFilePath)
{
byte[] encoded;
try
{
byte[] numArray = File.ReadAllBytes(InFilePath);
X509Certificate x509Certificate =ESCmsEncrypt.LoadCertificate(CertFilePath);
CmsEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CmsEnvelopedDataGenerator();
CmsProcessableByteArray cmsProcessableByteArray = new CmsProcessableByteArray(numArray);
cmsEnvelopedDataGenerator.AddKeyTransRecipient(x509Certificate);
encoded = cmsEnvelopedDataGenerator.Generate(cmsProcessableByteArray, PkcsObjectIdentifiers.DesEde3Cbc.Id).GetEncoded();
}
catch (Exception exception1)
{
Exception exception = exception1;
throw exception;
}
return encoded;
}
I import the certificate using this method:
public static X509Certificate LoadCertificate(string filename)
{
X509Certificate x509Certificate;
try
{
X509CertificateParser x509CertificateParser = new X509CertificateParser();
FileStream fileStream = new FileStream(filename, FileMode.Open);
X509Certificate x509Certificate1 = x509CertificateParser.ReadCertificate(fileStream);
fileStream.Close();
x509Certificate = x509Certificate1;
}
catch (Exception exception1)
{
Exception exception = exception1;
Log.LogError("ESCmsEncrypt.LoadCertificate", exception.Message, exception.ToString());
throw exception;
}
return x509Certificate;
}
This code work well but i' don't know how to decrypt this file using bouncy castle.
I've tried but without results.
Thanks
Valerio M.
EDIT
i've also used this code but it doesn't work:
public static void test()
{
X509Certificate2Collection scollection = new X509Certificate2Collection();
// Output which certificate will be used
Console.WriteLine("Using Certificate:");
string path_certificato = ConfigurationManager.AppSettings["certificate_file"].ToString();
X509Certificate2 cert = new X509Certificate2();
X509Certificate2 x509 = new X509Certificate2(File.ReadAllBytes(path_certificato));
Console.WriteLine("---------------------------------------------------------------------");
Console.WriteLine("1.\tFull DN: {0}", x509.Subject);
Console.WriteLine("\tThumbprint: {0}", x509.Thumbprint);
Console.WriteLine("---------------------------------------------------------------------");
cert = x509;
scollection.Add(cert);
// Wait
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
// Create data for encryption
string message = "THIS IS OUR SECRET MESSAGE";
byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Encrypt
Console.WriteLine("Encrypting message...");
//ContentInfo contentInfo = new ContentInfo(data); // will use default ContentInfo Oid, which is "DATA"
// Explicitly use ContentInfo Oid 1.2.840.113549.1.7.1, "DATA", which is the default.
ContentInfo contentInfo = new ContentInfo(new System.Security.Cryptography.Oid("1.2.840.113549.1.7.1"), data);
// If using OID 1.2.840.113549.3.7 (the default one used if empty constructor is used) or 1.2.840.113549.1.9.16.3.6 everything works
// If using OID 2.16.840.1.101.3.4.1.42 (AES CBC) it breaks
AlgorithmIdentifier encryptionAlgorithm = new AlgorithmIdentifier(new System.Security.Cryptography.Oid("1.2.840.113549.3.7"));
EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo); // this will use default encryption algorithm (3DES)
//EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo, encryptionAlgorithm);
Console.WriteLine("Encyption Algorithm:" + envelopedCms.ContentEncryptionAlgorithm.Oid.FriendlyName);
Console.WriteLine("Encyption Algorithm:" + envelopedCms.ContentEncryptionAlgorithm.Oid.Value);
CmsRecipientCollection recipients = new CmsRecipientCollection(SubjectIdentifierType.IssuerAndSerialNumber, scollection);
/*Console.WriteLine("Receipientinfo count: " + encryptionEnvelopedCms.RecipientInfos.Count.ToString());
foreach (var i in encryptionEnvelopedCms.RecipientInfos)
{
Console.Write("RecipientInfo Encryption Oid: " + i.KeyEncryptionAlgorithm.Oid);
}
*/
envelopedCms.Encrypt(recipients);
byte[] encryptedData = envelopedCms.Encode();
Console.WriteLine("Message encrypted!");
EnvelopedCms envelopedCms_new = new EnvelopedCms();
envelopedCms_new.Decode(encryptedData);
envelopedCms_new.Decrypt(scollection);
byte[] decryptedData = envelopedCms_new.ContentInfo.Content;
}
"envelopedCms_new.Decode(encryptedData);"this part doesn't work
System.Security.Cryptography.CryptographicException: 'Impossibile trovare la proprietà o l'oggetto.

iTextSharp 5 - Upgrading SHA1 signing to SHA256

I am currently having an issue with converting our PDF signing from SHA1 hashing to SHA256.
We use the Digest signing approach and not signing the entire PDF.
I have gone through a number of articles and have got to the point where the digest comes back in SHA256, however this invalidates the signature (which was previously valid).
The validity error message is "The document has been altered or corrupted since the Signature was applied"
I am new to Digital Signatures, and as a result would appreciate any assistance in this regard. If any of my terminology is incorrect, please feel free to correct me.
public static byte[] Sign(PdfSignatureAppearance signatureAppearance, IExternalSignature externalSignature, ICollection<X509Certificate> chain, ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize, CryptoStandard sigtype, PdfDictionary customSignatureProperties)
{
byte[] signedCMS = null;
List<X509Certificate> certificateChain = new List<X509Certificate>(chain);
ICollection<byte[]> crlBytes = BuildCrlBytes(certificateChain, crlList);
if (estimatedSize == 0)
{
estimatedSize = CalculateEstimatedSizeOfSignature(crlBytes, ocspClient, tsaClient);
}
signatureAppearance.CryptoDictionary = CreateCryptoDictionary(signatureAppearance, customSignatureProperties, PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
signatureAppearance.PreClose(SignGetEstimatedSizeDictionary(estimatedSize));
using (Stream data = signatureAppearance.GetRangeStream())
{
byte[] documentHash = DigestAlgorithms.Digest(data, externalSignature.GetHashAlgorithm());
signedCMS = externalSignature.Sign(documentHash);
byte[] encodedSignatureWithTimestamp = SignAddTimestampToSignedCms(tsaClient, signedCMS);
if (SignCheckEstimatedSize(encodedSignatureWithTimestamp, estimatedSize))
{
byte[] paddedSignature = new byte[estimatedSize];
Array.Copy(encodedSignatureWithTimestamp, 0, paddedSignature, 0, encodedSignatureWithTimestamp.Length);
signatureAppearance.Close(SignGetDigestDictionary(paddedSignature));
}
}
return signedCMS;
}
private static PdfDictionary CreateCryptoDictionary(PdfSignatureAppearance signatureAppearance, PdfDictionary customSignatureProperties, PdfName filter, PdfName subFilter)
{
PdfSignature dictionary = new PdfSignature(filter, subFilter);
dictionary.Reason = signatureAppearance.Reason;
dictionary.Location = signatureAppearance.Location;
dictionary.Contact = signatureAppearance.Contact;
dictionary.Date = new PdfDate(signatureAppearance.SignDate);
if (customSignatureProperties != null)
{
dictionary.PutAll(customSignatureProperties);
}
return dictionary;
}
private static byte[] SignAddTimestampToSignedCms(ITSAClient tsaClient, byte[] signedCms)
{
ArrayList newSigners = new ArrayList();
CmsSignedData cmsSignedData = new CmsSignedData(signedCms);
foreach (SignerInformation information in cmsSignedData.GetSignerInfos().GetSigners())
{
byte[] signedDigest = information.GetSignature();
byte[] timestampImprint = DigestAlgorithms.Digest(tsaClient.GetMessageDigest(), signedDigest);
byte[] timestampToken = tsaClient.GetTimeStampToken(timestampImprint);
newSigners.Add(SignerInformation.ReplaceUnsignedAttributes(information, GenerateUnsignedAttributes(Constants.TIMESTAMP_OID, timestampToken)));
}
return CmsSignedData.ReplaceSigners(cmsSignedData, new SignerInformationStore(newSigners)).GetEncoded();
}
Edit: Adding in the code implemented by the IExternalSignature Sign method implementation
public static byte[] SignDigest(string signer, byte[] digest)
{
SignatureData data = ConfigurationHelpers.GetSignatureData(signer);
var cryptoServiceProvider = RSACryptoServiceProvider)data.SigningCertificate.PrivateKey; // verify private key access
var contentInfo = new ContentInfo(digest);
var signedCms = new SignedCms(contentInfo);
var cmsSigner = new CmsSigner(data.SigningCertificate);
cmsSigner.IncludeOption = X509IncludeOption.WholeChain;
signedCms.ComputeSignature(cmsSigner);
// Encode the CMS/PKCS #7 message.
return signedCms.Encode();
}

RSACryptoServiceProvider.Decrypt() throws "bad data" in console application while the same code works in WCF application

string keyName = "c94a1e1f-177c-460a-8a34-bf1a3da300a2";
string valueToDecrypt = "GvI5sh1P3a30iX6vkfolier/rHFEDpfVhXngxp12AoUXgfCxkvICugNcvZ9yZLIrTJcsS3clyp8iA7ByRkxYvb1oYOzGznFYkKfWE/4mtarUdlyrLYX8ubYMEGeDfUIhisXGTkRe9ewr7QoNt4wJ8Avu+mRjTonPwzDGTE3f2CQ=";
string retVal = String.Empty;
RSACryptoServiceProvider rsa = null;
try
{
if (!String.IsNullOrEmpty(keyName))
{
byte[] bDecryptedValue = Convert.FromBase64String(valueToDecrypt);
// Array.Reverse(bDecryptedValue);
//byte[] bDecryptedValue = Encoding.UTF8.GetBytes(valueToDecrypt);
CspParameters cp = new CspParameters() { KeyContainerName = keyName, Flags = CspProviderFlags.UseExistingKey};
rsa = new RSACryptoServiceProvider(cp);
Console.WriteLine("RSE Object created");
byte[] byteNumber = rsa.Decrypt(bDecryptedValue, false);
retVal = ASCIIEncoding.ASCII.GetString(byteNumber);
}
}
When i used this code in a WCF application it worked properly. But when i Used the same code on a Console application. Bad data exception is throwing from the line:
byte[] byteNumber = rsa.Decrypt(bDecryptedValue, false);
I tried after reversing the byte array before decrypting and that also didn't work. I also tried creating a Crypto key security access rule since in IIS the application pool was running under "NetworkService" identity.
CryptoKeySecurity cks = new CryptoKeySecurity();
var si = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);
var sec = new System.Security.AccessControl.CryptoKeyAccessRule(si, CryptoKeyRights.GenericAll, AccessControlType.Allow);
cks.AddAccessRule(sec);
cp.CryptoKeySecurity = cks;
Any idea what would be the reason?
The Code used in WCF Service is
public string Decrypt(string keyName, string valueToDecrypt)
{
string retVal = String.Empty;
RSACryptoServiceProvider rsa = null;
try
{
if (!String.IsNullOrEmpty(keyName))
{
byte[] bDecryptedValue = Convert.FromBase64String(valueToDecrypt);
CspParameters cp = new CspParameters() { KeyContainerName = keyName, Flags = CspProviderFlags.UseExistingKey };
Console.WriteLine("Reached initialization");
rsa = new RSACryptoServiceProvider(cp);
byte[] byteNumber = rsa.Decrypt(bDecryptedValue, false);
retVal = ASCIIEncoding.ASCII.GetString(byteNumber);
}
}
catch (Exception ex)
{
retVal = ex.Message;
}
finally
{
if (rsa != null)
{
rsa.Dispose();
}
}
return retVal;
}
The function used for encryption is
string Encrypt(string valueToEncrypt)
{
string retVal = String.Empty;
RSACryptoServiceProvider rsa = null;
try
{
Key currentKey = GetActiveCryptoKey();
// while running the Kay name is "c94a1e1f-177c-460a-8a34-bf1a3da300a2"
if ((currentKey != null) && (!String.IsNullOrEmpty(currentKey.KeyName)))
{
byte[] bDecryptedValue = ASCIIEncoding.ASCII.GetBytes(valueToEncrypt);
CspParameters cp = new CspParameters() { KeyContainerName = currentKey.KeyName, Flags = CspProviderFlags.UseExistingKey};
rsa = new RSACryptoServiceProvider(cp);
byte[] byteNumber = rsa.Encrypt(bDecryptedValue, false);
retVal = Convert.ToBase64String(byteNumber);
}
}
catch (FaultException fex)
{
throw new FaultException<ServiceFault>(new ServiceFault(fex), fex.Message);
}
catch (Exception ex)
{
LogException(ex);
}
finally
{
if (rsa != null)
{
rsa.Dispose();
}
}
return retVal;
}

How do I create an ascii-armored signed OpenPGP message using ArmoredOutputStream of the BouncyCastle crypto library (C# version)

When I use ArmoredOutputStream I get a "-----BEGIN PGP MESSAGE-----" instead of a "-----BEGIN PGP SIGNATURE-----" after the clear text. I cannot figure out how to use ArmoredOutputStream on my own. Sometimes I get the signature header, but have non-base64 characters in the message. The BC legionaries must be sadists releasing such a good library with nearly no documentation how to use it...
Here is my code:
private void doTestSig(
PublicKeyAlgorithmTag encAlgorithm,
HashAlgorithmTag hashAlgorithm,
PgpPublicKey pubKey,
PgpPrivateKey privKey)
{
MemoryStream testIn = new MemoryStream(TEST_DATA, false);
MemoryStream baseOut = new MemoryStream();
ArmoredOutputStream aOut = new ArmoredOutputStream(baseOut);
aOut.BeginClearText(hashAlgorithm);
aOut.Write(testIn.ToArray(), 0, testIn.ToArray().Length);
aOut.EndClearText();
PgpSignatureGenerator sGen = new PgpSignatureGenerator(encAlgorithm, hashAlgorithm);
sGen.InitSign(PgpSignature.BinaryDocument, privKey);
sGen.GenerateOnePassVersion(false).Encode(aOut);
PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
Stream lOut = lGen.Open(
new FilterStream(aOut),
PgpLiteralData.Binary,
PgpLiteralDataGenerator.Console,
TEST_DATA.Length * 2,
DateTime.UtcNow);
int ch;
while ((ch = testIn.ReadByte()) >= 0)
{
aOut.WriteByte((byte)ch);
sGen.Update((byte)ch);
}
lOut.Write(TEST_DATA, 0, TEST_DATA.Length);
sGen.Update(TEST_DATA);
lGen.Close();
sGen.Generate().Encode(aOut);
aOut.Close();
byte[] outarr = baseOut.ToArray();
string strOut = System.Text.Encoding.UTF8.GetString(outarr, 0, outarr.Length);
// strOut gets this:
// "-----BEGIN PGP SIGNED MESSAGE-----\r\n
// Hash: SHA1\r\n
// \r\n
// hello world!\n
// hello world!\n
//
// -----BEGIN PGP MESSAGE-----\r\n
// Version: BCPG C# v1.7.0.0
// \r\n
// \r\n
// kA0DAAIR4GIXExqVFDEBy0JiCF9DT05TT0xFVBcoRmhlbGxvIHdvcmxkIQpoZWxs\r\n
// byB3b3JsZCEKaGVsbG8gd29ybGQhCmhlbGxvIHdvcmxkIQqIRgQAEQIABgUCVBco\r\n
// RgAKCRDgYhcTGpUUMXglAJwNOiEzA7H9RxaoU/gs9AoxZCOd+ACffl8lJ/6ZNpkB\r\n
// FLBjbd9wlEU3/SY=\r\n=u7Mk\r\n
// -----END PGP MESSAGE-----\r\n"
}
Finally I found a source code that demonstrates the use of ArmoredOutputStream:
// Setup signature stuff
var signatureData = new PgpSignatureGenerator(encAlgorithm, hashAlgorithm);
signatureData.InitSign(PgpSignature.CanonicalTextDocument, privKey);
foreach (string userId in pubKey.GetUserIds())
{
var subPacketGenerator = new PgpSignatureSubpacketGenerator();
subPacketGenerator.SetSignerUserId(false, userId);
signatureData.SetHashedSubpackets(subPacketGenerator.Generate());
// Just the first one!
break;
}
using (var sout = new MemoryStream())
{
using (var armoredOut = new ArmoredOutputStream(sout))
{
armoredOut.BeginClearText(hashAlgorithm);
using (MemoryStream testIn = new MemoryStream(TEST_DATA, false))
{
int ch;
while ((ch = testIn.ReadByte()) >= 0)
{
armoredOut.WriteByte((byte)ch);
signatureData.Update((byte)ch);
}
}
armoredOut.EndClearText();
using (var outputStream = new BcpgOutputStream(armoredOut))
{
signatureData.Generate().Encode(outputStream);
}
byte[] outarr = sout.ToArray();
string strOut = System.Text.Encoding.UTF8.GetString(outarr, 0, outarr.Length);
Note that this code doesn't include a fix for the missing linebreak before '-----BEGIN PGP SIGNATURE-----' bug in the library. You have to add it yourself in the output.

Create a X509Certificate2 from RSACryptoServiceProvider fails with Cannot find the requested object

Sample code:
CspParameters cspParameters = new CspParameters();
cspParameters.ProviderType = 1; // PROV_RSA_FULL
// Create the crypto service provider, generating a new
// key.
mRsaCSP = new RSACryptoServiceProvider(mDefaultKeyLength, cspParameters);
mRsaCSP.PersistKeyInCsp = true;
RSAParameters privateKey = mRsaCSP.ExportParameters(true);
byte[] rsaBytes = mRsaCSP.ExportCspBlob(true);
try
{
X509Certificate2 cert = new X509Certificate2(rsaBytes);
mKeyDataPfx = Convert.ToBase64String(cert.Export(X509ContentType.Pkcs12, password));
}
catch (Exception ce)
{
string error = ce.Message;
}
Here is my solution, using the BouncyCastle library.
// create the RSA key from an XML string
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(keyTextBox.Text);
// convert to BouncyCastle key object
var keypair = DotNetUtilities.GetRsaKeyPair(key);
var gen = new X509V3CertificateGenerator();
string certName = Path.GetFileNameWithoutExtension(fileName);
var name = new X509Name("CN=" + certName);
var serial = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(serial);
gen.SetSubjectDN(name);
gen.SetIssuerDN(name);
gen.SetNotAfter(DateTime.Now.AddYears(10));
gen.SetNotBefore(DateTime.Now);
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(keypair.Public);
// generate the certificate
var newCert = gen.Generate(keypair.Private);
// convert back to .NET certificate
var cert = DotNetUtilities.ToX509Certificate(newCert);
// export as byte array
byte[] certData = cert.Export(X509ContentType.Pfx);
File.WriteAllBytes(fileName, certData);

Categories

Resources