How can I generate a .pfx file? - c#

Is there any way to create .pfx files in order to sign documents,
I've found a program called x509 Certificate Generate,but I want to know if it can be generated in code using c#.

There is a Microsoft command-line tool makecert that can be used to generate certificates. It's part of the Windows SDK. On my machine there are half a dozen versions e.g. in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64. Then in your code you can start a process to run the executable with the appropriate parameters.

You could check out the Bouncy Castle API, it can be used to generate certificates using C#.

First of all, signing documents with self-signed certificates makes no sense unless you have custom PKI hierarchy in your organization (and in the latter case you need to know well what you are doing, which seems to be not the case).
PFX is a container for one or more certificates with associated private keys. So you don't generate "PFX file". You generate a keypair and create a certificate, which can then be exported to PFX file or to other format.
As mentioned above, BouncyCastle can generate certificates, and our SecureBlackbox library also can generate certificates and save and load them to/from many different formats.

If you read about makecert like #David Clarke's answer refers to, you will see to fulfill your requirement, you just need a managed makecert written in .NET.
Luckily the Mono guys have implemented this a long time ago,
https://github.com/mono/mono/blob/master/mcs/tools/security/makecert.cs

You can make digital signature by using adobe reader
if you are using adobe x
-then go to 3rd option from left
-here you can see signing setting
-open this and go to add id
-just enter your details and your are done .pfx file is ready where ever you browsed it....
-it is valid for 6 years

You can use OpenSSL.NET library for this.
Here is the code example how to do it:
public X509Certificate2 GeneratePfxCertificate(string certificatePath, string privateKeyPath,
string certificatePfxPath, string rootCertificatePath, string pkcs12Password)
{
string keyFileContent = File.ReadAllText(privateKeyPath);
string certFileContent = File.ReadAllText(certificatePath);
string rootCertFileContent = File.ReadAllText(rootCertificatePath);
var certBio = new BIO(certFileContent);
var rootCertBio = new BIO(rootCertFileContent);
CryptoKey cryptoKey = CryptoKey.FromPrivateKey(keyFileContent, string.Empty);
var certificate = new OpenSSL.X509.X509Certificate(certBio);
var rootCertificate = new OpenSSL.X509.X509Certificate(rootCertBio);
using (var certChain = new Stack<OpenSSL.X509.X509Certificate> { rootCertificate })
using (var p12 = new PKCS12(pkcs12Password, cryptoKey, certificate, certChain))
using (var pfxBio = BIO.MemoryBuffer())
{
p12.Write(pfxBio);
var pfxFileByteArrayContent =
pfxBio.ReadBytes((int)pfxBio.BytesPending).Array;
File.WriteAllBytes(certificatePfxPath, pfxFileByteArrayContent);
}
return new X509Certificate2(certificatePfxPath, pkcs12Password);
}

Related

What's the simplest way to distribute an RSA public key with software?

I'm working on some software that exchanges XML documents with a server. The server signs the XML using XMLDSIG and the client should verify the signature before trusting the XML. I'm using RSACryptoServiceProvider to do this. The XML is signed, but not encrypted.
I'm following the basic procedure explained in:
How to Sign XML Documents with Digital Signatures
How to Verify the Digital Signatures of XML Documents
This requires that the client software has the public key available. I want the distribution of the client software to be as simple as possible and I don't want the client to have to deal with certificates. The pair of documents referenced above conveniently skirt around the subject of distributing the public key, simply stating that the user "needs to have the same key". I don't particularly want the end user to even be aware that they have a public key, so asking them to mess around with certificates is out of the question. Since the public key is public, what I would like to do is somehow embed it within the client software. As I see it, my options are:
Install the public key during the setup process
Somehow embed the public key into the software itself, possibly within the App.config file
Is this feasible in practice? What is the simplest way of achieving this that doesn't require any user interaction or awareness?
You don't have to distribute the certificate. One of common approaches is to include the certificate in the signed document, in the KeyInfo/X509Data node.
The validation can use the embedded certificate easily and the only required infrastructure element at the client side is the certificate thumbprint and subject name. In other words, client validates the document using included certificate and then easily checks the certificate agaist the subject name and thumbprint. In case of a match, there is the assumption that a correct certificate has been provided.
Read more about technical details in one of my blog entries (this is a 3 part tutorial so you can also take a look at all other entries). Anyway, no importing certificates and no including certificates with your software, rather you have two string configuration parameters.
The embedded certificate inside the XmlDsigned document has a const size and usually the overhead is neglectable.
http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c.html
http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c_20.html
Am not sure what problem you're facing without seeing your code but, could this answer from Ji Zhou help?
public static void Main()
{
try
{ //initialze the byte arrays to the public key information.
byte[] PublicKey = {214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56,
74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222,
207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175,
108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194,
240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139,
168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171,
38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93,
106,99,179,68,175,211,164,116,64,148,226,254,172,147};
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Get an instance of RSAParameters from ExportParameters function.
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
Console.WriteLine("RijndaelManaged Key and IV have been encrypted with RSACryptoServiceProvider.");
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
}

Sign Xml with digital certificate in format of PKCS#7 in DER (ITU-T Rec. X.690)

I have a .xml file that has to be signed with digital certificate in format of PKCS#7 version 1.5 (RFC 2315) and DER (ITU-T Recommendation X.690
That .xml will be send to a govt. WebService that only accept the format I mentioned upwards.
What I'm able to do - thanks to this website is digitaly sign .xml with the .pfx file that I generated with Certificate Export Wizard explained below. The class that I'm using to sign is down on mentioned website or here.
From what I tried to understand so far I will need to sign the .xml with .pfx file according to X.690 standards but I'm only able to access this namespace:
using System.Security.Cryptography.X509Certificates;
which is obviously for X.509 format.
Note:
There are several things I'm confused about - to export the certificate into .pfx I'm using Internet Explorer - Certificate Export Wizard from there I'm able to:
Yes - export private keys - then it will be generated in PKCS#12 but .pfx
No - do not export private keys - Certificate according to standards Cryptographic Message Syntax Standard - PKCS#7 that I guess I need but I would receive .p7b file
I must say that I am a newbie in certificates and digital signatures so I'm not even sure if I'm correctly exporting the certificat and the second thing is how I can sign according to X.690 standards.
May I know how to sign according to X.690 format please?
Thank you everyone for your time and replies.
My code is following:
bool res = false;
try
{
byte[] certBytes = System.IO.File.ReadAllBytes(pvkPath);
X509Certificate2 cert = new X509Certificate2(certBytes, certPass);
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
// sign the document with the private key of the certificate
XmlDsig.SignXml(doc, cert);
// save the document
doc.Save(xmlSavePath);
// verify that the document has a signature
bool hasSignature = XmlDsig.HasSignatureElement(doc);
return res = true;
}
catch (Exception)
{ return res; }
foDigital signature in PKCS#7/CMS format is blob that contains your XML data + signer's x509 public key certificate (.cer file) + Digital signature. The entire blob is encoded in ASN 1.0 format(X690). There may be variations in the blob due to the absence of original data or the signer certificate, This variation is called detached signatures.
Digital signature is generated when you sign your xml file with the signer's private key. This signature can be verified when you send your XML file + signer's public key (as X509 .cer file)+ digital signature to the party who are interested in verifying it.
PFX/p12 is a container that contains both the signer's private key and public key. You get this key pair from either your government or your government approved key custodians. You will then use this PFX to perform digital signature.
PKCS#7 is supported by cryptoAPI.
The above are the basics. This should allow you make your queries more clearly.

Unable to sign data with X509Certificate in python

I do not have much experiance with security, but now I have to implement a signature procedure in python.
I have a certificate somename.cer. I have an c# implementation example of how to sign my string with that string as follows:
CertColl is the collection of certificates where related code finds the related certificate with Thumbprint in the previous lines and returns a list of certificates.
X509Certificate2 cert = certColl[0]
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
return Convert.ToBase64String(rsa.SignData(Encoding.GetEncoding(1251).GetBytes(my_string), new SHA1CryptoServiceProvider()));
my_string is the string to be signed and constructed within the code, but I do not need to add those steps in here
So I am trying to implement this in Python with the help of this previous Q&A
from Crypto.Util.asn1 import DerSequence
from Crypto.PublicKey import RSA
from binascii import a2b_base64
pem = open("some-path/somefile.cer") # I have a certificate with `cer` extension
lines = pem.replace(" ",'').split()
der = a2b_base64(''.join(lines[1:-1]))
cert = DerSequence()
cert.decode(der)
tbsCertificate = DerSequence()
tbsCertificate.decode(cert[0])
subjectPublicKeyInfo = tbsCertificate[6]
rsa_key = RSA.importKey(subjectPublicKeyInfo)
As I expect, now I can sign my_string with this.
rsa_key.sign("Hello World", "")
But I receive the following error:
TypeError: Private key not available in this object
Am I doing something wrong, like usnig the wrong method to mimic rsa.SignData in python?
Your certificate does not contain the private key.
From what I see in your C# code, I'm guessing you're sourcing the certificate from the Windows Certificate Store. This store can contain certificates both with and without private key attached.
.cer files, on the other hand, (usually) don't contain private keys - they only have public keys. That's why signing with it is impossible.
I'm guessing you have exported the .cer file from the Windows Certificate Store and haven't selected the "Export private key" option. You should have better luck by re-exporting it in .pfx or .pvk format and try signing with that file.
See more on this topic here

C# RSA Encrypt Private Decrypt Public?

Here is the problem I am trying to solve. Let's say I was releasing some web software built on ASP.NET MVC and I only wanted the end user to be able to add X users to the system. The software would be hosted on their servers.
I want to include an encrypted file that when the user tries to add a new user, it goes out and reads from the file an encrypted string. When the website decodes it, the clear text will be the number of allowed users.
What is the best/simplest way on my end to encrypt to generate this string on my end then decode it back to clear text in my application? Obviously I want to ensure that the end user cannot be spinning up their own encrypted string and just replace mine. I don't want to worry about having to try and obfuscate my source so that they would not be able to see how I decode the string.
Is it possible to encrypt with a private rsa key, then decrypt it with the public one? I haven't had luck with that in the code below:
var rsa = new RSACryptoServiceProvider();
var pubicKey = rsa.ToXmlString(false);
var privateKey = rsa.ToXmlString(true);
var test = "this string needs to be encrypted then decrypted";
var rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(privateKey);
var encryptedBytes = rsa2.Encrypt(Encoding.UTF8.GetBytes(test), false);
var encryptedString = Convert.ToBase64String(encryptedBytes);
var rsa3 = new RSACryptoServiceProvider();
rsa3.FromXmlString(pubicKey);
encryptedBytes = Convert.FromBase64String(encryptedString);
var decryptedString = Encoding.UTF8.GetString(rsa3.Decrypt(encryptedBytes, false));
You can use a signature strategy, where the private key is used to generate a signature that verifies that your message is authentic.
// Create message and signature on your end
string message = "Here is the license message";
var converter = new ASCIIEncoding();
byte[] plainText = converter.GetBytes(secret);
var rsaWrite = new RSACryptoServiceProvider();
var privateParams = rsaWrite.ExportParameters(true);
// Generate the public key / these can be sent to the user.
var publicParams = rsaWrite.ExportParameters(false);
byte[] signature =
rsaWrite.SignData(plainText, new SHA1CryptoServiceProvider());
// Verify from the user's side. Note that only the public parameters
// are needed.
var rsaRead = new RSACryptoServiceProvider();
rsaRead.ImportParameters(publicParams);
if (rsaRead.VerifyData(plainText,
new SHA1CryptoServiceProvider(),
signature))
{
Console.WriteLine("Verified!");
}
else
{
Console.WriteLine("NOT verified!");
}
This example was largely copied from Microsoft's site:
RSACryptoServiceProvider.SignData Method (Byte[], Object)
And here is web page that explains the concept:
Using RSA for Signing Messages
I think what you are looking for is digital signature. It doesn't matter if the content is encrypted or not, since the user has the (public) key to decrypt it. All that matters is if the content's source is you.
Since you have a config file I reckon it is XML, so you are looking for XMLDSIG.
You can easily achieve this using the SignedXml class in .Net. Then all you need to do is verify the signature when loading the config file. This method allows you to eaisly use any X509 certificates you may have. You can even embed the public key in the signed file, so the user does not need to install your cert (public key).
Your idea is correct, but I wonder about unforeseen consequences.
You state they will be running software on their servers, so this means they are hosting a service for themselves. But you also mention this service has to connect out tot he internet to add a user by validating with your server. What happens when the internet goes down or they want to have a secure system and a firewall blocks internet access to the servers? Will they completely lose their ability to function?
Just giving you a question to ask yourself :p
You don't use a public key to 'decrypt' the file. you can only decrypt the file with the private key.
In your case you could store the number of users as well a signature of the data which you create with your private key.
On the clients sever, you use your public key to verify the signature matches the data in the file (number of users)
However, it is possible that an advanced user could swap out your public key with their own and sign the file themselves.
As stated in your comment in the question, your approach is using a key from a client and a key from yourself. This will not work, as the prime numbers used in RSA are meant for use with only the corresponding private/public key.
What you need to do use your two keys and nothing from the client or the client's two keys and nothing of yours. For example,
You could sign it using your two keys by encrypting with your private key and allowing the client to decrypt using your public key.
You could encrypt it using your client's public key and have them decrypt is using their (the client's) private key.
Hope this helps!

Digitally sign in PHP using private key, verify in C#

I am working on a feature that needs me to digitally sign a short string in PHP, and verify the string's signature in C#.
I would really like to use openssl_sign in PHP, because of its simplicity, but all the information I can find on Google indicates that this will not work.
There are some external libraries that claim to do this well, however as this is a hobby project I would rather not purchase such a library.
So what are the alternatives here? Full interoperability between C# and PHP is required. Libraries besides OpenSSL can be used.
I've done something very similar using Bouncy Castle Crypto APIs. It appears PHP openssl_sign uses SHA1 by default. If you are using anything other than the default you'll need to change the algorithm parameter for GetSigner.
string base64pubkey = "<!-- BASE64 representation of your pubkey from open ssl -->";
RsaKeyParameters pubKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(base64pubkey)) as RsaKeyParameters;
byte[] signature = Convert.FromBase64String("<!-- BASE64 representation of your sig -->");
byte[] message = Encoding.ASCII.GetBytes("Something that has been signed");
ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
sig.Init(false, pubKey);
sig.BlockUpdate(message, 0, message.Length);
if (sig.VerifySignature(signature))
{
Console.WriteLine("all good!");
}
You may use to check the digital signature smth like this:
string publicKey = "some key";
// Verifying Step 1: Create the digital signature algorithm object
DSACryptoServiceProvider verifier = new DSACryptoServiceProvider();
// Verifying Step 2: Import the signature and public key.
verifier.FromXmlString(publicKey);
// Verifying Step 3: Store the data to be verified in a byte array
FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(file2);
byte[] data = reader.ReadBytes((int)file2.Length);
// Verifying Step 4: Call the VerifyData method
if (verifier.VerifyData(data, signature))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature NOT verified");
reader.Close();
file.Close();
Is there a reason you need something as complex as SSL signing? Can't you just use a simple one-way hash like MD5/SHA-1 on the string? If all you're looking for is verification that the string wasn't tampered with, that should be sufficient.
So looking at this - this guy appears to have asymmetric signing and encrypting working between PHP and C#. Signing should not be a problem, SHA* and MD* are standard, and so it's very very unlikely that is going to not be compatible (although you should be looking at SHA256 as MD* and SHA1 are deprecated due to vulnerabilities)
We're missing some context as to why you need to sign it. You may not need to.
The important question is: what guarantees do you need from your data?
If all you need to do is verify the integrity of the data, a hash will do the job. If you need to verify where it's coming from, you need to sign it. If you need both, hash it, concatenate the payload with the hash, and sign the whole thing.
Regarding cross-platform libraries... you really should need to worry about it. A SHA1 is a SHA1 is a SHA1, no matter which library generated it. Same thing with generating and verifying digital signatures. Use what's easiest in PHP and use what's easiest in C#. If they're both set up correctly you shouldn't need to worry about it.

Categories

Resources