I create public and private key for RSA algorithm. I would like to export public key into byte[]. I did method called FunctionA bellow, later i got suggestion to use the ExportSubjectPublicKeyInfo which is included in FunctionB bellow. I have to store the public key in byte[] and sent it into server which isn't in .NET.
I'd like to know if some of these approaches are correct or i should consider some other solution.
private RSAParameters RSAParamsPublicKey;
private RSAParameters RSAParamsPrivateKey;
private byte[] keyPublicKeyArray;
private void FunctionA() {
var csp = new RSACryptoServiceProvider();
RSAParamsPrivateKey = csp.ExportParameters(true);
RSAParamsPublicKey = csp.ExportParameters(false);
List < byte > keyPublicKeyList = new List < byte > ();
foreach(byte b in RSAParamsPublicKey.Exponent) {
keyPublicKeyList.Add(b);
}
foreach(byte b in RSAParamsPublicKey.Modulus) {
keyPublicKeyList.Add(b);
}
keyPublicKeyArray = keyPublicKeyList.ToArray();
}
private void FunctionB() {
var csp = new RSACryptoServiceProvider();
csp.ExportParameters(true);
csp.ExportParameters(false);
keyPublicKeyArray = csp.ExportSubjectPublicKeyInfo();
}
Related
I'm trying to implement an asymmetric cryptography approach using RSA algorithm
for that, I'm using the following class library from Microsoft System.Security.Cryptography
This Image Source
so based on public-key sharing, This is my architecture
Basically, I've three standalone applications
Encryption/Decryption Service, which is a class library.
WPF Application to encrypt plain text to ciphertext.
Console Application to decrypt cipher text to plain text.
so this is my Encryption/Decryption Service Backbone
public class EncryptDecryptService : IEncryptDecryptService
{
private static RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
private RSAParameters _privateKey;
private RSAParameters _publicKey;
public EncryptDecryptService()
{
_privateKey = csp.ExportParameters(true);
_publicKey = csp.ExportParameters(false);
}
public void WritePrivateKey(string _privatePath)
{
TextWriter _privateKeyTxt = new StreamWriter(_privatePath);
_privateKeyTxt.Write(GeneratePrivateKey());
_privateKeyTxt.Close();
}
public void WritePublicKey(string _publicPath)
{
TextWriter _publicKeyTxt = new StreamWriter(_publicPath);
_publicKeyTxt.Write(GeneratePublicKey());
_publicKeyTxt.Close();
}
public string GeneratePublicKey()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _publicKey);
return sw.ToString();
}
public string GeneratePrivateKey()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _privateKey);
return sw.ToString();
}
public string EncryptText(string plainText, string wpfPrivateKeyPath, string consolePublicKeyPath)
{
csp = new RSACryptoServiceProvider();
var consoleAppPublicKey = CovertRSAXMLtoRSAParam(consolePublicKeyPath, false);
var wpfAppPrivateKey = CovertRSAXMLtoRSAParam(wpfPrivateKeyPath, true);
csp.ImportParameters(consoleAppPublicKey);
csp.ImportParameters(wpfAppPrivateKey);
var data = Encoding.Unicode.GetBytes(plainText);// sample
var cypher = csp.Encrypt(data, false);
return Convert.ToBase64String(cypher);
}
public string DecryptText(string cypherText, string wpfPublicKeyPath, string consolePrivateKeyPath)
{
var dataBytes = Convert.FromBase64String(cypherText);
var consoleAppPrivateKey = CovertRSAXMLtoRSAParam(consolePrivateKeyPath, true);
var wpfAppPublicKey = CovertRSAXMLtoRSAParam(wpfPublicKeyPath, false);
csp.ImportParameters(consoleAppPrivateKey);
csp.ImportParameters(wpfAppPublicKey);
var plainText = csp.Decrypt(dataBytes, false);
return Encoding.Unicode.GetString(plainText);
}
public static RSAParameters CovertRSAXMLtoRSAParam(string _location, bool isExport)
{
string xmlContent = System.IO.File.ReadAllText(_location);
RSAParameters _publicKey = new RSAParameters();
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider key = new RSACryptoServiceProvider(cspParam);
key.FromXmlString(xmlContent);
_publicKey = key.ExportParameters(isExport);
return _publicKey;
}
}
Like this way I'm generating the ciphertext for a plain text in WPF application
private void Button_Click(object sender, RoutedEventArgs e)
{
var wpfPrivateKeyPath = "C:\\SERVICE\\keys\\wpf_private_key.txt";
var consolePublicKeyPath = "C:\\SERVICE\\keys\\console_public_key.txt";
objWebservice.WritePrivateKey(wpfPrivateKeyPath);
objWebservice.WritePublicKey(consolePublicKeyPath);
string _plainText = PlainTextValue.Text;
string _encryptedText = objWebservice.EncryptText(_plainText, wpfPrivateKeyPath, consolePublicKeyPath);
EncryptedTextValue.Text = _encryptedText;
}
Then that ciphertext I'm trying to convert back to previous plain text in the following way.
public static void Main(string[] args)
{
EncryptDecryptService decryptService = new EncryptDecryptService();
string encryptedText = "SDSFDSFSDFDSFSsdfsdf";
var wpfPublicKeyPath = "C:\\SERVICE\\keys\\wpf_public_key.txt";
var consolePrivateKeyPath = "C:\\SERVICE\\keys\\console_private_key.txt";
decryptService.WritePrivateKey(consolePrivateKeyPath);
decryptService.WritePublicKey(wpfPublicKeyPath);
var plaintText = decryptService.DecryptText(encryptedText, wpfPublicKeyPath, consolePrivateKeyPath);
Console.WriteLine(plaintText);
Console.ReadLine();
}
this is where an error occurring when it's going to decrypt as in this image.
what did I missed here, please if can guide me to make this correct :)
here is what i want to do
1. create public ,private key pair for encryption
2. encrypt data by private key
3. decrypt data by public key
i want to encrypt data by private key so that encrypted data i send to anyone
could be decrypted by my public key
ensuring data is coming from me
here is what i have right now
i am using RSACryptoServiceProvider class
var rsa = new RSACryptoServiceProvider();
var privateKey = rsa.ToXmlString(true);
var publicKey = rsa.ToXmlString(false);
var text = "my messege";
Console.WriteLine("RSA // Text to encrypt: " + text);
var enc = Encrypt(text, publicKey);
Console.WriteLine("RSA // Encrypted Text: " + enc);
var dec = Decrypt(enc, privateKey);
Console.WriteLine("RSA // Decrypted Text: " + dec);
my methods
for decryption
public static string Decrypt(string data,string pvtK)
{
var rsa = new RSACryptoServiceProvider();
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
rsa.FromXmlString(pvtK);
var decryptedByte = rsa.Decrypt(dataByte, false);
return _encoder.GetString(decryptedByte);
}
for encryption
public static string Encrypt(string data,string pubK)
{
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(pubK);
var dataToEncrypt = _encoder.GetBytes(data);
var encryptedByteArray = rsa.Encrypt(dataToEncrypt, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
var sb = new StringBuilder();
foreach (var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length)
sb.Append(",");
}
return sb.ToString();
}
currently its working fine when encrypting by public key and decrypting by private key
now i have two concern when decrypting by private key
When i pass my private key to encrypt my message it got decrypted but when i pass my public key to decrypt that data i got wrong key exception and not working
in RSACryptoServiceProvider private key is a combo of Public and private how do i know which is my actual private key as its in the xmlFormat making it really difficult to identify what does every thing mean in the key
here is my private key
<RSAKeyValue><Modulus>sHQOnB9obOy9UUvKolGBYUHyGNKXKC7ZqerB/pLQcOKKlhqXAB5KLPf62banbC5DLU5+Mhd25sq5KE5l/vEZeQLia+np2TYwis8bNVQpLYh/Q2MmuldKzl4Al+ziVH90NLe0fX6LiC5W9Q36HkzV16BKrHwLPljNNBNYWENl/p8=</Modulus><Exponent>AQAB</Exponent><P>vGAPI9BTSnOvVKQ9spTt7WaCb3j+Dexy48VHbGV2+h1hKEA7pF4Mrog7VL7MCNp8G8XZIWh3sMa9VHn2bNv0mQ==</P><Q>78xcUFFtngtKxpr6pZssiXIlTThFo7X2zRiUsWLSUKDJlYlGELu8cGAxzbRYirk2psm92Fga1jAPNDhuzpVX9w==</Q><DP>dHcThTn89RAXO8ab2riXbequBEuTD3q8AbTsFsmYyMS3WBJ2jYYUYygZPqkELwkeKHGncC9NqP8G+Z66S82mKQ==</DP><DQ>C7Zel+myQfLpPxQYw/f1T+1MVx41gI6FtHTL5nIeNaP01KH00yJoTNDV/eceIAB14+WcqTF8dhO42mMbPmna9w==</DQ><InverseQ>ORoUweiOyF+eEQ3F3+NU2IdcSYM5TRG/J73er1nBuyfz5QjKpOhSWqtl5W3mNmQmX8/WDv9bFzgE0jPdXQtFTQ==</InverseQ><D>B/agGpHcs7gpdFJNCYjpI5UHOPFdt6DWdPGVCLxI4oqIaG04Lfd8yU1cIyUE2eaEMWn1J9iUQEBoHWmp9vJozLbhzUdQUC+tcrms4dys6U+AhLTJ+obpmlJczdVABSWlwFe1lnoJNqJN9QQyc4tVvcLKzy+YPbhHvb66bfhVcqk=</D></RSAKeyValue>
How can I verify signature for open PGP using BouncyCastle?
I am using C#
I have pulic key http://itransact.com/support/toolkit/html-connection/pgp.php
I am using BouncyCastle as open pgp library
I have signature that I recieve in query string.
According to instruction (http://itransact.com/downloads/PCFullDocument-4.4.pdf p.145) algorithm is RSA.
I checked a lot of resource but no success. As I understood I need to pass public key and signature to some Verify method.
It is also not clear if I have to convert given public key in string format to some appropriate public key object. If I have to what is the type? I have tried to convert it to RsaKeyParameters but got error message about inappropriate block on public key.
At the moment I have the following code
private bool VerifyWithPublicKey(string data, byte[] sig)
{
RSACryptoServiceProvider rsa;
using (var keyreader = new StringReader(publicKey))
{
var pemReader = new PemReader(keyreader);
var y = (RsaKeyParameters)pemReader.ReadObject();
rsa = (RSACryptoServiceProvider)RSA.Create();
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
rsa.ImportParameters(rsaParameters);
// compute sha1 hash of the data
var sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
// This always returns false
return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), sig);
}
Using RSA is not your case. You need
Define public key
Convert public ket into PgPPublicKey
Get PgpSignature object
Verify signature
To verify signature you will need original data that was signed.
public class iTransactVerifier
{
private const string PublicKey = #"-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 4.5
mQCNAjZu
-----END PGP PUBLIC KEY BLOCK-----";
public static bool Verify(string signature, string data)
{
var inputStream = ConvertStringToStream(signature);
PgpPublicKey publicKey = ReadPublicKeyFromString();
var stream = PgpUtilities.GetDecoderStream(inputStream);
PgpObjectFactory pgpFact = new PgpObjectFactory(stream);
PgpSignatureList sList = pgpFact.NextPgpObject() as PgpSignatureList;
if (sList == null)
{
throw new InvalidOperationException("PgpObjectFactory could not create signature list");
}
PgpSignature firstSig = sList[0];
firstSig.InitVerify(publicKey);
firstSig.Update(Encoding.UTF8.GetBytes(data));
var verified = firstSig.Verify();
return verified;
}
....
private static PgpPublicKey ReadPublicKeyFromString()
{
var varstream = ConvertStringToStream(PublicKey);
var stream = PgpUtilities.GetDecoderStream(varstream);
PgpObjectFactory pgpFact = new PgpObjectFactory(stream);
var keyRing = (PgpPublicKeyRing)pgpFact.NextPgpObject();
return keyRing.GetPublicKey();
}
}
I want to make 2 applications. The first will crypt the file and sign it. The second will be encrypt and verify the data. I use the following code as example.
using System;
using System.Security.Cryptography;
using System.Text;
class RSACSPSample
{
static void Main()
{
try
{
// Create a UnicodeEncoder to convert between byte array and string.
ASCIIEncoding ByteConverter = new ASCIIEncoding();
string dataString = "Data to Sign";
// Create byte arrays to hold original, encrypted, and decrypted data.
byte[] originalData = ByteConverter.GetBytes(dataString);
byte[] signedData;
// Create a new instance of the RSACryptoServiceProvider class
// and automatically create a new key-pair.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
// Export the key information to an RSAParameters object.
// You must pass true to export the private key for signing.
// However, you do not need to export the private key
// for verification.
RSAParameters Key = RSAalg.ExportParameters(true);
// Hash and sign the data.
signedData = HashAndSignBytes(originalData, Key);
// Verify the data and display the result to the
// console.
if(VerifySignedHash(originalData, signedData, Key))
{
Console.WriteLine("The data was verified.");
}
else
{
Console.WriteLine("The data does not match the signature.");
}
}
catch(ArgumentNullException)
{
Console.WriteLine("The data was not signed or verified");
}
}
public static byte[] HashAndSignBytes(byte[] DataToSign, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Hash and sign the data. Pass a new instance of SHA1CryptoServiceProvider
// to specify the use of SHA1 for hashing.
return RSAalg.SignData(DataToSign, new SHA1CryptoServiceProvider());
}
catch(CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
public static bool VerifySignedHash(byte[] DataToVerify, byte[] SignedData, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Verify the data using the signature. Pass a new instance of SHA1CryptoServiceProvider
// to specify the use of SHA1 for hashing.
return RSAalg.VerifyData(DataToVerify, new SHA1CryptoServiceProvider(), SignedData);
}
catch(CryptographicException e)
{
Console.WriteLine(e.Message);
return false;
}
}
}
The problem is I can not understand how can I get OriginalData (1-st parameter) for the function VerifySignedHash? I mean the application (signature checker) will read the signed data. How can I convert the signed data to original data for the data verifying?
I am building a custom shopping cart where CC numbers and Exp date will be stored in a database until processing (then deleted). I need to encrypt this data (obviously).
I want to use the RSACryptoServiceProvider class.
Here is my code to create my keys.
public static void AssignNewKey(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
Now the plan is to store the private key xml on a USB drive attached to the managers key chain.
Whenever a manager leaves the company I want to be able to generate new public and private keys (and re-encrypt all currently stored CC numbers with the new public key).
My problem is that the keys generated by this code are always the same. How would I generate a unique set of keys every time?
UPDATE. My test code is below.:
note: the "privatekey" parameter here is the original private key. In order for the keys to be changed I need to verify that the private key is valid.
In Default.aspx.cs
public void DownloadNewPrivateKey_Click(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(fileUpload.FileContent);
string privateKey = reader.ReadToEnd();
Response.Clear();
Response.ContentType = "text/xml";
Response.End();
Response.Write(ChangeKeysAndReturnNewPrivateKey(privateKey));
}
In Crytpography.cs:
public static privateKey;
public static publicKey;
public static RSACryptoServiceProvider rsa;
public static string ChangeKeysAndReturnNewPrivateKey(string _privatekey)
{
string testData = "TestData";
string testSalt = "salt";
// encrypt the test data using the exisiting public key...
string encryptedTestData = EncryptData(testData, testSalt);
try
{
// try to decrypt the test data using the _privatekey provided by user...
string decryptTestData = DecryptData(encryptedTestData, _privatekey, testSalt);
// if the data is successfully decrypted assign new keys...
if (decryptTestData == testData)
{
AssignNewKey();
// "AssignNewKey()" should set "privateKey" to the newly created private key...
return privateKey;
}
else
{
return string.Empty;
}
}
catch (Exception ex)
{
return string.Empty;
}
}
public static void AssignParameter(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
}
public static void AssignNewKey()
{
AssignParameter();
using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
{
SqlCommand myCmd = myConn.CreateCommand();
string publicPrivateKeyXML = rsa.ToXmlString(true);
privateKey = publicPrivateKeyXML; // sets the public variable privateKey to the new private key.
string publicOnlyKeyXML = rsa.ToXmlString(false);
publicKey = publicOnlyKeyXML; // sets the public variable publicKey to the new public key.
myCmd.CommandText = "UPDATE Settings SET PublicKey = #PublicKey";
myCmd.Parameters.AddWithValue("#PublicKey", publicOnlyKeyXML);
myConn.Open();
myComm.ExecuteScalar();
}
}
public static string EncryptData(string data2Encrypt, string salt)
{
AssignParameter();
using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
{
SqlCommand myCmd = myConn.CreateCommand();
myCmd.CommandText = "SELECT TOP 1 PublicKey FROM Settings";
myConn.Open();
using (SqlDataReader sdr = myCmd.ExecuteReader())
{
if (sdr.HasRows)
{
DataTable dt = new DataTable();
dt.Load(sdr);
rsa.FromXmlString(dt.Rows[0]["PublicKey"].ToString());
}
}
}
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt + salt);
byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
return Convert.ToBase64String(cipherbytes);
}
public static string DecryptData(string data2Decrypt, string privatekey, string salt)
{
AssignParameter();
byte[] getpassword = Convert.FromBase64String(data2Decrypt);
string publicPrivateKeyXML = privatekey;
rsa.FromXmlString(publicPrivateKeyXML);
//read ciphertext, decrypt it to plaintext
byte[] plain = rsa.Decrypt(getpassword, false);
string dataAndSalt = System.Text.Encoding.UTF8.GetString(plain);
return dataAndSalt.Substring(0, dataAndSalt.Length - salt.Length);
}
When you use a code like this:
using (var rsa = new RSACryptoServiceProvider(1024))
{
// Do something with the key...
// Encrypt, export, etc.
}
.NET (actually Windows) stores your key in a persistent key container forever.
The container is randomly generated by .NET
This means:
Any random RSA/DSA key you have EVER generated for the purpose of protecting data, creating custom X.509 certificate, etc. may have been exposed without your awareness in the Windows file system. Accessible by anyone who has access to your account.
Your disk is being slowly filled with data. Normally not a big concern but it depends on your application (e.g. it might generates hundreds of keys every minute).
To resolve these issues:
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// Do something with the key...
// Encrypt, export, etc.
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
ALWAYS
The RSACryptoServiceProvider(CspParameters) constructor creates a keypair which is stored in the keystore on the local machine. If you already have a keypair with the specified name, it uses the existing keypair.
It sounds as if you are not interested in having the key stored on the machine.
So use the RSACryptoServiceProvider(Int32) constructor:
public static void AssignNewKey(){
RSA rsa = new RSACryptoServiceProvider(2048); // Generate a new 2048 bit RSA key
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
EDIT:
Alternatively try setting the PersistKeyInCsp to false:
public static void AssignNewKey(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
rsa.PersistKeyInCsp = false;
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
What I ended up doing is create a new KeyContainer name based off of the current DateTime (DateTime.Now.Ticks.ToString()) whenever I need to create a new key and save the container name and public key to the database. Also, whenever I create a new key I would do the following:
public static string ConvertToNewKey(string oldPrivateKey)
{
// get the current container name from the database...
rsa.PersistKeyInCsp = false;
rsa.Clear();
rsa = null;
string privateKey = AssignNewKey(true); // create the new public key and container name and write them to the database...
// re-encrypt existing data to use the new keys and write to database...
return privateKey;
}
public static string AssignNewKey(bool ReturnPrivateKey){
string containerName = DateTime.Now.Ticks.ToString();
// create the new key...
// saves container name and public key to database...
// and returns Private Key XML.
}
before creating the new key.