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...
Related
I have a sample C# script that handle decryption. By using the key provided with the sample, the code is working fine:
public static string DecryptByPrivateKey(string s, string key)
{
s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
engine.Init(false, GetPrivateKeyParameter(key));
byte[] byteData = Convert.FromBase64String(s);
var resultData = engine.ProcessBlock(byteData, 0, byteData.Length);
return CommonHelper.EncodeBase64(resultData);
}
private static AsymmetricKeyParameter GetPrivateKeyParameter(string s)
{
s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
byte[] privateInfoByte = Convert.FromBase64String(s);
AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
return priKey;
}
However, when using our own private key, above function will throw exception at PrivateKeyFactory.CreateKey():
System.ArgumentException: 'Unknown object in GetInstance:
Org.BouncyCastle.Asn1.DerInteger Parameter name: obj'
Our public/private key strings are generated with openssl on windows with command line:
openssl pkcs12 -in cert.pfx -nocerts -nodes -out cert.key
openssl rsa -in cert.key -out cert_private.key
openssl rsa -in cert.key -pubout -out cert_public.key
The key strings are in base64 format. The sample private key have 1624 characters while our private key has 1592 only.
In Visual Studio debug mode I checked the parameter privateInfoByte is a "byte[1192]". I have no clue on the error.
I am not sure my key strings are in correct format. How can I verify? Thank you.
According to the documentation, PrivateKeyFactory.CreateKey() expects a private key in PKCS#8 format. However, cert_private.key has the PKCS#1 format, which is thus incompatible.
cert.key, on the other hand, contains among other things the private key in PKCS#8 format, which can be extracted from this. Alternatively, the PKCS#1 formatted key can be converted to a PKCS#8 formatted key using OpenSSL, see openssl pkcs8:
openssl pkcs8 -topk8 -nocrypt -in <pkcs#1 key file> -out <pkcs#8 key file>
cert_private.key and cert.key contain the PEM encoded keys consisting of header, footer and the Base64 encoding of the DER encoded keys.
PrivateKeyFactory.CreateKey() expects a DER encoded key, i.e. from the PEM encoded key determined e.g. from cert.key, header, footer and line breaks are to be removed and the rest has to be Base64 decoded (which seems to be already considered in your code).
Header/footer of the PEM encoded PKCS#8 key are -----BEGIN PRIVATE KEY-----/-----END PRIVATE KEY----- and of the PEM encoded PKCS#1 key -----BEGIN RSA PRIVATE KEY----- / -----END RSA PRIVATE KEY-----.
Edit:
The statement openssl pkcs12 -out... -in... parses a PKCS#12 file and writes the contained certificates and private keys PEM encoded to a file. -nocerts causes the contained certificates not to be written, -nodes causes the private keys not to be encrypted (i.e. your statement exports only the PEM encoded private key unencrypted). The format of the exported private key is not explicitly specified, but can be easily identified as PKCS#8 using header/footer or an ASN.1 parser.
The statement openssl rsa -in... -out... finally exports the PKCS#8 formatted key to a PKCS#1 formatted key (PEM encoded). So to get the needed PKCS#8 formatted key you have the option to 1st use the PKCS#8 formatted key exported directly from the PKCS#12 file (s. previous section) or 2nd convert the PKCS#1 formatted key back to a PKCS#8 formatted key.
Therefore: yes, cert.pfx is a file in PKCS#12 format, and yes, cert_private.key is a key in PKCS#1 format, which is incompatible with PrivateKeyFactory.CreateKey(), which requires a key in PKCS#8 format.
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.
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 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);
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