problem generating pgp keys? - c#

I'm using RSACryptoServiceProvider I've generated public key and private key. The keys generated by it are in the following format:
Public key:
<RSAKeyValue>
<Modulus>m9bAoh2...eGNKYs=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
Private key:
<RSAKeyValue>
<Modulus>m9bAo...ZAIeGNKYs=</Modulus>
<Exponent>AQAB</Exponent>
<P>xGj/UcXs...R1lmeVQ==</P>
<Q>yx6e18aP...GXzXIXw==</Q>
<DP>NyxvnJ...1xAsEyQ==</DP>
<DQ>La17Jycd...FhApEqwznQ==</DQ>
<InverseQ>JrG7WCT...Hp3OWA==</InverseQ>
<D>RdWsOFn....KL699Vh6HK0=</D>
</RSAKeyValue>
but using PGP Desktop i've generated keys like this -
Public key:
mQCNBEoOlp8BBACi/3EvBZ83ZduvG6YHu5F0P7Z3xOnpIsaPvTk0q+dnjwDUa5sU
lEFbUZgDXSz7ZRhyiNqUOy+IG3ghPxpiKGBtldVpi33qaFCCEBiqsxRRpVCLgTUK
HP2kH5ysrlFWkxTo
=a4t9
Private key:
lQHgBEoOlp8BBACi/3EvBZ83ZduvG6YHu5F0P7Z3xOnpIsaPvTk0q+dnjwDUa5sU
lEFbUZgDXSz7ZRhyiNqUOy+IG3ghPxpiKGBtldVpi33qaFCCEBiqsxRRpVCLgTUK
waBnEitQti3XgUUEZnz/rnXcQVM0QFBe6H5x8fMDUw==
=CVPD
So when I'm passing the keys generated by PGP Desktop it is able to do encryption and decryption perfectly but when im passing the keys generated by RSACryptoServiceProvider I'm not able to encrypt and decrypt?
Can anyone please tell me how to generate keys in the pattern generated by PGP?

using the bouncycastle c# library this is how i generate key pairs.
public void GenerateKey(string username, string password, string keyStoreUrl)
{
IAsymmetricCipherKeyPairGenerator kpg = new RsaKeyPairGenerator();
kpg.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(0x13), new SecureRandom(), 1024, 8));
AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
FileStream out1 = new FileInfo(string.Format("{0}secret.asc", keyStoreUrl)).OpenWrite();
FileStream out2 = new FileInfo(string.Format("{0}pub.asc", keyStoreUrl)).OpenWrite();
ExportKeyPair(out1, out2, kp.Public, kp.Private, username, password.ToCharArray(), true);
}
private static void ExportKeyPair(
Stream secretOut,
Stream publicOut,
AsymmetricKeyParameter publicKey,
AsymmetricKeyParameter privateKey,
string identity,
char[] passPhrase,
bool armor)
{
if (armor)
{
secretOut = new ArmoredOutputStream(secretOut);
}
PgpSecretKey secretKey = new PgpSecretKey(
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
publicKey,
privateKey,
DateTime.Now,
identity,
SymmetricKeyAlgorithmTag.Cast5,
passPhrase,
null,
null,
new SecureRandom()
// ,"BC"
);
secretKey.Encode(secretOut);
secretOut.Close();
if (armor)
{
publicOut = new ArmoredOutputStream(publicOut);
}
PgpPublicKey key = secretKey.PublicKey;
key.Encode(publicOut);
publicOut.Close();
}
and it generate private and public keys in armored ASCII format such as.
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.32
mIsEShU7ywEEAKtxKTtGTyUaVxFuWBpziA2l7qDKhe6jznre3DMPuzDnN4Ax573a
7s/bPOkzkK9tEUGFw+BW6F4DkKydv8SQfSN5Vvc0RFMha8X1E8jki1oXTIPA8bKK
dg8ZewZt8+Zwpt5IPAkIydmxDhMjwd71ay3p1ypOfROFPOfc2dBPx/0JAAUTtAdo
YW1zbWFuiJwEEAECAAYFAkoVdAsACgkQEz/ESPB1tojuIQP8CjAzJx8PoIN33pxQ
AfGF+fMCZx8/m7dDBE113aiio25BCvNKOpFwye2UK4ioKN70k24pzkyi8AZO22/s
u6GL7XEiiBZLPynBxJR4A7PzvD3KNqdQUqesu9IkPFyXz3UFH3clR0hnZtZtgnbk
L9dvj5RYVuGiS3Dcf1zoLMOiCdc=
=dFfG
-----END PGP PUBLIC KEY BLOCK-----

RSA and PGP are different.
What you are essentially asking is how do I run my petrol car on diesel? The answer is you can't.
You should look into PGP CommandLine - this allows you to perform PGP commands from the command line.

thanks for the good methods, was faffing around the web for them since quite a while,
some correction tho...
After a call to
ExportKeyPair(out1, out2, kp.Public, kp.Private, username, password.ToCharArray(), true);
please also call
out1.Close();
out2.Close();
A sample private key generated from the above routine
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: BCPG C# v1.6.1.0
lQHqBEvhYOcBBACa5HjZ14ULRvZLKj+rwscQh63Zd9rnfZmVKN5fNsK+ocxxV8rc
TWa6P3knIWCra1lqZ1onNtM8tL1XRuK9pagu7XPjjHUR37ajYv/e0/w9IHlOBtM4
1T3oMM48FBH5WGZswOQnTCHoHpZilx7zeJgcyoUayM9uaWGWVLb6PqAE2QAFE/8D
AwL4BEE4Y+mD6GB0ctnbN4tZuctydODYJUNOK3p+UdgEh5rj5nOelB5h3kqFWdwq
8F3EBxB4guRnLOxIeSjzvFoFpqb4QSrM4brdisaHoK0qgrsyCaQhdepVlz662hSD
5bxJPQqmJ4c9X7x6tTMwDAseoz+VUK9U91iN9jv72hp2dXJYjJvBbkTX9euz2i4P
HrlLV2DuOeGWipsb+sIOuYqpZoK5aMq5AAGTTmmApYam/+0d2lXTt+Cw0FkoN1U+
CWriVFE+x58/MmpqKttlrHyp/c7aRmdxeKheY7QAnKPmTRFZAu6HR/DnLSya6+Qz
MqsYBZAocDs7Bg9U6N79Ynl7mkChoVR4ZwJE/OXgHDRSYlcBwT++frHI06cn1l8t
f0CWU/Z6EuYj/rmgL/v5ln7EQ2H+SRypPxYJKK8dTcu2uk5Ev1x4EOQ2nF1BxBB1
CceSVEimc2TDcVj0K7QIc3BhcmVraDOInAQQAQIABgUCS+FS1wAKCRBHXl7hbFhY
BLInA/9TPwmivxofs7/y4xmrl0X+Ruish0l+KC45/MQGU1bT2MYCR5jefyaUIHMK
gH8bX4DHobBFxtkTXoTgpZmm5JNHGiSQoOXqW7iqHOkp6q6rkwV9BYvfsbjMsfAB
bV7l29CMoMDj1qB3k9CJDP4MuorEI5Qx30x07Mm2+uwcYC2+Ag==
=jh9t
-----END PGP PRIVATE KEY BLOCK-----
thanks once again for the above methods.
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.6.1.0
mIsES+Fg5wEEAJrkeNnXhQtG9ksqP6vCxxCHrdl32ud9mZUo3l82wr6hzHFXytxN
Zro/eSchYKtrWWpnWic20zy0vVdG4r2lqC7tc+OMdRHftqNi/97T/D0geU4G0zjV
PegwzjwUEflYZmzA5CdMIegelmKXHvN4mBzKhRrIz25pYZZUtvo+oATZAAUTtAhz
cGFyZWtoM4icBBABAgAGBQJL4VLXAAoJEEdeXuFsWFgEsicD/1M/CaK/Gh+zv/Lj
GauXRf5G6KyHSX4oLjn8xAZTVtPYxgJHmN5/JpQgcwqAfxtfgMehsEXG2RNehOCl
mabkk0caJJCg5epbuKoc6SnqrquTBX0Fi9+xuMyx8AFtXuXb0IygwOPWoHeT0IkM
/gy6isQjlDHfTHTsybb67BxgLb4C
=ZyOZ
-----END PGP PUBLIC KEY BLOCK-----

Related

C# - How to Decrypt an Encrypted Private Key with Bouncy Castle

I have a private key that was generated by running:
openssl req -new -sha384 -x509 -days 63524 -subj "/C=CA/ST=State/L=City/O=Org/CN=Org-CA" -extensions v3_ca -keyout Org-CA.key -out Org-CA.pem -passout pass:pass1234
I need to use this private key and certificate to sign client CSRs. I used to use OpenSSL to do this, but I need to do this in C# instead.
I've found examples of what I want to do online, but those examples are using bouncy castle and an un-encrypted private key.
The key file looks like this:
-----BEGIN ENCRYPTED PRIVATE KEY-----
....
-----END ENCRYPTED PRIVATE KEY-----
And I'm trying to load it by doing this:
var privatekey = File.ReadAllBytes(#"Org-CA.key");
var rsaKeyParameters = PrivateKeyFactory.DecryptKey("pass1234".ToArray(), privatekey);
But thats not working. I get an error saying Wrong number of elements in sequence (Parameter 'seq')'
Is this how I'm supposed to be decrypting and loading the private key?
Depending on your .NET version, you may not need BouncyCastle at all. As of .NET Core 3.1 there is RSA.ImportEncryptedPkcs8PrivateKey() for DER encoded encrypted private PKCS#8 keys and as of .NET 5.0 there is even RSA.ImportFromEncryptedPem() for PEM encoded encrypted keys.
Otherwise with C#/BouncyCastle the import of an encrypted private PKCS#8 key is available e.g. with:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
...
string encPkcs8 = #"-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----";
StringReader stringReader = new StringReader(encPkcs8);
PemReader pemReader = new PemReader(stringReader, new PasswordFinder("<your password>"));
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)pemReader.ReadObject();
...
with the following implementation of the IPasswordFinder interface:
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string pwd) => password = pwd;
public char[] GetPassword() => password.ToCharArray();
}
If necessary, a conversion from keyParams to System.Security.Cryptography.RSAParameters is possible with:
using Org.BouncyCastle.Security;
...
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(keyParams);
which can be imported directly e.g. with RSA.ImportParameters().
Edit:
After digging through the C#/BouncyCastle source code, your way is also possible (which I didn't know before).
DecryptKey() has several overloads, one of which can handle the DER encoded encrypted key as already suspected by Maarten Bodewes in his comment. The latter can be easily generated with the Org.BouncyCastle.Utilities.IO.Pem.PemReader() class.
Note that this PemReader is different from the one in the first implementation (different namespaces), which is why I use the namespace explicitly in the following code snippet. With this approach, the RsaPrivateCrtKeyParameters instance can be generated as follows:
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
...
StringReader stringReader = new StringReader(encPkcs8);
Org.BouncyCastle.Utilities.IO.Pem.PemReader pemReader = new Org.BouncyCastle.Utilities.IO.Pem.PemReader(stringReader);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pem = pemReader.ReadPemObject();
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.DecryptKey("<your password>".ToCharArray(), pem.Content);
...
pem.Content contains the DER encoded encrypted private PKCS#8 key.

convert PEM encoded RSA public key to AsymmetricKeyParameter

I am trying o create a method that constructs an AsymmetricKeyParameter from a PEM encoded public key. Unfortunately, pemReader.ReadObject() return null.
Here's a working solution for a private key: convert PEM encoded RSA private key to AsymmetricKeyParameter
What is wrong with this method?
static AsymmetricKeyParameter ReadPublicKeyFromPemEncodedString(string pemEncodedKey)
{
AsymmetricKeyParameter result = null;
using (var stringReader = new StringReader(pemEncodedKey))
{
var pemReader = new PemReader(stringReader);
var pemObject = pemReader.ReadObject(); // null!
result = ((AsymmetricCipherKeyPair)pemObject).Public;
}
return result;
}
Here is the PEM-encoded public key I am testing with. I have tried without the comment and also removing SSH2.
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-20170608"
AAAAB3NzaC1yc2EAAAABJQAAAQEAk0AmagKx285Ufbri/olc+f3WagL1Ho+DrYdD
SbuU7cJAq+uD9xGvvP9m2JavSP4wO9i9pB/cmCFMPoIj3oGJt1/cnLb/U2juneOw
6Uo0N3F8TXdyXfZNAIPhq/jw0YfIypTFTTvFkKXfTArIwW/bQBW8/dujFR8i5CxP
jRKRDOBEy0PPOLJDD0iUr9GX/h/EO4jQ7B/GszjhPiPx+gJCilaMY+jrSczjxpsK
OXzpZEdT1NqMrzgvIZPHYhQzAiw9vQzov3vezDwKgKcRrUixZ2B8uiEQNn7Wa2Qz
WF3vL+6CGflFNYQcc0leDQBe86baYhCollouP4jfaH9KcMkYYw==
---- END SSH2 PUBLIC KEY ----
Bouncy castle just does not understand this format of public key (SSH2) (you can verify this by looking at source code of PemReader if you would like to). Unfortunately I don't know how to convert it to appropriate format in C#, but you can do that with many tools, for example with ssh-keygen (also available in gitbash for windows), or openssl. Your public key will look like this when converted to PEM:
-----BEGIN RSA PUBLIC KEY-----
MIIBCAKCAQEAk0AmagKx285Ufbri/olc+f3WagL1Ho+DrYdDSbuU7cJAq+uD9xGv
vP9m2JavSP4wO9i9pB/cmCFMPoIj3oGJt1/cnLb/U2juneOw6Uo0N3F8TXdyXfZN
AIPhq/jw0YfIypTFTTvFkKXfTArIwW/bQBW8/dujFR8i5CxPjRKRDOBEy0PPOLJD
D0iUr9GX/h/EO4jQ7B/GszjhPiPx+gJCilaMY+jrSczjxpsKOXzpZEdT1NqMrzgv
IZPHYhQzAiw9vQzov3vezDwKgKcRrUixZ2B8uiEQNn7Wa2QzWF3vL+6CGflFNYQc
c0leDQBe86baYhCollouP4jfaH9KcMkYYwIBJQ==
-----END RSA PUBLIC KEY-----
And it will be correctly handled by your current code, with a little change:
var pemReader = new PemReader(stringReader);
var pemObject = pemReader.ReadObject(); // null!
// it's already AsymmetricKeyParameter
result = ((AsymmetricKeyParameter)pemObject);

How to set RSACryptoServiceProvider Public Key?

I have a RSA public key stored in a file. The file is plain text and reads as:
-----BEGIN RSA PUBLIC KEY-----
Mdflkjlkf8u8f84rkrjfgk8r7u8t758tkjfedfkjldfjhfjdfdjfkdjfkdfdfdfs
Ddfldkfdjfkjljfldfdlfhkdhfkdhfkdhfkdhfkjdffdnodhmndhiufdofhodhfd
xWCnQ6QOIwKqRY6lklk09erjbds6erottgkjirt895t5tixaevJlMmrZGLaITW66
xVjbPvdpjMniFiemtwIDAQAB
-----END RSA PUBLIC KEY-----
I want to feed this public key to an object of RSACryptoServiceProvider and encrypt an arbitrary message using Encrypt. Unfortunately, I couldn't figure out how to set PK. Any help is more than welcome.
X509Certificate2 cert = new X509Certificate2("pub_key.crt");
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
Then use rsa object.

System.IO.IOException: -----END RSA PRIVATE KEY not found

I am trying to create an online database application using PHP for the server and C# form application for the client.
On the server I encrypt a simple string using a public RSA key with the PHPSecLib. Then the C# application receives the string and tries to decrypt it using the corresponding private key.
The bytes are base64 encoded on the server and decoded to bytes again by C#. I created the key pair using the PHPSecLib.
This is the code I use on the client application:
public string rsa_decrypt(string encryptedText, string privateKey) {
byte[] bytesToDecrypt = Convert.FromBase64String(encryptedText);
Pkcs1Encoding decrypter = new Pkcs1Encoding(new RsaEngine());
//the error occurs on this line:
AsymmetricCipherKeyPair RSAParams = (AsymmetricCipherKeyPair)new PemReader(new StringReader(privateKey)).ReadObject();
decrypter.Init(false, RSAParams.Private);
byte[] decryptedBytes = decrypter.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length);
string decryptedString = Convert.ToBase64String(decryptedBytes);
return decryptedString;
}
But, I get the following error on the line specified above^.
An unhandled exception of type 'System.IO.IOException' occurred in
BouncyCastle.Crypto.dll
Additional information: -----END RSA PRIVATE KEY not found
I believe there's nothing wrong with the key pair combo as I get an error before I even try to decrypt anything.
The privateKey parameter is currently hardcoded into the script using this format:
string privateKey = "-----BEGIN RSA PRIVATE KEY-----XXXXXXXX-----END RSA PRIVATE KEY-----";
So it seems to me the footer actually is included in the string... I have debugged and googled everywhere but I can't seem to solve it. I'm pretty new to RSA&Bouncycastle so maybe I'm just using wrong methods.
Hope you can help, thanks!
- G4A
P.S. This is my first Stackoverflow question, I just created an account, so if you could also give me some feedback on the way I formulated this question; great!
You need to add a new line between the pre/post encapsulation boundary text and the Base64 data, so:
string privateKey = "-----BEGIN RSA PRIVATE KEY-----\r\nXXX\r\n-----END RSA PRIVATE KEY-----";
This is because the pem specification allows for the existence of other textual headers between the two.
If this doesn't work
"-----BEGIN RSA PRIVATE KEY-----\r\nXXXXXXXX\r\n-----END RSA PRIVATE KEY-----"
please try this
"-----BEGIN RSA PRIVATE KEY-----
XXXXXXXX
-----END RSA PRIVATE KEY-----"
We converted the BOX Private Key to Base64 Format and stored the same in Azure Vault.
Convert key to Base64 using Base64Encode method, store in Azure Key Vault.
Retrieve the encoded string in code, decoded back using Base64Decode Method.
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
I recommend use \x0A instead of \r\n and
.
Because only this option worked for me.
So :
"-----BEGIN RSA PRIVATE KEY-----\x0AXXXXXXXX\x0A-----END RSA PRIVATE KEY-----"

Bouncy Castle Decryption in c# from private key and encrytedtext

Encrytped text is:
wMXLjsRSfO1VngHqotJXoxygP1eTktr3gc3tuhdzXpqOy1N1V8/wflJuHkn1PX7Rf3/ccvL5vzPYYaKIm3s4IMhshrwVH3p4euprwRyNTvlBPLLmZ/b/wuTXkKqRdK81V9oHocIfxerivS4oIJfA4J6fMbtKom6IoE4GVhiAsJs=
My Private Key is:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDIlsvQQVhLQsmRFr/KUcAjOE/nlCNPS+0Q+Q8sIhEZFmT9f2qR
3d/9gtaxGY/WYgFwFplMArtaMzqcQSwntH296E1CdDj2U/v1AhTVCupeyNdz7//E
hIWrmlHjkrFynghRBFEEkACDtAV96VdtDvk10Knzl2CZ2kPklGz39sQsgQIDAQAB
AoGBAKVEwYbD4CiaTZNSaBEdTC54njVSs8kI6Ll8S4j0RJwj/G90xOyMH5ozbAqc
4gsj0sV0iTe8ZHsMDHVjqSrJpnMU6wDHhKQpr+zITJUxbTPjxgJf/2tKtsvFIMnb
2ghjTS/lMMzMPyeMhUcsLjPpoK9c+SDkl/PWU9Ay/pYvCCf1AkEA77JrZzn4gdJ3
VqtXUlV/y249frMPwYh+dS+aahyUUw0QW9BVa65Ume2iO5gGFVC3eJBZYxALFGai
ih06j0HOlwJBANY7bvp/2UfM2XWHYXvKXfasq/UzOMnc7jQvGJV6aFvch6mVxuTi
+ah7CCqGPVEbn8ZK92FwtsHYd5EvQO+R2KcCQCDfe1Ng4/AKCUvdm9Ay4Z/oso5Z
yGNmcNFpgefjm4P4WrH81Ho8ImYp7QH3S35I36CtS1UGsj5OBSSj9ZAIGmkCQDI/
xowjKMfamLckhg0PLnMJlVvyI8PVelnrIg0NpSTG2VtBsmFFi+Gk2gl/ayp3HEba
lqPYWEWnjIQVXVnUD8kCQQDJpHSBSFQWRBRGHl2Oyy1SXiBYFdW2FH7+2c1WzN4P
iKkmgOXqC2RfMD0aE/xtMe8F2zFhPKcARIvEvfneVjmT
-----END RSA PRIVATE KEY-----
I am using Bouncy Castle in c# , when i decrypt using the encrytedtext and private key using below code:
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
IAsymmetricBlockCipher cipher = new RsaEngine();
RsaKeyParameters privateKey = (RsaKeyParameters)keyPair.Private;
cipher.Init(false, keyPair.Private);
byte[] deciphered = cipher.ProcessBlock(bytesl, 0, bytesl.Length);
string decipheredText = utf8enc.GetString(deciphered);
I am getting decipheredText as
☻♣?????U??`?u????|???^H?|???☺????♦M>?→?&↔.0p?J??a?▼?S←$*▬T☼? xQ??-??Ai9;??siqD??_??? ♥↓§?k?Ny??kr?U??↔z Mazher Ul Haq
but my actual string was "Mazher Ul Haq" , How to get actual string
Your "encrypted text" is actually base64 text. I suspect that if you convert that into non-base64 data first, you should be fine. If you've already got it as a string, that's as simple as:
byte[] binaryData = Convert.FromBase64String(base64Text);
If you need to convert it to a string first:
string base64Text = Encoding.ASCII.GetString(base64Binary);
byte[] binaryData = Convert.FromBase64String(base64Text);

Categories