I was looking for a method to securely store values into a trusted execution environment and I found this library from Microsoft called Tpm2Lib.
I'm using the code below that is a actually working but I've some concerns about the security.
It is known that the data are stored securely in the TPM but, looking into the code, the AuthValue byte[] initialization is here, easy to be disassembled..
If an attacker disassemble my code he could easily write a software with the same AuthValue to get the secret from the TPM.. Am I right?
public static AuthValue _authValue = new AuthValue(new byte[] { 22, 123, 22, 1, 33 });
public static void SaveValueIntoTpm(int address, byte[] data, int length, AuthValue authValue)
{
Tpm2Device tpmDevice;
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
{
tpmDevice = new TbsDevice();
}
else
{
tpmDevice = new LinuxTpmDevice();
}
tpmDevice.Connect();
var tpm = new Tpm2(tpmDevice);
var ownerAuth = new AuthValue();
TpmHandle nvHandle = TpmHandle.NV(address);
tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle);
AuthValue nvAuth = authValue;
var nvPublic = new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Authwrite | NvAttr.Authread, new byte[0], (ushort)length);
tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth,nvPublic);
tpm[nvAuth].NvWrite(nvHandle, nvHandle, data, 0);
tpm.Dispose();
}
public static byte[] ReadValueFromTpm(int address, int length, AuthValue authValue)
{
Tpm2Device tpmDevice;
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
{
tpmDevice = new TbsDevice();
}
else
{
tpmDevice = new LinuxTpmDevice();
}
tpmDevice.Connect();
var tpm = new Tpm2(tpmDevice);
TpmHandle nvHandle = TpmHandle.NV(address);
AuthValue nvAuth = authValue;
byte[] newData = tpm[nvAuth].NvRead(nvHandle, nvHandle, (ushort)length, 0);
tpm.Dispose();
return newData;
}
Related
for testing purposes my unittest generates a test certificate with custom extensions using BouncyCastle for .NET core.
Generate function
static internal class CertificateGenerator
{
public static X509Certificate2 GenerateCertificate(string region)
{
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);
var certificateGenerator = new X509V3CertificateGenerator();
var serialNumber =
BigIntegers.CreateRandomInRange(
BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
const string signatureAlgorithm = "SHA1WithRSA";
certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
var subjectDN = new X509Name("CN=FOOBAR");
var issuerDN = subjectDN;
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
var notBefore = DateTime.UtcNow.Date.AddHours(-24);
var notAfter = notBefore.AddYears(1000);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
var fakeOid = "1.3.6.1.1.5.6.100.345434.345";
if (region != null)
{
certificateGenerator.AddExtension(new DerObjectIdentifier(fakeOid), false, Encoding.ASCII.GetBytes(region));
}
const int strength = 4096;
var keyGenerationParameters = new KeyGenerationParameters(random, strength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
var issuerKeyPair = subjectKeyPair;
var certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
var store = new Pkcs12Store();
string friendlyName = certificate.SubjectDN.ToString();
var certificateEntry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(friendlyName, certificateEntry);
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });
string password = "password";
var stream = new MemoryStream();
store.Save(stream, password.ToCharArray(), random);
byte[] pfx = Pkcs12Utilities.ConvertToDefiniteLength(stream.ToArray(), password.ToCharArray());
var convertedCertificate =
new X509Certificate2(
pfx, password,
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
return convertedCertificate;
}
}
Reader
public class CertificateExtensionReader
{
private readonly ILogger logger;
public CertificateExtensionReader(ILogger logger)
{
this.logger = logger;
}
public CertificateExtensionValues ReadExtensionValues(byte[] certificate)
{
var x509Certificate2 = new X509Certificate2(certificate);
var region = GetCustomExtensionValue(x509Certificate2.Extensions, new Oid("1.3.6.1.1.5.6.100.345434.345"));
return new CertificateExtensionValues { Region = region };
}
private string GetCustomExtensionValue(X509ExtensionCollection x509Extensions, Oid oId)
{
var extension = x509Extensions[oId.Value];
if(extension == null)
throw new CertificateExtensionValidationException($"The client certificate does not contain the expected extensions '{oId.FriendlyName}' with OID {oId.Value}.");
if (extension.RawData == null)
throw new CertificateExtensionValidationException($"Device client certificate does not a value for the '{oId.FriendlyName}' extension with OID {oId.Value}");
var customExtensionValue = Encoding.UTF8.GetString(extension.RawData).Trim();
logger.LogInformation($"Custom Extension value for the '{oId.FriendlyName}' extension with OID {oId.Value}: '{customExtensionValue}'");
return customExtensionValue;
}
}
public class CertificateExtensionValues
{
public string Region { get; set; }
}
Test
[TestFixture]
public class CertificateExtensionReaderFixture
{
private ILogger logger = new NullLogger<CertificateExtensionReaderFixture>();
private CertificateExtensionReader reader;
[SetUp]
public void Setup()
{
reader = new CertificateExtensionReader(logger);
}
[Test]
public void ShouldReadExtensionValues()
{
var certificate = CertificateGenerator.GenerateCertificate("r1").Export(X509ContentType.Pfx);
var values = reader.ReadExtensionValues(certificate);
values.Region.Should().Be("r1");
}
}
Expected values.Region to be "r1" with a length of 2, but "\u0004\u0002r1" has a length of 4, differs near "\u0004\u0002r" (index 0).
So BouncyCastle added two extra bytes \u0004\u0002 (End of transmission, begin of text) for the extension value.
I saved the certificate to a file and dumped it via certutil -dump -v test.pfx
What am I doing wrong? Is it the generation of the certificate? Or is is how I read the values? Are all extension values encoded this way? I was expecting only the string bytes. I could not find something in the spec.
What am I doing wrong?
you are creating extension wrong.
certificateGenerator.AddExtension(new DerObjectIdentifier(fakeOid), false, Encoding.ASCII.GetBytes(region));
Last parameter is incorrect. It must contain any valid ASN.1 type. Since parameter value is invalid ASN.1 type, BC assumes it is just a random/arbitrary octet string and implicitly encodes raw value into ASN.1 OCTET_STRING type. If it is supposed to be a text string, then use any of applicable ASN.1 string types that fits you requirements and char set.
And you have to update your reader to expect ASN.1 string type you chose for encoding and then decode string value from ASN.1 string type.
My current project is using Microsoft's Membership to manage user's credentials.
For now, it stores passwords into SQL DB in plain-text.
I want to change it store hashes instead, or to encrypt/hide password column.
Current code:
protected void BtnSubmit_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
NAME_OF_TABLE_Provider provider = new NAME_OF_TABLE_Provider();
string userName = SPContext.Current.Web.CurrentUser.Name;
MembershipUserCollection userMembership = Membership.GetAllUsers();
MembershipUser membershipUser = userMembership[userName];
if (membershipUser != null)
{
try
{
membershipUser.ChangePassword(OldPassword.Text, NewPassword.Text);
ConfirmPanel.Visible = true;
InvalidPanel.Visible = false;
Message.InnerText = "The password is changed successfully";
}
catch (Exception ex)
{
ConfirmPanel.Visible = false;
InvalidPanel.Visible = true;
InvalidPassword.InnerText = "The password is not strong. Please verify.";
}
}
}
}
#1 Possible(?) Solution: HashBytes
INSERT INTO <tbl> (..., passwd) values (...., HashBytes('SHA1', #password))
SELECT HashBytes('SHA1', #password);
#2 Possible(?) Solution: C# Storing of Hashes
static void Main(string[] args)
{
//Store a password hash:
PasswordHash hash = new PasswordHash("password");
byte[] hashBytes = hash.ToArray();
//For testing purposes
Console.WriteLine(Convert.ToBase64String(hashBytes));
//Check password against a stored hash
byte[] hashBytes2 = hashBytes;//read from store.
PasswordHash hash2 = new PasswordHash(hashBytes2);
if (!hash.Verify("password"))
{
throw new System.UnauthorizedAccessException();
}
else
{
Console.WriteLine("True");
}
Console.ReadLine();
}
}
public sealed class PasswordHash
{
const int SaltSize = 16, HashSize = 20, HashIter = 10000;
readonly byte[] _salt, _hash;
public PasswordHash(string password)
{
new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
_hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
}
public PasswordHash(byte[] hashBytes)
{
Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
}
public PasswordHash(byte[] salt, byte[] hash)
{
Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
}
public byte[] ToArray()
{
byte[] hashBytes = new byte[SaltSize + HashSize];
Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
return hashBytes;
}
public byte[] Salt { get { return (byte[])_salt.Clone(); } }
public byte[] Hash { get { return (byte[])_hash.Clone(); } }
public bool Verify(string password)
{
byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
for (int i = 0; i < HashSize; i++)
if (test[i] != _hash[i])
return false;
return true;
}
#3 Possible(?) Solution: Transact-SQL to encrypt single column
https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/encrypt-a-column-of-data?view=sql-server-2017#TsqlProcedure
May I know what is the correct approach? Thank you.
It goes without saying that any solution is better than the current one.
The first solution looks solid, but I could not find out if a salt is used. If not, that's a disadvantage. You also are now dependent on this database vendor and cannot switch.
The second solution looks good, but I didn't look too closely, you should probably head over to CodeReview, they do reviews of working code to look for improvements.
The last solution is not really a solution. Passwords are hashed not exncrypted for a reason. If you can decrypt them, the attacker who gets access to the system and steals them will have the same access to the decryption means as you do. So it's a layer of inconvenience, not security.
So pick number two and let somebody look over it for weaknesses or bugs.
I've seen plenty of encryption/decryption tutorials and examples on the net in C# that use the System.Security.Cryptography.RSACryptoServiceProvider, but what I'm hoping to be able to do is:
Create an RSA public/private keypair
Transmit the public key (or for proof of concept, just move it in a string variable)
Create a new RSA crypto provider and encrypt a string with the public key
Transmit the encrypted string (or data) back to the original crypto provider and decrypt the string
Could anyone point me to a useful resource for this?
well there are really enough examples for this, but anyway, here you go
using System;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
static class Program
{
static void Main()
{
//lets take a new CSP with a new 2048 bit rsa key pair
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "foobar";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
/*
* some transmission / storage / retrieval
*
* and we want to decrypt our cypherText
*/
//first, get our bytes back from the base64 string ...
bytesCypherText = Convert.FromBase64String(cypherText);
//we want to decrypt, therefore we need a csp and load our private key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(privKey);
//decrypt and strip pkcs#1.5 padding
bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
}
}
as a side note: the calls to Encrypt() and Decrypt() have a bool parameter that switches between OAEP and PKCS#1.5 padding ... you might want to choose OAEP if it's available in your situation
public static string Encryption(string strText)
{
var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// client encrypting data with public key issued by server
rsa.FromXmlString(publicKey.ToString());
var encryptedData = rsa.Encrypt(testData, true);
var base64Encrypted = Convert.ToBase64String(encryptedData);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
public static string Decryption(string strText)
{
var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
var base64Encrypted = strText;
// server decrypting data with private key
rsa.FromXmlString(privateKey);
var resultBytes = Convert.FromBase64String(base64Encrypted);
var decryptedBytes = rsa.Decrypt(resultBytes, true);
var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return decryptedData.ToString();
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
Honestly, I have difficulty implementing it because there's barely any tutorials I've searched that displays writing the keys into the files. The accepted answer was "fine". But for me I had to improve it so that both keys gets saved into two separate files. I've written a helper class so y'all just gotta copy and paste it. Hope this helps lol.
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
class RSAFileHelper
{
readonly string pubKeyPath = "public.key";//change as needed
readonly string priKeyPath = "private.key";//change as needed
public void MakeKey()
{
//lets take a new CSP with a new 2048 bit rsa key pair
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
//how to get the private key
RSAParameters privKey = csp.ExportParameters(true);
//and the public key ...
RSAParameters pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
File.WriteAllText(pubKeyPath, pubKeyString);
}
string privKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
File.WriteAllText(priKeyPath, privKeyString);
}
}
public void EncryptFile(string filePath)
{
//converting the public key into a string representation
string pubKeyString;
{
using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
}
//get a stream from the string
var sr = new StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
byte[] bytesPlainTextData = File.ReadAllBytes(filePath);
//apply pkcs#1.5 padding and encrypt our data
var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
string encryptedText = Convert.ToBase64String(bytesCipherText);
File.WriteAllText(filePath,encryptedText);
}
public void DecryptFile(string filePath)
{
//we want to decrypt, therefore we need a csp and load our private key
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
string privKeyString;
{
privKeyString = File.ReadAllText(priKeyPath);
//get a stream from the string
var sr = new StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
csp.ImportParameters(privKey);
}
string encryptedText;
using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
byte[] bytesCipherText = Convert.FromBase64String(encryptedText);
//decrypt and strip pkcs#1.5 padding
byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);
//get our original plainText back...
File.WriteAllBytes(filePath, bytesPlainTextData);
}
}
}
I'll share my very simple code for sample purpose. Hope it will help someone like me searching for quick code reference.
My goal was to receive rsa signature from backend, then validate against input string using public key and store locally for future periodic verifications.
Here is main part used for signature verification:
...
var signature = Get(url); // base64_encoded signature received from server
var inputtext= "inputtext"; // this is main text signature was created for
bool result = VerifySignature(inputtext, signature);
...
private bool VerifySignature(string input, string signature)
{
var result = false;
using (var cps=new RSACryptoServiceProvider())
{
// converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
byte[] signatureBytes = Convert.FromBase64String(signature);
cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes );
}
return result;
}
for big data
public class RsaService : System.IDisposable
{
public delegate int TransformBlockCall(System.ReadOnlySpan<byte> data, System.Span<byte> destination);
private readonly RSA _encoder;
private readonly RSAEncryptionPadding _padding;
private readonly TransformBlockCall _encryptBlockCall;
private readonly TransformBlockCall _decryptBlockCall;
private int _encrypt_InputBlockSize;
private int _encrypt_OutputBlockSize;
private int _decrypt_InputBlockSize;
private int _decrypt_OutputBlockSize;
public RsaService(RSA encoder) {
if(encoder == null)
throw new System.ArgumentNullException(nameof(encoder));
_encoder = encoder;
_padding = RSAEncryptionPadding.Pkcs1;
_encryptBlockCall = new TransformBlockCall(EncryptBlock);
_decryptBlockCall = new TransformBlockCall(DecryptBlock);
OnEndSetParameters();
}
private void OnEndSetParameters() {
_encrypt_InputBlockSize = GetSizeOutputEncryptOfKeySize(_encoder.KeySize);
_encrypt_OutputBlockSize = _encoder.KeySize / 8;
_decrypt_InputBlockSize = _encrypt_OutputBlockSize;
_decrypt_OutputBlockSize = _encrypt_OutputBlockSize;
}
public void ImportParameters(RSAParameters parameters) {
_encoder.ImportParameters(parameters);
OnEndSetParameters();
}
public byte[] Encrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int outputLength = GetEncryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[outputLength];
Encrypt(data, outputData);
return outputData;
}
public byte[] Decrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int maxOutputLength = GetDecryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[maxOutputLength];
int actual_OutputLength = Decrypt(data, outputData);
if(maxOutputLength > actual_OutputLength)
System.Array.Resize(ref outputData, actual_OutputLength);
return outputData;
}
public int Encrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
#if DEBUG
int inputBlockSize = _encrypt_InputBlockSize;
int outputBlockSize = _encoder.KeySize / 8;
int blockCount = (data.Length / inputBlockSize);
if(data.Length % inputBlockSize != 0)
blockCount++;
System.Diagnostics.Debug.Assert((blockCount * outputBlockSize) <= destination.Length);
#endif
if(data.Length > _encrypt_InputBlockSize)
return TransformFinal(_encryptBlockCall, data, destination, _encrypt_InputBlockSize);
else
return _encryptBlockCall(data, destination);
}
public int Decrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
if(data.Length > _decrypt_InputBlockSize)
return TransformFinal(_decryptBlockCall, data, destination, _decrypt_InputBlockSize);
else
return _decryptBlockCall(data, destination);
}
private int EncryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Encrypt(data, destination, _padding);
private int DecryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Decrypt(data, destination, _padding);
public int GetEncryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _encrypt_InputBlockSize) * _encrypt_OutputBlockSize;
public int GetDecryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _decrypt_InputBlockSize) * _decrypt_OutputBlockSize;
public void Dispose() {
_encoder.Dispose();
System.GC.SuppressFinalize(this);
}
#region Methods_Helper
public static RsaService Create(RSAParameters parameters) => new RsaService(RSA.Create(parameters));
public static RsaService Create() => new RsaService(RSA.Create());
// [keySize] ÷ 8 - [11 bytes for padding] = Result
// Exsimple: [2048 key size] ÷ 8 - [11 bytes for padding] = 245
public static int GetSizeOutputEncryptOfKeySize(int keySize) => (keySize / 8) - 11;
private static int GetBlockCount(int dataLength,int inputBlockSize) {
int blockCount = (dataLength / inputBlockSize);
if(dataLength % inputBlockSize != 0)
blockCount++;
return blockCount;
}
public static int TransformFinal(TransformBlockCall transformBlockCall, System.ReadOnlySpan<byte> data, System.Span<byte> destination, int inputBlockSize) {
int blockCount = GetBlockCount(data.Length, inputBlockSize);
int data_writtenCount = 0;
int destination_writtenCount = 0;
while(blockCount-- > 0) {
if(blockCount == 0) {
inputBlockSize = data.Length - data_writtenCount;
if(inputBlockSize == 0) break;
}
destination_writtenCount += transformBlockCall(data: data.Slice(data_writtenCount, inputBlockSize)
, destination: destination.Slice(destination_writtenCount));
data_writtenCount += inputBlockSize;
}
return destination_writtenCount;
}
public static (RSAParameters keyPublic, RSAParameters keyPrivate) GenerateKeyPair(int keySize = 2048) {
RSAParameters keyPriv;
RSAParameters keyPub;
using(var rsa = RSA.Create(keySize)) {
keyPriv = rsa.ExportParameters(true);
keyPub = rsa.ExportParameters(false);
}
return (keyPub, keyPriv);
}
#endregion Methods_Helper
}
public static class Program
{
static void Main() {
var (keyPublic, keyPrivate) = RsaService.GenerateKeyPair();
var encryptor = RsaService.Create(keyPublic);
var decryptor = RsaService.Create(keyPrivate);
string originalText = "";
for(int i = 0; i < 1000; i++) {
originalText += "ABC123456789";
}
byte[] inputData = Encoding.UTF8.GetBytes(originalText); // data random for test
System.Console.WriteLine("inputData.Length: {0}", inputData.Length);
var encryptedData = encryptor.Encrypt(inputData);
System.Console.WriteLine("encryptedData.Length: {0}", encryptedData.Length);
byte[] decryptedData = decryptor.Decrypt(encryptedData);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
System.Console.WriteLine("status: {0}", decryptedText == originalText);
}
}
I've seen plenty of encryption/decryption tutorials and examples on the net in C# that use the System.Security.Cryptography.RSACryptoServiceProvider, but what I'm hoping to be able to do is:
Create an RSA public/private keypair
Transmit the public key (or for proof of concept, just move it in a string variable)
Create a new RSA crypto provider and encrypt a string with the public key
Transmit the encrypted string (or data) back to the original crypto provider and decrypt the string
Could anyone point me to a useful resource for this?
well there are really enough examples for this, but anyway, here you go
using System;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
static class Program
{
static void Main()
{
//lets take a new CSP with a new 2048 bit rsa key pair
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "foobar";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
/*
* some transmission / storage / retrieval
*
* and we want to decrypt our cypherText
*/
//first, get our bytes back from the base64 string ...
bytesCypherText = Convert.FromBase64String(cypherText);
//we want to decrypt, therefore we need a csp and load our private key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(privKey);
//decrypt and strip pkcs#1.5 padding
bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
}
}
as a side note: the calls to Encrypt() and Decrypt() have a bool parameter that switches between OAEP and PKCS#1.5 padding ... you might want to choose OAEP if it's available in your situation
public static string Encryption(string strText)
{
var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// client encrypting data with public key issued by server
rsa.FromXmlString(publicKey.ToString());
var encryptedData = rsa.Encrypt(testData, true);
var base64Encrypted = Convert.ToBase64String(encryptedData);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
public static string Decryption(string strText)
{
var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
var base64Encrypted = strText;
// server decrypting data with private key
rsa.FromXmlString(privateKey);
var resultBytes = Convert.FromBase64String(base64Encrypted);
var decryptedBytes = rsa.Decrypt(resultBytes, true);
var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return decryptedData.ToString();
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
Honestly, I have difficulty implementing it because there's barely any tutorials I've searched that displays writing the keys into the files. The accepted answer was "fine". But for me I had to improve it so that both keys gets saved into two separate files. I've written a helper class so y'all just gotta copy and paste it. Hope this helps lol.
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
class RSAFileHelper
{
readonly string pubKeyPath = "public.key";//change as needed
readonly string priKeyPath = "private.key";//change as needed
public void MakeKey()
{
//lets take a new CSP with a new 2048 bit rsa key pair
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
//how to get the private key
RSAParameters privKey = csp.ExportParameters(true);
//and the public key ...
RSAParameters pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
File.WriteAllText(pubKeyPath, pubKeyString);
}
string privKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
File.WriteAllText(priKeyPath, privKeyString);
}
}
public void EncryptFile(string filePath)
{
//converting the public key into a string representation
string pubKeyString;
{
using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
}
//get a stream from the string
var sr = new StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
byte[] bytesPlainTextData = File.ReadAllBytes(filePath);
//apply pkcs#1.5 padding and encrypt our data
var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
string encryptedText = Convert.ToBase64String(bytesCipherText);
File.WriteAllText(filePath,encryptedText);
}
public void DecryptFile(string filePath)
{
//we want to decrypt, therefore we need a csp and load our private key
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
string privKeyString;
{
privKeyString = File.ReadAllText(priKeyPath);
//get a stream from the string
var sr = new StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
csp.ImportParameters(privKey);
}
string encryptedText;
using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
byte[] bytesCipherText = Convert.FromBase64String(encryptedText);
//decrypt and strip pkcs#1.5 padding
byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);
//get our original plainText back...
File.WriteAllBytes(filePath, bytesPlainTextData);
}
}
}
I'll share my very simple code for sample purpose. Hope it will help someone like me searching for quick code reference.
My goal was to receive rsa signature from backend, then validate against input string using public key and store locally for future periodic verifications.
Here is main part used for signature verification:
...
var signature = Get(url); // base64_encoded signature received from server
var inputtext= "inputtext"; // this is main text signature was created for
bool result = VerifySignature(inputtext, signature);
...
private bool VerifySignature(string input, string signature)
{
var result = false;
using (var cps=new RSACryptoServiceProvider())
{
// converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
byte[] signatureBytes = Convert.FromBase64String(signature);
cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes );
}
return result;
}
for big data
public class RsaService : System.IDisposable
{
public delegate int TransformBlockCall(System.ReadOnlySpan<byte> data, System.Span<byte> destination);
private readonly RSA _encoder;
private readonly RSAEncryptionPadding _padding;
private readonly TransformBlockCall _encryptBlockCall;
private readonly TransformBlockCall _decryptBlockCall;
private int _encrypt_InputBlockSize;
private int _encrypt_OutputBlockSize;
private int _decrypt_InputBlockSize;
private int _decrypt_OutputBlockSize;
public RsaService(RSA encoder) {
if(encoder == null)
throw new System.ArgumentNullException(nameof(encoder));
_encoder = encoder;
_padding = RSAEncryptionPadding.Pkcs1;
_encryptBlockCall = new TransformBlockCall(EncryptBlock);
_decryptBlockCall = new TransformBlockCall(DecryptBlock);
OnEndSetParameters();
}
private void OnEndSetParameters() {
_encrypt_InputBlockSize = GetSizeOutputEncryptOfKeySize(_encoder.KeySize);
_encrypt_OutputBlockSize = _encoder.KeySize / 8;
_decrypt_InputBlockSize = _encrypt_OutputBlockSize;
_decrypt_OutputBlockSize = _encrypt_OutputBlockSize;
}
public void ImportParameters(RSAParameters parameters) {
_encoder.ImportParameters(parameters);
OnEndSetParameters();
}
public byte[] Encrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int outputLength = GetEncryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[outputLength];
Encrypt(data, outputData);
return outputData;
}
public byte[] Decrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int maxOutputLength = GetDecryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[maxOutputLength];
int actual_OutputLength = Decrypt(data, outputData);
if(maxOutputLength > actual_OutputLength)
System.Array.Resize(ref outputData, actual_OutputLength);
return outputData;
}
public int Encrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
#if DEBUG
int inputBlockSize = _encrypt_InputBlockSize;
int outputBlockSize = _encoder.KeySize / 8;
int blockCount = (data.Length / inputBlockSize);
if(data.Length % inputBlockSize != 0)
blockCount++;
System.Diagnostics.Debug.Assert((blockCount * outputBlockSize) <= destination.Length);
#endif
if(data.Length > _encrypt_InputBlockSize)
return TransformFinal(_encryptBlockCall, data, destination, _encrypt_InputBlockSize);
else
return _encryptBlockCall(data, destination);
}
public int Decrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
if(data.Length > _decrypt_InputBlockSize)
return TransformFinal(_decryptBlockCall, data, destination, _decrypt_InputBlockSize);
else
return _decryptBlockCall(data, destination);
}
private int EncryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Encrypt(data, destination, _padding);
private int DecryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Decrypt(data, destination, _padding);
public int GetEncryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _encrypt_InputBlockSize) * _encrypt_OutputBlockSize;
public int GetDecryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _decrypt_InputBlockSize) * _decrypt_OutputBlockSize;
public void Dispose() {
_encoder.Dispose();
System.GC.SuppressFinalize(this);
}
#region Methods_Helper
public static RsaService Create(RSAParameters parameters) => new RsaService(RSA.Create(parameters));
public static RsaService Create() => new RsaService(RSA.Create());
// [keySize] ÷ 8 - [11 bytes for padding] = Result
// Exsimple: [2048 key size] ÷ 8 - [11 bytes for padding] = 245
public static int GetSizeOutputEncryptOfKeySize(int keySize) => (keySize / 8) - 11;
private static int GetBlockCount(int dataLength,int inputBlockSize) {
int blockCount = (dataLength / inputBlockSize);
if(dataLength % inputBlockSize != 0)
blockCount++;
return blockCount;
}
public static int TransformFinal(TransformBlockCall transformBlockCall, System.ReadOnlySpan<byte> data, System.Span<byte> destination, int inputBlockSize) {
int blockCount = GetBlockCount(data.Length, inputBlockSize);
int data_writtenCount = 0;
int destination_writtenCount = 0;
while(blockCount-- > 0) {
if(blockCount == 0) {
inputBlockSize = data.Length - data_writtenCount;
if(inputBlockSize == 0) break;
}
destination_writtenCount += transformBlockCall(data: data.Slice(data_writtenCount, inputBlockSize)
, destination: destination.Slice(destination_writtenCount));
data_writtenCount += inputBlockSize;
}
return destination_writtenCount;
}
public static (RSAParameters keyPublic, RSAParameters keyPrivate) GenerateKeyPair(int keySize = 2048) {
RSAParameters keyPriv;
RSAParameters keyPub;
using(var rsa = RSA.Create(keySize)) {
keyPriv = rsa.ExportParameters(true);
keyPub = rsa.ExportParameters(false);
}
return (keyPub, keyPriv);
}
#endregion Methods_Helper
}
public static class Program
{
static void Main() {
var (keyPublic, keyPrivate) = RsaService.GenerateKeyPair();
var encryptor = RsaService.Create(keyPublic);
var decryptor = RsaService.Create(keyPrivate);
string originalText = "";
for(int i = 0; i < 1000; i++) {
originalText += "ABC123456789";
}
byte[] inputData = Encoding.UTF8.GetBytes(originalText); // data random for test
System.Console.WriteLine("inputData.Length: {0}", inputData.Length);
var encryptedData = encryptor.Encrypt(inputData);
System.Console.WriteLine("encryptedData.Length: {0}", encryptedData.Length);
byte[] decryptedData = decryptor.Decrypt(encryptedData);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
System.Console.WriteLine("status: {0}", decryptedText == originalText);
}
}
I have tried and tried but I continue to get "Bad Data". How do you decrypt data using the RSACryptoServiceProvider with the public key's Exponent/Modulus?
public static byte[] Encrypt(byte[] b, byte[] mod, byte[] exp)
{
CspParameters csp = new CspParameters();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
RSACryptoServiceProvider.UseMachineKeyStore = false;
RSAParameters par = new RSAParameters();
par.Exponent = exp;
par.Modulus = mod;
rsa.ImportParameters(par);
return rsa.Encrypt(b, false);
}
public static byte[] Decrypt(byte[] b, byte[] pubexp, byte[] mod, byte[] priexp)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
RSACryptoServiceProvider.UseMachineKeyStore = false;
RSAParameters rp = new RSAParameters();
rp.Exponent = pubexp;
rp.D = priexp;
rp.Modulus = mod;
rsa.ImportParameters(rp);
return rsa.Decrypt(b, false);
}
static List<byte[]> Base2Array(string str)
{
byte[] b = Convert.FromBase64String(str);
List<byte[]> Bytes = new List<byte[]>();
int i = 0;
while (i < b.Length)
{
int size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(b, i));
i += 4;
byte[] b2 = new byte[size];
Array.Copy(b, i, b2, 0, size);
Bytes.Add(b2);
i += size;
}
return Bytes;
}
static void Main(string[] args)
{
List<byte[]> pub = Base2Array("AAAAB3NzaC1yc2EAAAABJQAAAIBMW4HxU1glv+CcZpJnvUKEyeNfFoKkyLOVLOOb/vNXQkrkGsNdpYAZkKKizij8fD3u3/iYT8UI+xkFoyonRYVipgCslirJB1VdvLivXs69Ht4vf7VAv2yJSUni3XsIHauMlfOkjJ7DpUW75ZkrxsGieICFWlXvRnAyDdqQrkZRZQ==");
List<byte[]> pri = Base2Array("AAAAgBSjHDNiojO3UXZg6Ux4VyrOx9SCn9mCWgykWTEUeR6Anp6DxhlPUw3UEEetVy97hlw8iGCEQxcvG4T7qocni9UtUTLdpuQzvr6718y2CP0ouKt/1hVKD9QssT08XUvJEBQnnl2yVZAbIqT/DGnUH36L0BnQE/2ombPakwHscfFFAAAAQQCSfQy2cP8Oa0IR0u0whxqGmuuXY/3tCD8NaaSCYm31ly0QBdxFdf2WkC51DNVaf5/1ErHceMapFN9Z3j+/6lA7AAAAQQCFcMoSA32f240nFBmMv/nn/mL1uSdAXOxjUHViJc6M8ntZvW2ZuP2qTvfA3mh1AK5K69piX/4T72xxqTA2tmrfAAAAQFxX1JunFI+fpobdienVCZcjibwbpDPf1MVTbwQhAXHqVBL3XXgkysS/67X/aWnv/+SdBDaXa1SnDpphSWOkxAQ=");
//pub[0] 7
//pub[1] 1
//pub[2] 128
//pri[0] 128
//pri[1] 65
//pri[2] 65
//pri[3] 64
byte[] pubmod = null;
byte[] primod = null;
byte[] pubexp = null;
byte[] priexp = null;
pubexp = pub[0];
pubmod = pub[2];
priexp = pri[0];
primod = pri[2];
byte[] bstr = Encoding.ASCII.GetBytes("Test");
bstr = Encrypt(bstr, pubmod, pubexp);
bstr = Decrypt(bstr, pubexp, pubmod, null);
string str = Encoding.ASCII.GetString(bstr);
}
i do something like that:
public byte[] PublicDecryption(byte[] encryptedData)
{
var encData = new BigInteger(encryptedData);
BigInteger bnData = encData.modPow(_exponent, _modulus);
return bnData.getBytes();
}
public byte[] PrivateDecryption(byte[] encryptedData)
{
var encData = new BigInteger(encryptedData);
d = new BigInteger(rsaParams.D);
BigInteger bnData = encData.modPow(d, _modulus);
return bnData.getBytes();
}
where BigInteger is this:
http://www.codeproject.com/KB/cs/biginteger.aspx
because microsoft implementation is partial and buggy.
I've never had a problem with this.
Hope this help
Few month ago I have tried to implement scenario with private key encryption and public key decryption. I spent a week trying doing this with RSACryptoServiceProvider and.. nothing. They support only two use cases:
Public key encryption , private (full) key decryption.
Signing with private key, verifying with public.
And they have done everything to not allow you do something else with their API.
Please, check out msdn forums:
I have found many answers like that one msdn, including answers from support development team. All they said: that this is prohibit by design. So my suggestion is don't even try to do that with RSACryptoServiceProvider, better use another implementation.