I'm trying to simulate a Meet-in-the-Middle attack on Double DES which works as follows:
So I'm performing the MitM attack by first encrypting a known plaintext m and with all possible values of k1, and then subsequently I decrypt a known ciphertext c with all possible values of k2. Then there should be a match inbetween which gives me k1, and k2. I'm using a cut-down key size of 20 bits instead of 56bit (or 64bit which is what the DES implementation actually wants as input). I just pad with zeroes after 20bits.
I've implemented what I think is a right solution but not getting any matches.
My two hashtables:
Dictionary<string, string> hashTable = new Dictionary<string, string>();
Dictionary<string, string> matches = new Dictionary<string, string>();
Encrypting:
Since I'm using a reduced 20bit key, there can be 220 different combinations of 20bits. So for each iteration, I take the counter i, convert it to a binary string representation, then I pad 0s until it makes a 64bit binary value. Then I convert this string to a byte array and encrypt the plaintext with the key. I'm storing the output (intermediary cipher) as the key in the hashTable and the actual key used to get that cipher, as the value.
//First generate all possible intermediary values
for(int i=0; i< Math.Pow(2,20); i++)
{
string key1 = ToBin(i, 20);
string paddedKey1 = ToBin(i, 20).PadRight(64, '0');
//First encryption of plaintext1 using key1
string intermediaryCipher =
DESWrapper.DES_Encrypt(plaintext1, ConvertBinaryStringToByteArray(paddedKey1));
hashTable.Add(intermediaryCipher, key1);
//Show the current iteration in binary
Console.WriteLine(ToBin(i, 20));
}
DESWrapper.DES_Encrypt method:
public static string DES_Encrypt(string input, byte[] key)
{
DESCryptoServiceProvider desCryptoService = new DESCryptoServiceProvider();
//Reflection necessary otherwise it complains about a weak key, so bypassing that check
MethodInfo mi = desCryptoService.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
object[] Par = { key, desCryptoService.Mode, key, desCryptoService.FeedbackSize, 0 };
ICryptoTransform trans = mi.Invoke(desCryptoService, Par) as ICryptoTransform;
byte[] resultArray = trans.TransformFinalBlock(Encoding.Default.GetBytes(input), 0, Encoding.Default.GetBytes(input).Length);
desCryptoService.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
After the encryption I have a hastable with 220 entries. The next thing I do is to make the decryption:
Decrypting:
When I'm decrypting ciphertext1 with the current padded key, the result, if it is the correct key, will be an intermediary cipher which already exists in the hashTable as a Key. So I perform this lookup. If it exists I save the two keys to another hashtable matches. If it doesn't exist I move on.
for (int i = 0; i < Math.Pow(2, 20); i++)
{
string key2 = ToBin(i, 20);
string paddedKey2 = ToBin(i, 20).PadRight(64, '0');
//Decrypting ciphertext1 with key2 (64bit padded)
string intermediaryCipher =
DESWrapper.DES_Decrypt(ciphertext1, ConvertBinaryStringToByteArray(paddedKey2));
var temp = hashTable.FirstOrDefault(x => x.Key == intermediaryCipher);
if(temp.Key != null)
{
matches.Add(temp.Value, key2);
Console.WriteLine("Found match!");
Console.ReadKey();
}
//Show the current iteration in binary
Console.WriteLine(ToBin(i, 20));
}
DESWrapper.DES_Decrypt:
public static string DES_Decrypt(string input, byte[] key)
{
DESCryptoServiceProvider desCryptoService = new DESCryptoServiceProvider();
//Again have to use reflection..
MethodInfo mi = desCryptoService.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
object[] Par = { key, desCryptoService.Mode, key, desCryptoService.FeedbackSize, 0 };
ICryptoTransform trans = mi.Invoke(desCryptoService, Par) as ICryptoTransform;
byte[] resultArray = trans.TransformFinalBlock(Encoding.Default.GetBytes(input), 0, Encoding.Default.GetBytes(input).Length);
desCryptoService.Clear();
return Convert.ToBase64String(resultArray);
}
The problem:
I never get a match, so the hashtable lookup always returns an empty key-value pair. I don't understand why. Eventually it should match but it doesn't.
Could the problem be in the way I'm trying to look up the values in the hashTable?
Other information:
To encrypt the intial plaintext and ciphertext I use a fabricated key which the 17th bit set to 1 and all other 63 bits set to 0. This is done for both keys.
In this way I should get the match quite fast when I'm doing the decryption, but I'm not sure if the problem is here. Including the code anyway:
private static void GeneratePlaintextCiphertextPairs(out string plainText1, out string plainText2, out string cipherText1, out string cipherText2)
{
Random rnd = new Random(Guid.NewGuid().GetHashCode());
//Generate two random keys of 20 bits padded with 0s to reach 64 bits
//We need 64 bits because the implementation of DES requires it. Internally,
//it will only use 56 bits
byte[] key1 = GenerateRandom64BitPaddedKey(rnd);
byte[] key2 = GenerateRandom64BitPaddedKey(rnd);
plainText1 = "Hello Dear World";
//Perform double DES encryption
cipherText1 = DESWrapper.DES_Encrypt(
DESWrapper.DES_Encrypt(plainText1, key1),
key2);
plainText2 = "Hello Evil World";
//Perform double DES encryption
cipherText2 = DESWrapper.DES_Encrypt(
DESWrapper.DES_Encrypt(plainText2, key1),
key2);
}
private static byte[] GenerateRandom64BitPaddedKey(Random rnd)
{
short keySize = 64;
//The first 20bits are of interest, the rest is padded with 0s
BitArray bitArray = new BitArray(keySize);
for (int i=0; i<keySize; i++)
{
//if(i < 20) { bitArray[i] = rnd.NextDouble() > 0.5; }
//else { bitArray[i] = false; }
if (i == 17) { bitArray[i] = true; }
else { bitArray[i] = false; }
}
//Console.WriteLine("In Binary: " + ToDigitString(bitArray));
byte[] key = new byte[8];
ReverseBitArray(ref bitArray);
bitArray.CopyTo(key, 0);
return key;
}
Related
I have a server (python) and a client (c#), I need to communicate between them temporarily using assymetric rsa cryptography.
When I connect to the server as the client, I send him my public key and he send me his. I use at the server the rsa library and I get there the server's public key parameters {n,e} I send those and receive them with a space between them. I seperate them and convert the modulus into a BigInteger using this function:
public static BigInteger GetBigInteger(string number)
{
BigInteger bigNum = new BigInteger();
for (int i = number.Length; i > 0; i--)
{
bigNum *= 10;
bigNum += (int) number[number.Length-i];
}
return bigNum;
}
public static void Connect(IPAddress ipAddress, int port)
{
try
{
string[] message;
byte[] data = new byte[1024];
srvr.Receive(data); //Recieve the server's public key.
int length = int.Parse(Encoding.ASCII.GetString(data.Take(4).ToArray()));
message = Encoding.ASCII.GetString(data.Skip(4).Take(length).ToArray()).Split(' ') ;
RSACryptoServiceProvider RSAserver = new RSACryptoServiceProvider(1024);
RSAParameters par = new RSAParameters();
par.Modulus = GetBigInteger(message[0]).ToByteArray(); // Saves the server's public key.
par.Exponent = new byte[] { 1, 0, 1 }; // Saves the server's public key.
RSAserver.ImportParameters(par);
addresseeKey = RSAserver.ToXmlString(false);
...
}
...
}
An exception is thrown on the ImportParameters line that says: "The parameter is incorrect" .
What's wrong?
BigInteger.ToByteArray() exports the data in little-endian order. RSAParameters wants all of its data in big-endian order.
There's also an issue that the modulus value should have its most significant bit set, and therefore BigInteger.ToByteArray() needs to add in a padding byte to prevent the number from being reinterpreted as being negative, so you'll need to trim that off.
Assuming that your python export is representing the modulus as a base-10 positive integer, your code will work (though BigInteger.Parse(string) would be more efficient) once you align the data properly.
byte[] tmp = GetBigInteger(message[0]).ToByteArray();
// Array.Resize (to a smaller number) trims off the high index values,
// so it's slightly more compact code to do this before the resize.
if (tmp.Length > 0 && tmp[tmp.Length-1] == 0)
Array.Resize(ref tmp, tmp.Length - 1);
Array.Reverse(tmp);
par.Modulus = tmp;
I am trying to implement my own RSA encryption engine. Given these RSA algorithm values:
p = 61. // A prime number.
q = 53. // Also a prime number.
n = 3233. // p * q.
totient = 3120. // (p - 1) * (q - 1)
e = 991. // Co-prime to the totient (co-prime to 3120).
d = 1231. // d * e = 1219921, which is equal to the relation where 1 + k * totient = 1219921 when k = 391.
I am trying to write a method to encrypt each byte in a string and return back an encrypted string:
public string Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)BigInteger.ModPow(bytes[i], e, n);
}
string encryptedString = encoding.GetString(bytes);
Console.WriteLine("Encrypted {0} as {1}.", m, encryptedString);
return encryptedString;
}
The obvious issue here is that BigInteger.ModPow(bytes[i], e, n) may be too large to fit into a byte-space; it could result in values over 8 bits in size. How do you get around this issue while still being able to decrypt an encrypted string of bytes back into a regular string?
Update: Even encrypting from byte[] to byte[], you reach a case where encrypting that byte using the RSA algorithm goes beyond the size limit of a byte:
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)BigInteger.ModPow(bytes[i], e, n);
}
return bytes;
}
Update: My issue is that encryption would cause a greater number of bytes than the initial input string had:
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
byte[] returnBytes = new byte[0];
for (int i = 0; i < bytes.Length; i++)
{
byte[] result = BigInteger.ModPow(bytes[i], (BigInteger)e, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length);
result.CopyTo(returnBytes, preSize);
}
return returnBytes;
}
public string Decrypt(byte[] c, Encoding encoding)
{
byte[] returnBytes = new byte[0];
for (int i = 0; i < c.Length; i++)
{
byte[] result = BigInteger.ModPow(c[i], d, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length);
result.CopyTo(returnBytes, preSize);
}
string decryptedString = encoding.GetString(returnBytes);
return decryptedString;
}
If you ran this code like this:
byte[] encryptedBytes = engine.Encrypt("Hello, world.", Encoding.UTF8);
Console.WriteLine(engine.Decrypt(encryptedBytes, Encoding.UTF8));
The output would be this:
?♥D
?♥→☻►♦→☻►♦oD♦8? ?♠oj?♠→☻►♦;♂?♠♂♠?♠
Obviously, the output is not the original string because I can't just try decrypting each byte at a time, since sometimes two or more bytes of the cypher-text represent the value of one integer that I need to decrypt back to one byte of the original string...so I want to know what the standard mechanism for handling this is.
Your basic code for encrypting and decrypting each byte - the call to ModPow - is working, but you're going about the "splitting the message up and encrypting each piece" inappropriately.
To show that the ModPow part - i.e. the maths - is fine, here's code based on yours, which encrypts a string to a BigInteger[] and back:
using System;
using System.Linq;
using System.Numerics;
using System.Text;
class Test
{
const int p = 61;
const int q = 53;
const int n = 3233;
const int totient = 3120;
const int e = 991;
const int d = 1231;
static void Main()
{
var encrypted = Encrypt("Hello, world.", Encoding.UTF8);
var decrypted = Decrypt(encrypted, Encoding.UTF8);
Console.WriteLine(decrypted);
}
static BigInteger[] Encrypt(string text, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(text);
return bytes.Select(b => BigInteger.ModPow(b, (BigInteger)e, n))
.ToArray();
}
static string Decrypt(BigInteger[] encrypted, Encoding encoding)
{
byte[] bytes = encrypted.Select(bi => (byte) BigInteger.ModPow(bi, d, n))
.ToArray();
return encoding.GetString(bytes);
}
}
Next you need to read more about how a byte[] is encrypted into another byte[] using RSA, including all the different padding schemes etc. There's a lot more to it than just calling ModPow on each byte.
But to reiterate, you should not be doing this to end up with a production RSA implementation. The chances of you doing that without any security flaws are very slim indeed. It's fine to do this for academic interest, to learn more about the principles of cryptography, but leave the real implementations to experts. (I'm far from an expert in this field - there's no way I'd start implementing my own encryption...)
Note: I updated this answer. Please scroll down to the update for how it should actually be implemented because this first way of doing it is not the correct way of doing RSA encryption.
One way I can think to do it is like this (but may not be compliant to standards), and also, note this does not pad:
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
byte[] returnBytes = new byte[0];
for (int i = 0; i < bytes.Length; i++)
{
byte[] result = BigInteger.ModPow(bytes[i], (BigInteger)e, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length + 1);
(new byte[] { (byte)(result.Length) }).CopyTo(returnBytes, preSize);
result.CopyTo(returnBytes, preSize + 1);
}
return returnBytes;
}
public string Decrypt(byte[] c, Encoding encoding)
{
byte[] returnBytes = new byte[0];
for (int i = 0; i < c.Length; i++)
{
int dataLength = (int)c[i];
byte[] result = new byte[dataLength];
for (int j = 0; j < dataLength; j++)
{
i++;
result[j] = c[i];
}
BigInteger integer = new BigInteger(result);
byte[] integerResult = BigInteger.ModPow(integer, d, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + integerResult.Length);
integerResult.CopyTo(returnBytes, preSize);
}
string decryptedString = encoding.GetString(returnBytes);
return decryptedString;
}
This has the potential of being cross-platform because you have the option of using a different datatype to represent e or n and pass it to a C# back-end service like that. Here is a test:
string stringToEncrypt = "Mary had a little lamb.";
Console.WriteLine("Encrypting the string: {0}", stringToEncrypt);
byte[] encryptedBytes = engine.Encrypt(stringToEncrypt, Encoding.UTF8);
Console.WriteLine("Encrypted text: {0}", Encoding.UTF8.GetString(encryptedBytes));
Console.WriteLine("Decrypted text: {0}", engine.Decrypt(encryptedBytes, Encoding.UTF8));
Output:
Encrypting the string: Mary had a little lamb.
Encrypted text: ☻6☻1♦☻j☻☻&♀☻g♦☻t☻☻1♦☻? ☻g♦☻1♦☻g♦☻?♥☻?☻☻7☺☻7☺☻?♥☻?♂☻g♦☻?♥☻1♦☻$☺☻
c ☻?☻
Decrypted text: Mary had a little lamb.
Update: Everything I said earlier is completely wrong in the implementation of RSA. Wrong, wrong, wrong! This is the correct way to do RSA encryption:
Convert your string to a BigInteger datatype.
Make sure your integer is smaller than the value of n that you've calculated for your algorithm, otherwise you won't be able to decypher it.
Encrypt the integer. RSA works on integer encryption only. This is clear.
Decrypt it from the encrypted integer.
I can't help but wonder that the BigInteger class was mostly created for cryptography.
As an example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace BytePadder
{
class Program
{
const int p = 61;
const int q = 53;
const int n = 3233;
const int totient = 3120;
const int e = 991;
const int d = 1231;
static void Main(string[] args)
{
// ---------------------- RSA Example I ----------------------
// Shows how an integer gets encrypted and decrypted.
BigInteger integer = 1000;
BigInteger encryptedInteger = Encrypt(integer);
Console.WriteLine("Encrypted Integer: {0}", encryptedInteger);
BigInteger decryptedInteger = Decrypt(encryptedInteger);
Console.WriteLine("Decrypted Integer: {0}", decryptedInteger);
// --------------------- RSA Example II ----------------------
// Shows how a string gets encrypted and decrypted.
string unencryptedString = "A";
BigInteger integer2 = new BigInteger(Encoding.UTF8.GetBytes(unencryptedString));
Console.WriteLine("String as Integer: {0}", integer2);
BigInteger encryptedInteger2 = Encrypt(integer2);
Console.WriteLine("String as Encrypted Integer: {0}", encryptedInteger2);
BigInteger decryptedInteger2 = Decrypt(encryptedInteger2);
Console.WriteLine("String as Decrypted Integer: {0}", decryptedInteger2);
string decryptedIntegerAsString = Encoding.UTF8.GetString(decryptedInteger2.ToByteArray());
Console.WriteLine("Decrypted Integer as String: {0}", decryptedIntegerAsString);
Console.ReadLine();
}
static BigInteger Encrypt(BigInteger integer)
{
if (integer < n)
{
return BigInteger.ModPow(integer, e, n);
}
throw new Exception("The integer must be less than the value of n in order to be decypherable!");
}
static BigInteger Decrypt(BigInteger integer)
{
return BigInteger.ModPow(integer, d, n);
}
}
}
Example output:
Encrypted Integer: 1989
Decrypted Integer: 1000
String as Integer: 65
String as Encrypted Integer: 1834
String as Decrypted Integer: 65
Decrypted Integer as String: A
If you are looking to use RSA encryption in C# then you should not be attempting to build your own. For starters the prime numbers you have chosen are probably to small. P and Q are supposed to be large prime numbers.
You should check out some other question/answers:
how to use RSA to encrypt files (huge data) in C#
RSA Encryption of large data in C#
And other references:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
i try to coding HMAC-SHA256 Algorithm as Function
HMAC (K,m) = H((K ⊕ opad) ∥ H((K ⊕ ipad) ∥ m))
where
H is a cryptographic hash function,
K is a secret key padded to the right with extra zeros to the input block size of the hash function, or the hash of the original key if it's longer than that block size,
m is the message to be authenticated,
∥ denotes concatenation,
⊕ denotes exclusive or (XOR),
opad is the outer padding (0x5c5c5c…5c5c, one-block-long hexadecimal constant),
ipad is the inner padding(0x363636…3636, one-block-long hexadecimal constant).
and this my code
public static string MyHMACHash(string key , string message)
{
Encoding encoding = Encoding.UTF8;
//var md = System.Security.Cryptography.MD5CryptoServiceProvider.Create();
SHA256 hash = SHA256Managed.Create();
byte[] trans_5C = new byte[32];
byte[] trans_36 = new byte[32];
byte[] b_key = encoding.GetBytes(key);
// TODO: also check if key is to short
if (b_key.Length > 32)
b_key = hash.ComputeHash(b_key);
for (int i = 0; i < 32; i++)
{
trans_5C[i] = 92;
trans_36[i] = 54;
if (i < key.Length)
{
trans_5C[i] ^= b_key[i];
trans_36[i] ^= b_key[i];
}
}
byte[] inner = hash.ComputeHash(trans_36.Concat(encoding.GetBytes(message)).ToArray());
var Fhash = hash.ComputeHash(trans_5C.Concat(inner).ToArray());
StringBuilder sb = new StringBuilder();
foreach (byte b in Fhash)
sb.Append(b.ToString("x2"));
string result = sb.ToString(); // = 9036a1a3f654aefeab426e9f7e17288e
return result;
}
but when i try to test this code the result Non-conforming to standard HMAC-SHA256 hashing on the standard internet web sites
Here is the modified version with custom HMAC generation. Main thing to consider is that Input Block Size referred in the K, is the hash algorithm block size; not returned hashed byte length. For SHA256, block size is 64 bytes. I believe you were using 32byte block size. You can find different block size references here: http://en.wikipedia.org/wiki/Secure_Hash_Algorithm.
public static string MyHMACHash(string key, string message)
{
Encoding encoding = Encoding.UTF8;
//Reference http://en.wikipedia.org/wiki/Secure_Hash_Algorithm
//SHA256 block size is 512 bits => 64 bytes.
const int HashBlockSize = 64;
var keyBytes = encoding.GetBytes(key);
var opadKeySet = new byte[HashBlockSize];
var ipadKeySet = new byte[HashBlockSize];
if (keyBytes.Length > HashBlockSize)
{
keyBytes = GetHash(keyBytes);
}
// This condition is independent of previous
// condition. If previous was true
// we still need to execute this to make keyBytes same length
// as blocksize with 0 padded if its less than block size
if (keyBytes.Length < HashBlockSize)
{
var newKeyBytes = new byte[HashBlockSize];
keyBytes.CopyTo(newKeyBytes, 0);
keyBytes = newKeyBytes;
}
for (int i = 0; i < keyBytes.Length; i++)
{
opadKeySet[i] = (byte)(keyBytes[i] ^ 0x5C);
ipadKeySet[i] = (byte)(keyBytes[i] ^ 0x36);
}
var hash = GetHash(ByteConcat(opadKeySet,
GetHash(ByteConcat(ipadKeySet, encoding.GetBytes(message)))));
// Convert to standard hex string
return hash.Select<byte, string>(a => a.ToString("x2"))
.Aggregate<string>((a, b) => string.Format("{0}{1}", a, b));
}
public static byte[] GetHash(byte[] bytes)
{
using (var hash = new SHA256Managed())
{
return hash.ComputeHash(bytes);
}
}
public static byte[] ByteConcat(byte[] left, byte[] right)
{
if (null == left)
{
return right;
}
if (null == right)
{
return left;
}
byte[] newBytes = new byte[left.Length + right.Length];
left.CopyTo(newBytes, 0);
right.CopyTo(newBytes, left.Length);
return newBytes;
}
I have been over an article at CodeProject a for a while that explains how to encrypt and decrypt using the RSA provider:
RSA Private Key Encryption
While the old version from 2009 was buggy, the new 2012 version (with System.Numerics.BigInteger support) seems more reliable. What this version lacks though is a way to encrypt with a public key and decrypt using the private key.
So, I tried it myself but get garbage when I decrypt. I'm not familiar with the RSA provider, so I'm in the dark here. It's hard to find more info on how this is supposed to work.
Does anyone see what is wrong with this?
The following is ENcryption with a PUBLIC key:
// Add 4 byte padding to the data, and convert to BigInteger struct
BigInteger numData = GetBig( AddPadding( data ) );
RSAParameters rsaParams = rsa.ExportParameters( false );
//BigInteger D = GetBig( rsaParams.D ); //only for private key
BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );
BigInteger encData = BigInteger.ModPow( numData, Exponent, Modulus );
return encData.ToByteArray();
Do I use the big "D" from the provider when I do this? Probably not since it's the public key which doesn't have the "D".
Then the counterpart (DEcrypting using the PRIVATE key):
BigInteger numEncData = new BigInteger( cipherData );
RSAParameters rsaParams = rsa.ExportParameters( true );
BigInteger D = GetBig( rsaParams.D );
//BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );
BigInteger decData = BigInteger.ModPow( numEncData, D, Modulus );
byte[] data = decData.ToByteArray();
byte[] result = new byte[ data.Length - 1 ];
Array.Copy( data, result, result.Length );
result = RemovePadding( result );
Array.Reverse( result );
return result;
Do I need the "D" or the Exponent here?
Obviously I need the crypto to work both ways private-public public-private.
Any help is much appreciated!
Take this encode/decode example
byte[] toEncryptData = Encoding.ASCII.GetBytes("hello world");
//Generate keys
RSACryptoServiceProvider rsaGenKeys = new RSACryptoServiceProvider();
string privateXml = rsaGenKeys.ToXmlString(true);
string publicXml = rsaGenKeys.ToXmlString(false);
//Encode with public key
RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider();
rsaPublic.FromXmlString(publicXml);
byte[] encryptedRSA = rsaPublic.Encrypt(toEncryptData, false);
string EncryptedResult = Encoding.Default.GetString(encryptedRSA);
//Decode with private key
var rsaPrivate = new RSACryptoServiceProvider();
rsaPrivate.FromXmlString(privateXml);
byte[] decryptedRSA = rsaPrivate.Decrypt(encryptedRSA, false);
string originalResult = Encoding.Default.GetString(decryptedRSA);
here is an example for you:
public static void rsaPlayground()
{
byte[] data = new byte[] { 1, 2, 3, 4, 5 };
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();//make a new csp with a new keypair
var pub_key = csp.ExportParameters(false); // export public key
var priv_key = csp.ExportParameters(true); // export private key
var encData = csp.Encrypt(data, false); // encrypt with PKCS#1_V1.5 Padding
var decBytes = MyRSAImpl.plainDecryptPriv(encData, priv_key); //decrypt with own BigInteger based implementation
var decData = decBytes.SkipWhile(x => x != 0).Skip(1).ToArray();//strip PKCS#1_V1.5 padding
}
public class MyRSAImpl
{
private static byte[] rsaOperation(byte[] data, BigInteger exp, BigInteger mod)
{
BigInteger bData = new BigInteger(
data //our data block
.Reverse() //BigInteger has another byte order
.Concat(new byte[] { 0 }) // append 0 so we are allways handling positive numbers
.ToArray() // constructor wants an array
);
return
BigInteger.ModPow(bData, exp, mod) // the RSA operation itself
.ToByteArray() //make bytes from BigInteger
.Reverse() // back to "normal" byte order
.ToArray(); // return as byte array
/*
*
* A few words on Padding:
*
* you will want to strip padding after decryption or apply before encryption
*
*/
}
public static byte[] plainEncryptPriv(byte[] data, RSAParameters key)
{
MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
return rsaOperation(data, myKey.privExponent, myKey.Modulus);
}
public static byte[] plainEncryptPub(byte[] data, RSAParameters key)
{
MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
}
public static byte[] plainDecryptPriv(byte[] data, RSAParameters key)
{
MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
return rsaOperation(data, myKey.privExponent, myKey.Modulus);
}
public static byte[] plainDecryptPub(byte[] data, RSAParameters key)
{
MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
}
}
public class MyRSAParams
{
public static MyRSAParams fromRSAParameters(RSAParameters key)
{
var ret = new MyRSAParams();
ret.Modulus = new BigInteger(key.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
ret.privExponent = new BigInteger(key.D.Reverse().Concat(new byte[] { 0 }).ToArray());
ret.pubExponent = new BigInteger(key.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
return ret;
}
public BigInteger Modulus;
public BigInteger privExponent;
public BigInteger pubExponent;
}
I've been trying to encrypt a password with a public RSA key that is sent to me by the server.
var csp = new CspParameters(1, "Microsoft Strong Cryptographic Provider");
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1280, csp);
byte[] key = ByteUtils.HexToBytes(client.RSAKey);
RSA.ImportCspBlob(key);
byte[] encrypted = RSA.Encrypt(Encoding.ASCII.GetBytes(password), true);
The hex key is provided in such format:
string key = "30819D300D06092A864886F70D010101050003818B0030818702818100C7BD672D8C634D443840AD809790852770D3A2E99F456D6516329E0205D0645C23FD001D4D070CEE368A20526FEB2402358C915D7E86102B1659AA8651C449C344599F72BE904B8E338E7002E9978453C5BBCCA51AC165AA265069E0EAB1411D11A2FFDD35E5A8296A6A2AF238945874E8206979B0A16E2E4260A161CAB5C905020111";
As the string is 320-bytes long in hex format, I assume the key is 160 bytes (RSA 1280)
Using this method, the provider keeps saying "Bad Version of provider.\r\n".
I've tried several methods, convert it to Base64, simply import it as ASCII / Unicode. Nothing worked so far.
EDIT: My HexToBytes function (which works afaik, it returns me correct 160-b array):
public static byte[] HexToBytes(string pValue)
{
// FIRST. Use StringBuilder.
StringBuilder builder = new StringBuilder();
// SECOND... USE STRINGBUILDER!... and LINQ.
foreach (char c in pValue.Where(IsHexDigit).Select(Char.ToUpper))
{
builder.Append(c);
}
// THIRD. If you have an odd number of characters, something is very wrong.
string hexString = builder.ToString();
if (hexString.Length % 2 == 1)
{
//throw new InvalidOperationException("There is an odd number of hexadecimal digits in this string.");
// I will just add a zero to the end, who cares (0 padding)
Log.WriteLine(LogLevel.Debug, "Hexstring had an odd number of hexadecimal digits.");
hexString += '0';
}
byte[] bytes = new byte[hexString.Length / 2];
// FOURTH. Use the for-loop like a pro :D
for (int i = 0, j = 0; i < bytes.Length; i++, j += 2)
{
string byteString = String.Concat(hexString[j], hexString[j + 1]);
bytes[i] = HexToByte(byteString);
}
return bytes;
}
Your public key is not in the correct format. It is not a CSP blob. It is a DER encoded SubjectPublicKeyInfo structure. You can find source code to parse it or you can write your own. Here is one example of such code.