The following command is use to make a keystore called myalias.p12 and export a certificate called myalias2.cer.
Java Keytool is a key and certificate management utility. It allows users to manage their own public/private key pairs and certificates.
E:\>keytool -genkeypair -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -validity 36000 -alias myalias2 -keystore myalias.p12 -storetype pkcs12 -dname "cn=www.myalias.com, ou=myalias2, o=myalias2, l=tp, st=tp, c=tw" -storepass 123456 -keypass 123456
E:\>keytool -export -alias myalias2 -keystore myalias.p12 -storetype pkcs12 -rfc -file myalias2.cer -storepass 123456
Encryption:
string input="hello";
X509Certificate2 myCertificate = GetCertFromCerFile("e:\\myalias2.cer");
RSACryptoServiceProvider provider1 = (RSACryptoServiceProvider)myCertificate.PublicKey.Key;
byte[] buffer1 = Encoding.UTF8.GetBytes(input);
byte[] result = provider1.Encrypt(buffer1, false);
string data= Convert.ToBase64String(result);
Decryption:
44. RSACryptoServiceProvider provider2 = (RSACryptoServiceProvider)myCertificate.PrivateKey;
45. byte[] buffer2 = Convert.FromBase64String(data);
46. byte[] result2 = provider2.Decrypt(buffer2, false); // <-- error here
47. String decryptedMessage = Encoding.UTF8.GetString(result2);
It can normally perform the encryption operations. But, I found some errors on Line 46, (performing the decryption):
A first chance exception of type
'System.NullReferenceException'
occurred in CertTest.exe The thread
'' (0xcc8) has exited
with code 0 (0x0). at
CertTest.Program.Decrypt(String data)
in
D:\vsworkspace\CertTest\CertTest\Program.cs:line
46 at
CertTest.Program.Main(String[] args)
in
D:\vsworkspace\CertTest\CertTest\Program.cs:line
29
Anyone have Idea? Because I don't know how to solve this problem.
Thanks very much!
The NullReferenceException you're getting is because PrivateKey is null. This is because .cer files only includes a single .X509 certificate, which only includes the public key.
In this case that means you can only encrypt data using the certificate. In order to decrypt it you'll need the private key.
You can get access to the private key using the .p12 (or .pfx) file. This PKCS#12 file includes (in general) both the private key (password protected) and the certificate(s).
There are several X509Certificate[2] constructor that will accept a password and automatically decrypt the private key. Once loaded from the .p12 file your code will receive a valid (non-null) RSACryptoServiceProvider instance and you'll be able to decrypt the data.
BTW you should not encrypt string (or data) this way using RSA :-)
For more details read http://pages.infinit.net/ctech/20031101-0151.html
Related
This is the first time I am dealing in code with certificates.
My problem is, that I need to sign emails with a certificate that is split in a .cert and in a .key file. Those files need to be read from the file system and cannot be stored in some kind certificate store.
The self signed private key for testing purposes starts like this:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,B5F1CE2CAB1B3CE20326EF3CD60D230
tmPJKtI8S4dGl2B29HhyHlF6Dp6/mDldldX/n2+gYvfSaa4TEPVFQMJfLsRxp1ey
...
Importing the .cert part is fairly easy and straight forward:
X509Certificate2 certificate = new X509Certificate2(_emailConfig.PathToCertificate);
But I fail to figure out how to add the private key which I need for the actual signing.
This needs to also work on Linux.
Any help would be appreciated.
Update 0:
I obtained a string called privateKey that only contains the private key without any PEM syntax.
Then I did the following:
var privateKeyBytes = Convert.FromBase64String(privateKey);
using var rsa = RSA.Create();
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
Then I assigned the key:
certificate.PrivateKey = rsa;
The problem is I am getting the following Exception: System.Security.Cryptography.CryptographicException : ASN1 corrupted data.
I have an encrypted base64 file "PersonalCodes.txt" and a private key to it "private.key". The key is in .pem (---begin private key -- etc.) and is encrypted with -gost89.
I need to use an OpenSSL.NET for this (apparently System.Security.Cryptography have no support on .pem keys) For the simple openssl client , the commands will be:
base64 -d -in "PersonalCodes.txt" -out "PersonalCodesOUT.txt"
smime -decrypt -in "PersonalCodesOUT.txt" -inform der -inkey "private.key" -out "DecryptedCodes.txt"
First one is decrypting from base64 -ok. easy. Next one is decrypting with gost89 key.
As for the .NET - honestly , i'm completely frustrated. I added a reference to an openssl wrapper, and found an example how to get a key from file :
byte[] b = System.IO.File.ReadAllBytes(#"D:\private.key");
OpenSSL.Core.BIO bio = new OpenSSL.Core.BIO(b);
OpenSSL.Crypto.CryptoKey key = OpenSSL.Crypto.CryptoKey.FromPrivateKey(bio, "");
But this gives me an exception : unsupported private key algorithm According to google - i need to help openssl to see gost89
How should i do that in c#?
Moreover, can anyone help me with a the last command - decrypting with a private key in openssl.net? Ty...
-------------------------------------------------------------------------------
Found this implementation of the gost89 :
https://github.com/embedthis/packages/blob/master/openssl/openssl-1.0.1c/engines/ccgost/gost89.c
However it also doesnt give a function to decrypt a file with key...
Currently I perform this operation through openssl, and I have had no problem with the generated file
openssl dgst -sha256 -sign privateKey.key -out file.txt.signature file.txt
Now, we want to automate the generation of the file using C #, but I have not been able to get the same result.
public class Program
{
static void Main(string[] args)
{
Console.WriteLine(CreateToken("key...", "text"));
Console.ReadLine();
}
public static string CreateToken(string key, string message)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return System.Text.Encoding.UTF8.GetString(hashmessage);
}
}
I'm new to working with this, what would be the right way?
Am I not retrieving the information properly ?, Should I get the content directly from the file?
Thank you very much.
Signature generation is not the same thing as HMAC message authentication and it uses a different key. As HMAC can use a key of any size, it will probably take the private key, but that's not how it is supposed to work. RSA is an asymmetric algorithm that uses private and public keys, MAC uses symmetric, secret keys. The dgst -sign instead uses RSA PKCS#1 v1.5 padding to sign the file.
From the OpenSSL Wiki on dgst:
When signing a file, dgst will automatically determine the algorithm (RSA, ECC, etc) to use for signing based on the private key's ASN.1 info. When verifying signatures, it only handles the RSA, DSA, or ECDSA signature itself, not the related data to identify the signer and algorithm used in formats such as x.509, CMS, and S/MIME.
HMAC is not the same thing as SHA-256 either. RSA signature generation uses a hash, not a HMAC. You should use the SHA256 class to create a hash. HMAC is a message authentication code build using the SHA-256 hash. However, the SHA class is not needed as signature generation usually includes the hash generation (you sign a message, not a hash value).
So to create a signature, take a look at the RSAPKCS1SignatureFormatter class, it includes an example at the bottom. Try again using this example.
Make sure your message only contains ASCII (both in the text file as in your string) or your result may fail as well.
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 have a DER file with sha1RSA as the Signature Algorithm. I have to encrypt some data using it.
Can anyone tell me how do I load the DER file and use the RSA public key in it to encrypt my data in .NET?
DER or Distinguished Encoding Rules is a method for encoding a data object, such as an X.509 certificate, to be digitally signed or to have its signature verified.
The X.509 certificate only contains the public key. You need the private key to decrypt!
Typically private keys are exchanged in .PFX files, which are password protected.
-- EDIT --
Sorry I misread your question. Yes, you can encrypt with the public key of X.509 certificate. You can load the .der by using System.Security.Cryptography.X509Certificates.X509Certificate2.Import method.
Then convert the public and encrypt, something like:
rsa = (RSACryptoServiceProvider) certificate.PublicKey.Key;
encryptedText = rsa.Encrypt(msg, true);