How to write RSA encrypt function in C# - c#

I have following nodejs code to encrypt RSA:
const encryptWithRSA = (PublicKey, selData) => {
let encrypted = crypto.publicEncrypt(
{
key: -----BEGIN PUBLIC KEY-----\n${PublicKey}\n-----END PUBLIC KEY-----,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
Buffer.from(selData)
);
return encrypted.toString("base64");
};
Then I tried to convert this code block to C# :
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
public static string Encrypt(string publickey, string data)
{
string key = publickey;
Asn1Object obj = Asn1Object.FromByteArray(Convert.FromBase64String(key));
DerSequence publicKeySequence = (DerSequence)obj;
DerBitString encodedPublicKey = (DerBitString)publicKeySequence[1];
DerSequence publicKey = (DerSequence)Asn1Object.FromByteArray(encodedPublicKey.GetBytes());
DerInteger modulus = (DerInteger)publicKey[0];
DerInteger exponent = (DerInteger)publicKey[1];
RsaKeyParameters keyParameters = new RsaKeyParameters(false, modulus.PositiveValue, exponent.PositiveValue);
RSAParameters parameters = DotNetUtilities.ToRSAParameters(keyParameters);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(parameters);
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(data);
byte[] encryptedData = rsa.Encrypt(dataToEncrypt, RSAEncryptionPadding.Pkcs1);
return Convert.ToBase64String(encryptedData);
}
Two code return 2 different results. Anyone can show me what wrong? Thanks!

Related

Bouncy Castle Encrypt and Decrypt Password - Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'

NOTE: This is NOT for encrypting user passwords. Use a Hash to store user passwords. You can also throw some salt on those passwords similarly to salt bae.
I need to store one of my passwords to log into a program. I can encrypt the password but when I decrypt I get the error:
Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'
I am going to use a different private key so I'm not worried about posting this one here.
Program Class:
var input = "TestPassword123!";
Encryption EC = new Encryption();
var Key = "-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQCr874y+f3cYtz8hOuxamwHYUK7WS03c3t7LHMuCpmiR9wOz1FHEbBk6ZdvhY74I9sE+lIs0bUZVh08nKIS/txeECZ/d3WYDm8gW+mFjg0xD7LgQ9Prchsvrb2Q9c6FK5Us8i0iqOhDmrZdCYO+/zhyrYnP/Wy1EZTWPvMrI/GVWwIDAQABAoGBAJW5Sg8HIKYKq5NxhezY1rHiXYHWV4nmE0ogXTZk4nusiI+Ys5PncimcQFFKAUBNsEL4WB9QhplGI3UIihNyOZx68waSB6NiAi+tz8i7edTxDfwWkM271roOJxD3RzUJuQkyc57ZxrD61UyodRatmRoJkPhLBlEvIr9/dCwYBl0pAkEA5ucK8CFdxr4DWIAutZLeeeQx9oe1tCi/iUvEpSDOHKAvaELLBiD4bIInN4nx/Gj1gwHqICg8L/gs0x23cQWz3QJBAL6kYaRQFvCmVajTaTJ3ef3gYwynPsmfT5Urx0DWW5rXtbtZQ7vScDKRU4YbmBb3tD5eT/Fl/dIakPGv+hxllpcCQA3o5TPKDsgmMjVmo2m0y0o0gP4E9uE/gypWMiZwb3ox/CkfvPNFkTGYNZyW5sj52bBmsR/2zIlnPewJ4j8gxNECQDOT/8LX1E0Jg5VolUaNIpk4UzQCL6+XBY4DSSZWmHQdNlLYxMWVGrvjq6hV4OEd5UsWcySJhpGIlHx/Mvjp10MCQAon0SLhRI8QNrWfp/dLuFdqTy4b4y64j3HvooOu6GDZwCLwjqvwML3rimxUi52EQspssIOlLjpQjvIJvYBKBys=-----END RSA PRIVATE KEY-----";
var encrypted = EC.RsaEncrypt(input, Key);
string password = EC.RsaDecrypt(encrypted, Key);
Encryption Class
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
namespace TemarkNamespace
{
internal class Encryption
{
public string RsaEncrypt(string clearText, string Key)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(Key))
{
var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyPair.Private);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
// Decryption:
public string RsaDecrypt(string pass, string Key)
{
var bytesToDecrypt = Convert.FromBase64String(pass);
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(Key))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
}
}
I found this code and it seems to work fine
using System.Security.Cryptography;
public string Encrypt(string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
var encoding = new UTF8Encoding();
byte[] plain = encoding.GetBytes(s);
byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(secret);
}
}
public string Decrypt(string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
byte[] secret = Convert.FromBase64String(s);
byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
var encoding = new UTF8Encoding();
return encoding.GetString(plain);
}
}

C# decryption: Length of the data to decrypt if invalid error

Ok so for a school project I am making an app that has an encryption function.
Here is my code
public static string EncryptString(string stringToEncrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
Currently the encryption method works, however the decryption method crashes the entire app. The error message is as follows:
System.Security.Cryptography.CryptographicException: 'Length of the data to decrypt is invalid.'
It it important for the app that the user can set their own encryption/decryption key.
What exactly is causing the app to not work? I can provide more information if needed.
Thanks.
This should resolve your problem, you just need to decode the base64 string in the decrypt function, ie byte[] data = Convert.FromBase64String(stringToDecrypt);.
Also we want to return a string, rather than base64 data, so we'll do UTF8Encoding.UTF8.GetString() at then end of DecryptString.
I would take note of the fact that this would not be considered secure as the comments above indicate, but this is a learning exercise, so this will get you up and running!
I've also created a DotNetFiddle here: https://dotnetfiddle.net/PPzXKo
using System;
using System.Security;
using System.Text;
using System.Security.Cryptography;
namespace triple_des_test
{
public class Program
{
public void Main()
{
string key = "my key";
string encrypted = EncryptString("Hello world", key);
Console.WriteLine("Encrypted: " + encrypted);
Console.WriteLine("Decrypted: " + DecryptString(encrypted, key));
}
public static string EncryptString(string stringToEncrypt, string key)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string key)
{
byte[] data = Convert.FromBase64String(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(results, 0, results.Length);
}
}
}
}
}

Encrypt password by using Public Key (.pem) file

Now I have a Public Key(.pem) file and password to encrypt.
-----BEGIN PUBLIC KEY-----
.....
...
...
-----END PUBLIC KEY-----
I would like to get byte[] values for encrypted password.
It doesn't get any error but return byte[] values is seem to wrong.
Below are coding current my using one, pls help me or advise me if I'm going wrong.
Really appreciate for your help!!
private static UnicodeEncoding _encoder = new UnicodeEncoding();
public byte[] getPem(string pemFile, string password)
{
byte[] encryptData;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] Exponent = { 1, 0, 1 };
RSAParameters rsaParam = rsa.ExportParameters(false);
rsaParam.Modulus = Convert.FromBase64String(File.ReadAllText(pemFile).Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""));
rsaParam.Exponent = Exponent;
rsa.ImportParameters(rsaParam);
var dataToEncrypt = _encoder.GetBytes(password);
encryptData = rsa.Encrypt(dataToEncrypt, false);
return encryptData;
}

C# RSA Encryption to PHP Decryption using PHP OpenSSL public key

I'm trying to load a OpenSSL public key from a SOAP server through Nusoap into C#, encrypt my data using the public key, then send the data back to the PHP server for decryption using the private key.
My C# looks like this:
static void Main(string[] args)
{
PHPRef.AddService test = new PHPRef.AddService();
var pkey = test.getPublicKey();
//Console.WriteLine(pkey.ToString());
byte[] PublicKey = GetBytes(pkey);
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
//Get an instance of RSAParameters from ExportParameters function.
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
Console.WriteLine("RijndaelManaged Key and IV have been encrypted with RSACryptoServiceProvider.");
byte[] encryptedData = RSA.Encrypt(GetBytes("password"), false);
//byte[] returned = (byte[])(Array)test.getDecrypted((sbyte[])(Array)encryptedData);
//string answer = GetString(returned);
string answer = test.getDecrypted((sbyte[])(Array)encryptedData);
Console.WriteLine(answer);
Console.ReadLine();
}
static byte[] GetBytes(string str)
{
byte[] bytes = Encoding.ASCII.GetBytes(str);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = Encoding.ASCII.GetChars(bytes);
return new string(chars);
}
And my PHP like so:
function getPublicKey()
{
$crt = file_get_contents("public.crt");
// $publickey = str_ireplace("\r", "", $crt);
// $publickey = str_ireplace("\n", "", $publickey);
// $publickey = str_ireplace("-----BEGIN CERTIFICATE-----", "", $publickey);
// $publickey = str_ireplace("-----END CERTIFICATE-----", "", $publickey);
return $crt;
}
function getDecrypted($input)
{
global $privateRSA;
// $privateRSA = str_ireplace("\r", "", $privateRSA);
// $privateRSA = str_ireplace("\n", "", $privateRSA);
// $privateRSA = str_ireplace("-----BEGIN RSA PRIVATE KEY-----", "", $privateRSA);
// $privateRSA = str_ireplace("-----END RSA PRIVATE KEY-----", "", $privateRSA);
if(!openssl_private_decrypt($input, $decrypted, $privateRSA))
return "fail";
else
return "success";
return $decrypted;
}
Needless to say I get "fail" every time. Any suggestions? I'm trying to do this with pure PHP and pure C#, no special libraries. The keys are 2048 bit.
After nearly a full day trying to find this, it was incredibly simple. You don't need BouncyCastle, SecLib, any third-party libraries, nothing.
C#:
static void Main(string[] args)
{
PHPRef.AddService test = new PHPRef.AddService();
var pkey = test.getPublicKey();
byte[] pkeybyte = GetBytes(pkey);
X509Certificate2 cert = new X509Certificate2();
cert.Import(pkeybyte);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] encryptedData = rsa.Encrypt(GetBytes("password"), false);
Console.WriteLine(GetString(encryptedData));
string answer = test.getDecrypted((sbyte[])(Array)encryptedData);
Console.WriteLine(answer);
Console.ReadLine();
}
And the PHP:
Just change getPublicKey like so
function getPublicKey()
{
$crt = file_get_contents("public.crt");
$publickey = str_ireplace("\r", "", $crt);
$publickey = str_ireplace("\n", "", $publickey);
$publickey = str_ireplace("-----BEGIN CERTIFICATE-----", "", $publickey);
$publickey = str_ireplace("-----END CERTIFICATE-----", "", $publickey);
return $publickey;
}

WinRT RSA encryption from public key exponent/modulus

I'm trying to port this method from .NET 4.5 desktop app to a WinRT app:
static byte[] DotNetRsaEncrypt(string modulus, string exponent, byte[] data)
{
var modulusBytes = Convert.FromBase64String(modulus);
var exponentBytes = Convert.FromBase64String(exponent);
var rsaParameters = new RSAParameters { Modulus = modulusBytes, Exponent = exponentBytes };
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
var encrypted = rsa.Encrypt(data, true);
return encrypted;
}
After reading this RSA Encryption in metro style Application
I tried the following:
static byte[] WinRtRsaEncrypt(string modulus, string exponent, byte[] data)
{
var modulusBytes = Convert.FromBase64String(modulus);
var exponentBytes = Convert.FromBase64String(exponent);
var keyBlob = modulusBytes.Concat(exponentBytes).ToArray().AsBuffer();
var rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha1);
var key = rsa.ImportPublicKey(keyBlob, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
var encrypted = CryptographicEngine.Encrypt(key, data.AsBuffer(), null);
return encrypted;
}
But it does not work.
In order to get the same functionality as my desktop app...
What AsymmetricAlgorithmNames should I pass to OpenAlgorithm()?
What CryptographicPublicKeyBlobType should I pass to ImportPublicKey()?
Following up on user1968335's hint, this worked for me.
First, in a C# application, use the following code to obtain a CspBlob from your modulus/exponent:
var exponent = Encoding.Default.GetBytes(exponentStr);
var modulus = Encoding.Default.GetBytes(modulusStr);
var rsaParameters = new RSAParameters { Modulus = modulus, Exponent = exponent };
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
var cspBlobString = Convert.ToBase64String(rsa.ExportCspBlob(false));
Then, in a WinRT application you can use that CspBlob to sign a piece of data like this:
private static string SignString(string data)
{
string cspBlobString = //cspBlob
var keyBlob = CryptographicBuffer.DecodeFromBase64String(cspBlobString);
AsymmetricKeyAlgorithmProvider rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey key = rsa.ImportPublicKey(keyBlob, CryptographicPublicKeyBlobType.Capi1PublicKey);
IBuffer plainBuffer = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
IBuffer encryptedBuffer = CryptographicEngine.Encrypt(key, plainBuffer, null);
byte[] encryptedBytes;
CryptographicBuffer.CopyToByteArray(encryptedBuffer, out encryptedBytes);
return Convert.ToBase64String(encryptedBytes);
}
If it matters, this is how I generated my asymmetric keys: http://43n141e.blogspot.co.uk/2008/08/rsa-encryption-openssl-to-ruby-to-c-and_27.html
According to CryptoWinRT sample, OpenAlgorithm(...) method takes these values.
RSA_PKCS1
RSA_OAEP_SHA1
RSA_OAEP_SHA256
RSA_OAEP_SHA384
See also : RSA cryptography between a WinRT and a .Net app

Categories

Resources