Hello my goal is it to encrypt the password of a zipfile. As for now I only had to generate a SHA Hash which will be my password and used the RSA-Cryptoprovider with me private key to encrypt the password.
Now I need to use .p7b and .p12 certificates to do this task.
But I dont understand what do I need those files for after some research I figured out that .p12 will be probably the file that I use to encrypt my password but what do I need .p7b for?
That is what I did so far with it, it seems to work because I can read the string but still what do I need my .p7b file for?
var password = #"test";
var p12FilePath = #"key\Test.p12";
var text = #"myFutureZipPassword";
X509Certificate2 cert = new X509Certificate2(p12FilePath, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
byte[] certData = cert.Export(X509ContentType.Pfx, password);
RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PrivateKey;
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
var sign = rsaKey.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
var str = System.Text.Encoding.Default.GetString(sign);
Neither p12 - the extension for PKCS#12 key/certificate stores - nor .p7b - the extension for PKCS#7 binary Cryptographic Message Syntax - is a certificate.
PKCS#12 can be used to store multiple private key / certificate chains (required to sign or decrypt) or just trusted certificates (used to verify or encrypt). Other information can be stored as well, but for your assignment you should just use it as key / certificate store.
The PKCS#7 standard specifies the Cryptographic Message Syntax or CMS. It specifies a container format which can be used to specify signed or enveloped (read: encrypted) messages / files. Whereas RSA by itself can encrypt small files, PKCS#7 allows you to use a well specified form of hybrid encryption.
The container format indicates and may contain the certificates used to perform the encryption so you can choose which key to use. It also specifies the algorithms used to perform the encryption. To use it you need a higher level API than RSACryptoServiceProvider; it is provided in the PKCS namespace within the .NET framework (start with EnvelopedCms). PKCS stands for Public Key Cryptography Standards, which were first created by RSA Labs and then copied and continued in RFC's.
The structure of PKCS#12 and PKCS#7 have been defined in a language that defines data structures called ASN.1. The structures are then encoded using a binary encoding format called BER / DER. However, to make sure that the messages are correctly transmitted over a text based interface, the PKCS#7 file is often ASCII armored using PEM text encoding, which is just basically a few header / footer lines with base 64 encoded binary in between. The b is there in the filename to show that the PEM encoding should not be performed.
Note that sometimes the PKCS#7 / CMS is also used to simply store certificates, which could be used for encryption as you only need the public key for that. However, it is much nicer to use PKCS#12 for that.
I want to verify a private key signed SHA256 hash using the CryptographicEngine in a UWP application. The hash is created externally and is signed with a private RSA key with passphrase. For this example however, I also generate the unsigned hash. Both hashes are then compared at the end to verify that they are the same.
I have created my private and public keys using OSX command line, specified in this blog.
This gave me two .pem files. My public key has the following structure:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fasaNKpXDf4B4ObQ76X
qOaSRaedFCAHvsW4G0PzxL/...ETC ETC
-----END PUBLIC KEY-----
Here is my C# code to decrypt the hash:
//HASH THE INPUT STRING
var inputText = "stringtohash";
// put the string in a buffer, UTF-8 encoded...
IBuffer input = CryptographicBuffer.ConvertStringToBinary(inputText,
BinaryStringEncoding.Utf8);
// hash it...
var hasher = HashAlgorithmProvider.OpenAlgorithm("SHA256");
IBuffer hashed = hasher.HashData(input);
// format it...
string ourhash = CryptographicBuffer.EncodeToBase64String(hashed);
Debug.WriteLine(ourhash);
//CONVERT EXTERNAL HASH TO BUFFER
IBuffer data = CryptographicBuffer.DecodeFromBase64String("b18fbf9bc0fc7595af646155e18b71e1aeccf01719f9f293c72217d7b95cc2106edb419078c4c5c1c7f7d106b90198a4f26beb49ff4a714db4bface1f94fff193b8126ce05fe13825144a3dde97f55399846b6fd768f1fb152f1ba71bbf5cde8c1a7e58621a493070256e2444db36c346a88e870906529cf13c072ead50b6a01b2e74c7ef8c5d423e8ea25220f524b563ae2c3345b7837f9cd1a357540b1380c86287b9a240cf67f7518f11418352b665b657c5ffb6cbcb6126ec59e360de6304392b78cf4de79b52d73b8292df6a1e643d0c0f0945aae5949b391e2915772c996f03e6d1879192b7edf0f40c01b875e768358aa47a992070f628418ddf06472");
//CONVERT PUBLIC KEY TO BUFFER
IBuffer publickey = CryptographicBuffer.DecodeFromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fasaNKpXDf4B4ObQ76XqOaSRaedFCAHvsW4G0PzxL / RuAQFz80esZPyyDCps1PAbTKzQ + QblChPo7PJkbsU4HzNN4PIRGh5xum6SRmdvOowrlTUtyxdOkRJoFxmiR / VCea + PUspt26F7PLcK9ao5 + hVzMvPuqdYenqzd01f1t5hQEhFQ9qjB6Es8fpizHd / RSRfZ7n6rVKm9wYfCRLB7GJ7IHhWGuZrx9fjzsbW8eagu06qRhnUuR5oDVjXC8ZeazsRiw50xMuOzkhX9Oo081IYikwCgseJmQhT7vF4lZoyeB4qJpwTCA + glSy1w9N8ZfxyXK8QaT2RsrBrzl0ZCwIDAQAB");
// Open an asymmetric algorithm provider for the specified algorithm.
AsymmetricKeyAlgorithmProvider rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// Import Key
CryptographicKey key = rsa.ImportPublicKey(publickey, CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
// Decrypt the Hash using our Key
IBuffer result = CryptographicEngine.Decrypt(key, data, null);
Debug.WriteLine(result.ToString());
//Compare the two hashes
if (data == result) {
//Hash is verified!
}
Unfortunately when reaching the Decrypt method I get a NotImplementedException with error
The method or operation is not implemented
I researched online and I understand what needs to happen in theory but I don't know how to debug this further. What can I try?
Although both called PKCS#1 v1.5 padding, the padding for signature generation and encryption is not identical, see RFC 3447 for more details.
If you look at the RsaPkcs1 property you can see it is aimed at encryption:
Use the string retrieved by this property to set the asymmetric algorithm name when you call the OpenAlgorithm method. The string represents an RSA public key algorithm that uses PKCS1 to pad the plaintext. No hash algorithm is used.
As I don't see any option for "raw RSA", i.e. RSA without padding, it seems you are only able to verify your signature. However, RSA decryption expects an RSA private key. It's very likely that you get the error because of this: if you try and decrypt with a public key it will fail.
If you want to precompute the hash you can use VerifySignatureWithHashInput.
For other functionality you may have to use e.g. the C# lightweight API of Bouncy Castle. In the end you don't need platform provided cryptography to verify a signature.
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);
}
}
I'm trying to port the following Java code to a C# equivalent:
public static String encrypt(String value, String key) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] bytes = value.getBytes(Charset.forName("UTF-8"));
X509EncodedKeySpec x509 = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(key));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(x509);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
bytes = cipher.doFinal(bytes);
return DatatypeConverter.printBase64Binary(bytes);
}
So far I managed to write the following in C#, using the BouncyCastle library for .NET:
public static string Encrypt(string value, string key)
{
var bytes = Encoding.UTF8.GetBytes(value);
var publicKeyBytes = Convert.FromBase64String(key);
var asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
var rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter;
var cipher = CipherUtilities.GetCipher("RSA");
cipher.Init(true, rsaKeyParameters);
var processBlock = cipher.DoFinal(bytes);
return Convert.ToBase64String(processBlock);
}
The two methods, though, produce different results even if called with the same parameters.
For testing purposes, I'm using the following public RSA key:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItTMjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCuFUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB
Could you please help me to port the Java code successfully or suggest an alternative to get the same result in C#?
EDIT1: output in Java is different each time I run the program. I don't think that any padding was specified, so I don't understand what makes the output random.
EDIT2: Java uses PKCS1 by default, so it was enough to specify it in the C# cipher initialization to get the same encryption type (although not the same result, which was irrelevant at this point).
As an educated guess, I would say that Java adds random padding to create a stronger encryption.
Most practical implementations of RSA do this, and as the wiki puts it...
Because RSA encryption is a deterministic encryption algorithm – i.e., has no random component – an attacker can successfully launch a chosen plaintext attack against the cryptosystem, by encrypting likely plaintexts under the public key and test if they are equal to the ciphertext. A cryptosystem is called semantically secure if an attacker cannot distinguish two encryptions from each other even if the attacker knows (or has chosen) the corresponding plaintexts. As described above, RSA without padding is not semantically secure.
This is likely why your two methods don't output the same.
I've generate a self-signed certificates(X509 certificate) and want to use the private key to sign some document to make digital signature and I'm doing it in C#.
How can I import .pvk file? Do I need to import from key store?
And can I use this code to sign and create a digital signature?
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(RSA);
RSAFormatter.SetHashAlgorithm("SHA1");
RSAFormatter.SetKey(cert.PrivateKey);
byte[] SignedHash = RSAFormatter.CreateSignature(data);
Try tho Initialize your RSA like this:
RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)cert.PrivateKey;
To generate a signature I use rsa.SignData(data, "sha1");
First of all you need to determine, in what format the signature should be made. If you deal with certificates, most likely you will create PKCS#7 or CMS signature. There's a class in .NET for CMS signatures.
The next steps depend on whether you need certificate-based PKCS#7 signature or RSA (PKCS#1) signature.
Side note - putting several questions into one makes it hard to answer properly. Also most of your questions have lots of answers if you do the search.