Problems with the method ecdsa.VerifyData() - c#

I'm trying to verify some data with a public key the method ecdsa.VerifyData() that I'm signing with private key and I'm getting a false return and I don't know why.
These are the methods to Sign and Verify the data:
public byte[] SignData(byte[] dataValue)
{
X509Certificate2 privateKey = new X509Certificate2(privateKeyPfxFile);
//Encryting/Signing a hash
using (ECDsa ecdsa = privateKey.GetECDsaPrivateKey())
{
if (ecdsa == null) throw new Exception("Not an ECDSA cert, or has no private key");
return ecdsa.SignData(dataValue, HashAlgorithmName.SHA256);
}
}
public bool VerifyData(byte[] dataValue, byte[] dataSigned)
{
byte[] mycertCer = Properties.Resources.mycertCer;
X509Certificate2 publicKey = new X509Certificate2(mycertCer);
//Checking the hash and signature
using (ECDsa ecdsa = publicKey.GetECDsaPublicKey())
{
if (ecdsa == null) throw new Exception("Not an ECDSA cert, or has no private key");
return ecdsa.VerifyData(dataValue, dataSigned, HashAlgorithmName.SHA256);
}
}
This is how I create the keys:
public void CreateAsymmetricKeysPair(string path, string keyName)
{
var ecdsa = ECDsa.Create(); // generate asymmetric key pair
var req = new CertificateRequest("cn=localhost", ecdsa, HashAlgorithmName.SHA256);
var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
// Create PFX (PKCS #12) with private key
File.WriteAllBytes(Path.Join(path, keyName + ".pfx"), cert.Export(X509ContentType.Pfx));
// Create Base 64 encoded CER (public key only)
File.WriteAllText(Path.Join(path,keyName + ".cer"),
"-----BEGIN CERTIFICATE-----\r\n"
+ Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)
+ "\r\n-----END CERTIFICATE-----");
}
That is my unit test that I'm getting a false return:
private const string rawText = "test";
[Fact]
public void OnSignData_DoReturnSignature_WhenValidStream()
{
//Arrange
var rawBytes = Encoding.UTF8.GetBytes(rawText);
//Act
var signature = licenseService.SignData(rawBytes);
var isValid = licenseService.VerifyData(rawBytes, signature);
//Assert
Assert.True(isValid);
}
Am I missing something?

I just checked that this line was returning my old public key even that I deleted and pasted another one.
byte[] mycertCer = Properties.Resources.mycertCer;

Related

Decrypt and verify hash for SHA256 - c#

I am trying to decrypt and validate the hash but at times of decrypting, it throws me the error 'Key does not exist' and at the time of validating the hash return False
https://payvyne.readme.io/docs/webhooks
Signature:
HEjoCsghC9X0slrE2DprptDLYdoA7jaw4Jl7vpJVxzx9GNJEiO3pYGLDPhLmVqk98QJJ/FuiS5J+fvp+msr3Y8aFzKqjRQXj5TBELT38N+A7I8y3Vc0mgeR0aDMx7I83yhfkcoyhdiGJibzqQ5SYFZ0nnEVHYXheLUlga45yg/McDICtMm6lhnrPWEuHzoZTQkhsrLN/1W1PtLjJ2DickWB78PmhpeflL2Cpe6qS3qCclqFGZ7HIl9OoxU4WXpTYgxw7eixAKB7apFdFqea4BnGravfENNl97pOBuU6fRof4KtMczVagQw3QnxFD3BBtpTepRaT+jHY8wStXUG1bxllH32WiA9CVcpY4mxKhpxzQ8YD0b+3OgkpzZYS+BVVAdVazMJeEAw7v/zaxpjbR+Zo5l9vOLdyatwM75qpwMoKnMeKJHeRytEOK54al49OHiaE+v1OkOhJA0zh5nLzEIZanIdf+hXHDz3Euecs/p0cABiFNmhzYY5fl8qEytK6j2CjXQOYgljG5dqPm7M9CW36ntZTDaIEVWql3jdi9frxc4/82w1jhROFL0pBG1zz8nimAEesB1AaxmNqW7BIxULweX7eaReeo/dIqDSbmFuT+TikPQo4XRtmpDqO37Y9P6q7ZXtHOFopSaykHUHs+NgrKlBJMM5ADg5bHWm2Qows=
Public key:
pA6ULfXWrIMq-qvxn_0CykoStq0ZMYm63lHsuXTsE4q4tgekLJDW2Lnf35ilbFU_vybBdyeJAphpsYc4P0eJBt_z2T62HAV3gnwp_GU6hWIo8faK31TSXIrLmGjZlAVynAxjFYZoNxMeZuwEXpxG4bRGs58P7XSx1fAzedX6oGIlcSLljKH4I1BHt6gJhPIHYNXQzq_a0hX54C1m1VDVP_kot8ui1YKZil_riROK_Xk4ktnOTAqXo9z4uNBqzzH2k0J2YNiCb8VOdbp7kjmH9sPLI-jb-ociy0wSkGZc1e8saGIkkSm4eUASvX_M_TTDD99OrgoIS2Vx07Tw4lK5yd28EMVBUzy2OypuPVf9PyoDGv_4241x5PpJsA9IKocD7AgwxJ3E7FBFhvuSP8c5wspkbQxBwv5nnk2zAxuZsiJeK0o3JSxjkZJEkeVY4mA3VV9SvSXEKAFg2h9J3CR9PTwrZoVBruycVtWJ4it5jroXff-aGlLoRAO0g3gtfjkJb3tw6SJTFOA49iJci76Mj8Adz3eeEEGxTxfDzh_lq0jXxTk7cQSaR2_ChYLHaoorrrFmAvWgDH_lSvlISIgey-SzUoJM9RAy4gVFdmg-XCQQlpMh_d1-IACO3EfBvYKWE-6uGIqx1nZhn9WIDdSqMp6940xRxl0vQy8vYCQ5q8U
Data for Sign in string:
{"type":"PAYMENT_STATUS_CHANGE","paymentId":"1c6e834f074ec941","status":"FAILED","timestamp":1652688286662,"amount":"164.69","currency":"GBP","description":"This is test payment","paymentType":"ONE_OFF","bankName":"Diamond bank","destinationAccount":"GBP2","createdAt":"2022-05-16T08:04:32.994","updatedAt":"2022-05-16T08:04:46.662","customerReference":"1199","refundedAmount":"0.00"}
Expo (exponent):
AQAB
Below is the code to Decrypt the signature using public key.
public static void DecryptUsingPublicKey(string publicKey, string expo, string signature)
{
var modulus = ConvertToBase64(publicKey);
var exponent = Convert.FromBase64String(expo);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
var _publicKey = csp.ExportParameters(false);
_publicKey.Modulus = modulus;
_publicKey.Exponent = exponent;
csp.ImportParameters(_publicKey);
var dataBytes = ConvertToBase64(signature);
var plainText = csp.Decrypt(dataBytes, false);
var returnData = Encoding.Unicode.GetString(plainText);
Console.WriteLine($"value: {returnData}");
}
Below is the code for Verify signature using public key
public static void VerifySignature(string signature, string pKey, string dataForSign)
{
string pKeyNew = pKey;
pKeyNew = pKeyNew.Replace("_", "/").Replace("-", "+");
string publicKey = $"<RSAKeyValue><Modulus>{pKeyNew}==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var encoder = new UTF8Encoding();
byte[] dataForSignAsBytes = encoder.GetBytes(dataForSign);
byte[] signatureAsBytes = ConvertToBase64(signature);
RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
rsaCryptoServiceProvider.FromXmlString(publicKey);
var hashData = SHA256.Create().ComputeHash(dataForSignAsBytes);
var result1 = rsaCryptoServiceProvider.VerifyData(dataForSignAsBytes, CryptoConfig.MapNameToOID("SHA256"), signatureAsBytes);
var result2 = rsaCryptoServiceProvider.VerifyHash(hashData, CryptoConfig.MapNameToOID("SHA256"), signatureAsBytes);
var result3 = rsaCryptoServiceProvider.VerifyHash(hashData, signatureAsBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
var result4 = rsaCryptoServiceProvider.VerifyData(dataForSignAsBytes, signatureAsBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
Console.WriteLine(result1);
Console.WriteLine(result2);
Console.WriteLine(result3);
Console.WriteLine(result4);
}
ConvertToBase64 function
public static byte[] ConvertToBase64(string data)
{
byte[] cyperBuffer;
string dataNew = data;
dataNew = dataNew.Replace("_", "/").Replace("-", "+");
try
{
if (dataNew.Substring(dataNew.Length - 1) != "=")
{
dataNew += "=";
}
cyperBuffer = Convert.FromBase64String(dataNew);
}
catch
{
dataNew += "=";
try
{
cyperBuffer = Convert.FromBase64String(dataNew);
}
catch
{
//If any error occured while convert to base64 then append '=' at the end.
dataNew += "=";
cyperBuffer = Convert.FromBase64String(dataNew);
}
}
return cyperBuffer;
}
This is a conversion mistake; you need to decode the base 64 signature, not encode the signature, so the following line is wrong:
byte[] signatureAsBytes = ConvertToBase64(signature);
it should be something like:
byte[] signatureAsBytes = ConvertFromBase64(signature);
Decryption is modular exponentiation with a private key. Furthermore, encryption normally uses a different padding scheme than signature generation, so you'd expect that the unpadding would fail if you try and decrypt. Only verification is possible.

Encrypt string using public key as text in C#

I have recieved a public keY in txt format. (BEGIN CERTIFICATE---END CERTIFICATE)
I want to encrypt my message using this key in C# and send it across.
Similarly I have my private key in text format. I have shared my public key with the third party, which they are using to encrypt the message. I want to decrypt the message using my private key in TEXT format.
How do i do that in C#?
Kindly help.
public class MyCrypto
{
public X509Certificate2 GetDecryptionCertificate(string certificateName)
{
var my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
my.Open(OpenFlags.ReadOnly);
var collection = my.Certificates.Find(X509FindType.FindBySubjectName, certificateName, false);
if (collection.Count == 1)
{
return collection[0];
}
else if (collection.Count > 1)
{
throw new Exception(string.Format("More than one certificate with name '{0}' found in store LocalMachine/My.", certificateName));
}
else
{
throw new Exception(string.Format("Certificate '{0}' not found in store LocalMachine/My.", certificateName));
}
}
public X509Certificate2 GetEncryptionCertificate(string filePath)
{
var collection = new X509Certificate2Collection();
collection.Import(filePath);
return collection[0];
}
public string EncryptRsa(string input, X509Certificate2 x509Certificate2)
{
var output = string.Empty;
using (RSA csp = (RSA)x509Certificate2.PublicKey.Key)
{
byte[] bytesData = Encoding.UTF8.GetBytes(input);
byte[] bytesEncrypted = csp.Encrypt(bytesData, RSAEncryptionPadding.OaepSHA1);
output = Convert.ToBase64String(bytesEncrypted);
}
return output;
}
public string DecryptRsa(string encrypted, X509Certificate2 x509Certificate2)
{
var text = string.Empty;
using (RSA csp = (RSA)x509Certificate2.PrivateKey)
{
byte[] bytesEncrypted = Convert.FromBase64String(encrypted);
byte[] bytesDecrypted = csp.Decrypt(bytesEncrypted, RSAEncryptionPadding.OaepSHA1);
text = Encoding.UTF8.GetString(bytesDecrypted);
}
return text;
}
}

Trying to decrypt a string with public key(not private) using bouncycastle in .net

As a sample app, I encrypted a string using an rsa public key(supplied by a 3rd party api) using BouncyCastle library in .NET. When I send this encrypted string to the said 3rd party api endpoint, it is able to decrypt it(using its private key). I don't have their private key, but, is it possible to decrypt the string on my end using just the public key that I have?
From my understanding of RSA public/private key pair, when decrypting, you use the private key stored with you to decrypt a string and use the public key to confirm that you are receiving data from a said source.
public string RsaEncryptWithPublic(string clearText
, string publicKey)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(publicKey))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyParameter);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
public string RsaDecrypt(string base64Input
, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
//get a stream from the string
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
//decryptEngine.Init(false, keyPair.Private);
decryptEngine.Init(false, keyPair.Public);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
static void Main(string[] args)
{
string _creditCardNumber = "5454545454545454";
string publicKey = System.IO.File.ReadAllText(#"C:\ThirdPartyKeys\RSAPublicKey_01.txt");
var enc = new EncryptionClass();
var encryptedWithPublic = enc.RsaEncryptWithPublic(_creditCardNumber, publicKey);
Console.WriteLine("String: " + _creditCardNumber);
Console.WriteLine("Encrypted String: " + encryptedWithPublic);
// Decrypt
var outputWithPublic = enc.RsaDecrypt(encryptedWithPublic, publicKey);
//var outputWithPrivate = enc.RsaDecrypt(encryptedWithPrivate, _privateKey);
Console.WriteLine("Decrypted String: " + outputWithPublic);
}
The encryption works, but when I try to decrypt with the same public key, it complains of
Invalid Cast Exception:
Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters' to type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.
at line in RsaDecrypt function:
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
No. It's Asymmetric Encryption which means you can't decrypt it with the public key. If you could, it would defeat the purpose and anyone with the public key would be able to decrypt your secret message

Using Azure Key Vault RSA Key to encrypt and decrypt strings

I have setup Azure Key Vault to retrieve RSA Keys for encryption. Azure send me an object of type KeyBundle. This object contains a JsonWebKey of type RSA of size 2048. Looking at my RSA Key, it has 2 methods called Encrypt(byte[] data, RSAEncryptionPadding padding) and Decrypt(byte[] data, RSAEncryptionPadding padding). Now I am trying to encrypt and decrypt a simple string like this:
public EncryptionManager(KeyBundle encryptionKey)
{
string test = "Hello World!";
var key = encryptionKey.Key.ToRSA();
var encryptedString = key.Encrypt(Encoding.UTF8.GetBytes(test), RSAEncryptionPadding.OaepSHA256);
var decryptedString = key.Decrypt(encryptedString, RSAEncryptionPadding.OaepSHA256);
}
Encryption works, but decryption throws an exception with message:
Key does not exist.
Here is the StackTrace
at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(Byte[]
data, RSAEncryptionPadding padding, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.Decrypt(Byte[]
data, RSAEncryptionPadding padding) at
NxtUtils.Security.EncryptionManager..ctor(KeyBundle encryptionKey) in
C:\Repos\Enigma\EnigmaPrototype\SharedLibaries\NxtUtils\Security\EncryptionManager.cs:line
26
I am really not familiar with cryptographic algorithms. My question is: How can I encrypt and decrypt a simple strig using this RSA Key provided by Azure?
Thanks!
I got the same issue, what I did is here although I searched from internet and got this from the Microsoft docs
so this is my working code below
public static class KeyVaultEncryptorDecryptor
{
public static string KeyDecryptText(this string textToDecrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).Result;
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var encryptedTextNew = Convert.FromBase64String(textToDecrypt);
var decryptedData = kv.DecryptAsync(key.KeyIdentifier.Identifier.ToString(), JsonWebKeyEncryptionAlgorithm.RSAOAEP, encryptedTextNew).GetAwaiter().GetResult();
var decryptedText = Encoding.Unicode.GetString(decryptedData.Result);
return decryptedText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
public static string KeyEncryptText(this string textToEncrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).GetAwaiter().GetResult();
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var byteData = Encoding.Unicode.GetBytes(textToEncrypt);
var encryptedText = rsa.Encrypt(byteData, true);
string encText = Convert.ToBase64String(encryptedText);
return encText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
}
ToRSA has a default boolean parameter indicating if the private key should be available, or not.
Since you didn't explicitly say true it is implicitly false, therefore your key object is public-only. With a public RSA key you can encrypt data or verify a signature, but you cannot sign or decrypt.

Error occurred while decoding OAEP Padding C#

Below is my code and error is in the Title. I encrypted using private key but I decrypt using the same private key I ran into the error mentioned in the title, not really sure what is the underlying cause of the error. Any help in that regard will be highly appreciated.
Class Program
{
static void Main(string[] args)
{
string thumbPrint = "SomeValue";
EncryptUserName("Steve", thumbPrint, true, true);
}
public static void EncryptUserName(string textToEncript, string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
X509Certificate2 cert = FindCertificate(certificateThumbprint, searchLocalMachine, searchUser);
RSACryptoServiceProvider rsaEncryptor = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] cipherData = rsaEncryptor.Encrypt(Encoding.UTF8.GetBytes(textToEncript), true);
var encryptedString = Convert.ToBase64String(cipherData);
Console.WriteLine(encryptedString);
}
public static byte[] Decrypt(byte[] encryptedData, bool fOAEP, X509Certificate2 certificate)
{
if (encryptedData == null)
{
throw new ArgumentNullException("encryptedData");
}
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
if (certificate.PrivateKey == null)
{
throw new ApplicationException("Certificate provided has no private key");
}
Console.WriteLine(certificate.PrivateKey);
using (RSACryptoServiceProvider provider = (RSACryptoServiceProvider)certificate.PrivateKey)
{
return provider.Decrypt(encryptedData, fOAEP);
}
}
public static string CertificateDecrypt(string textToDecript, string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
X509Certificate2 certificate = FindCertificate(certificateThumbprint, searchLocalMachine, searchUser);
byte[] bytesArray = Convert.FromBase64String(textToDecript);
//Decrypt(bytesArray, true, certificate);
return Encoding.UTF8.GetString(Decrypt(bytesArray, true, certificate));
}
public static X509Certificate2 LoadCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
{
X509Store store = null;
X509Certificate2 certificate2;
try
{
store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Enumerator enumerator = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false).GetEnumerator();
X509Certificate2 current = null;
while (enumerator.MoveNext())
{
current = enumerator.Current;
}
certificate2 = current;
}
finally
{
if (store != null)
{
store.Close();
}
}
return certificate2;
}
private static X509Certificate2 FindCertificate(string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
certificateThumbprint = certificateThumbprint.Replace(" ", "");
X509Certificate2 certificate = null;
if (searchUser)
{
certificate = LoadCertificate(StoreName.My, StoreLocation.CurrentUser, certificateThumbprint);
}
if (searchLocalMachine && (certificate == null))
{
certificate = LoadCertificate(StoreName.My, StoreLocation.LocalMachine, certificateThumbprint);
}
if (certificate == null)
{
throw new ApplicationException($"Certificate with thumbprint {certificateThumbprint} cannot be loaded (not found)");
}
return certificate;
}
}
Error occurred while decoding OAEP Padding happens when either the input string for the decrypt is not exactly the same as the output string of the encrypt, or because the public key used for encryption does not match the private key used for decryption.
In your case, you are not actually passing an encrypted string to the Decrypt method so it will absolutely always fail, essentially making the encryption and decryption key not match.

Categories

Resources