C# Encrypt string with public RSA-1280 hex key - c#

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.

Related

How to encrypt a string using public key cryptography

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

Are there any rules for the XOR cipher?

I have the following method which takes the plain text and the key text. It is supposed to return a string encrypted with the XOR method as ascii.
public static string encryptXOREng(string plainText,string keyText)
{
StringBuilder chiffreText = new StringBuilder();
byte[] binaryPlainText = System.Text.Encoding.ASCII.GetBytes(plainText);
byte[] binaryKeyText = System.Text.Encoding.ASCII.GetBytes(keyText);
for(int i = 0;i<plainText.Length;i++)
{
int result = binaryPlainText[i] ^ binaryKeyText[i];
chiffreText.Append(Convert.ToChar(result));
}
return chiffreText.ToString();
}
For some characters it runs just fine. But for example if it performs XOR on 'G' & 'M', which is 71 XOR 77 it returns 10. And 10 stands for Line feed. This is then actually not represented by a character in my output. This leads to a plain text of a length being encrypted to a cipher string which is only 2 characters long, in some cases. I suppose this would make a decryption impossible, even with a key? Or are the ascii characters 0 - 31 there but simply not visible?
To avoid non printable chars use Convert.ToBase64String
public static string encryptXOREng(string plainText, string keyText)
{
List<byte> chiffreText = new List<byte>();
byte[] binaryPlainText = System.Text.Encoding.ASCII.GetBytes(plainText);
byte[] binaryKeyText = System.Text.Encoding.ASCII.GetBytes(keyText);
for (int i = 0; i < plainText.Length; i++)
{
int result = binaryPlainText[i] ^ binaryKeyText[i % binaryKeyText.Length];
chiffreText.Add((byte)result);
}
return Convert.ToBase64String(chiffreText.ToArray());
}
PS: In your code you assume keyText is not shorter than plainText, I fixed it also.
As far as i know there are no rules specific to xor-ciphers. Cryptographic functions often output values that are not printable, which makes sense - the result is not supposed to be readable. In stead you may want to use the output bytes directly or a base64 encoded result.
I would do something like:
public static byte[] XORCipher(string plainText, string keyText)
{
byte[] binaryPlainText = System.Text.Encoding.ASCII.GetBytes(plainText);
byte[] binaryKeyText = System.Text.Encoding.ASCII.GetBytes(keyText);
for(int i = 0;i<plainText.Length;i++)
{
binaryPlainText[i] ^= binaryKeyText[i];
}
return binaryPlainText;
}

How to decrypt an encrypted data in c# by using RSACryptoServiceProvider() in ubuntu?

I am encrypting my data by using RSACryptoServiceProvider() class in c#. I want to decrypt the data in ubuntu, that was encrypted in c#. Can you suggest me which mechanism I need to follow in order to decrypt. Following function is for encryption:
public static void Encrypt(String PublicKey, String plainText, out String cipherText)
{
try
{
int dwKeySize = 1024;
// TODO: Add Proper Exception Handlers
RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(dwKeySize);
rsaCryptoServiceProvider.FromXmlString(PublicKey);
int keySize = dwKeySize / 8;
byte[] bytes = Encoding.UTF32.GetBytes(plainText);
// The hash function in use by the .NET RSACryptoServiceProvider here is SHA1
// int maxLength = ( keySize ) - 2 - ( 2 * SHA1.Create().ComputeHash( rawBytes ).Length );
int maxLength = keySize - 42;
int dataLength = bytes.Length;
int iterations = dataLength / maxLength;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i <= iterations; i++)
{
byte[] tempBytes = new byte[(dataLength - maxLength * i > maxLength) ? maxLength : dataLength - maxLength * i];
Buffer.BlockCopy(bytes, maxLength * i, tempBytes, 0, tempBytes.Length);
byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt(tempBytes, true);
// Be aware the RSACryptoServiceProvider reverses the order
// of encrypted bytes after encryption and before decryption.
// If you do not require compatibility with Microsoft Cryptographic API
// (CAPI) and/or other vendors.
// Comment out the next line and the corresponding one in the
// DecryptString function.
Array.Reverse(encryptedBytes);
// Why convert to base 64?
// Because it is the largest power-of-two base printable using only ASCII characters
stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
}
cipherText = stringBuilder.ToString();
}
catch (Exception e)
{
cipherText = "ERROR_STRING";
Console.WriteLine("Exception in RSA Encrypt: " + e.Message);
//throw new Exception("Exception occured while RSA Encryption" + e.Message);
}
}
Don't use RSA like that. It's not meant to be used that way and it's way too slow.
The right way is to use a symmetric algorithm, e.g. AES, and encrypt the key you used with RSA. See my old blog entry for C# code doing just that.
You need the same mechanisms, but in reverse. Try first, ask later.

How to use 3DES encryption results to calculate the MAC value

I have a project to do for work to do in C#. I have the requirements for a project and this part is just a small piece in the entire project. I was given test data and the result. I need to code it so that I get the correct results. And at the moment I'm not getting the final result.
Please don't question or criticise the requirements, it's what I have and need to sort out and code it.
I was told to take input string "abc" and compute the SHA-1 hash for this. I got this part to work, here is the code:
private string CalculateSHA1Hash(string text, Encoding characterEncoding)
{
byte[] buffer = characterEncoding.GetBytes(text);
SHA1CryptoServiceProvider sha1CryptoServiceProvider = new SHA1CryptoServiceProvider();
byte[] s = sha1CryptoServiceProvider.ComputeHash(buffer);
string hash = BitConverter.ToString(sha1CryptoServiceProvider.ComputeHash(buffer)).Replace("-", "");
return hash;
}
I used UTF8Encoding because none was specified in the requirements doc. The result that I got from this is A9993E364706816ABA3E25717850C26C9CD0D89D.
I was then told to break up this string into 3 string blocks, of 16 characters each, and use just the 1st block. This is what I got:
block1: A9993E364706816A
I was also given 2 keys:
K1: 0123456789ABCDEF
K2: FEDCBA9876543210
Block1 is to be used as input string to a 3DES encryption using the 2 keys.
The result of the cipher text must be 6E5271A3F3F5C418, I am not getting this.
Below is my calculations. Can someone please see if I am doing this correctly and where I am doing this wrong. Chris (on SO) gave me some articles to read but I still can't get the results that I need to get. Is there something that cater for this already, I'm I just totally confused, or what?
public string Encrypt(string message)
{
string result = string.Empty;
// Calculate the SHA1 hash
UTF8Encoding characterEncoding = new UTF8Encoding();
string sha1HashResult = CalculateSHA1Hash(message, characterEncoding);
block1 = sha1HashResult.Substring(0, 16);
byte[] block1ByteArray = characterEncoding.GetBytes(block1);
string key = "0x" + accessKey1 + accessKey2 + accessKey1;
byte[] keyByteArray = StringToByteArray(key).ToArray();
byte[] enc = ComputeTripleDesEncryption(block1ByteArray, keyByteArray);
result = ByteArrayToString(enc);
return result;
}
public byte[] ComputeTripleDesEncryption(byte[] plainText, byte[] key)
{
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = key;
des.GenerateIV();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
ICryptoTransform ic = des.CreateEncryptor();
byte[] enc = ic.TransformFinalBlock(plainText, 0, plainText.Length);
return enc;
}
private byte[] StringToByteArray(String hex)
{
if (hex.Substring(0, 2) == "0x")
{
hex = hex.Substring(2);
}
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
private string ByteArrayToString(byte[] ba)
{
string hex = BitConverter.ToString(ba);
return hex.Replace("-", "");
}
I really do not know what to do further.
There's a few things wrong with what you have right now:
You're specifying that you need to use an IV, but you're using ECB (which doesn't use an IV)
You're generating the IV randomly, using GenerateIV(). This will cause the result to be different every time, if you're not using ECB.
You're only performing the transform on the final block, instead of the whole data.
See the following code sample for a decent idea of how to use 3DES in C#:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.tripledescryptoserviceprovider.aspx
I'd guess that since you're specifying an IV, you're actually meant to be using CBC instead of ECB. Try it out and see what you get.

C# Split byte[] array

I am doing RSA encryption and I have to split my long string into small byte[] and encrypt them. I then combine the arrays and convert to string and write to a secure file.
Then encryption creates byte[128]
I use this the following to combine:
public static byte[] Combine(params byte[][] arrays)
{
byte[] ret = new byte[arrays.Sum(x => x.Length)];
int offset = 0;
foreach (byte[] data in arrays)
{
Buffer.BlockCopy(data, 0, ret, offset, data.Length);
offset += data.Length;
}
return ret;
}
When I decrypt I take the string, convert it to a byte[] array and now need to split it to decode the chunks and then convert to string.
Any ideas?
Thanks
EDIT:
I think I have the split working now however the decryption fails. Is this because of RSA keys etc? At TimePointA it encrypts it, then at TimePointB it tries to decrypt and it fails. The public keys are different so not sure if that is the issue.
When you decrypt, you can create one array for your decrypt buffer and reuse it:
Also, normally RSA gets used to encrypt a symmetric key for something like AES, and the symmetric algorithm is used to encrypt the actual data. This is enormously faster for anything longer than 1 cipher block. To decrypt the data, you decrypt the symmetric key with RSA, followed by decrypting the data with that key.
byte[] buffer = new byte[BlockLength];
// ASSUMES SOURCE IS padded to BlockLength
for (int i = 0; i < source.Length; i += BlockLength)
{
Buffer.BlockCopy(source, i, buffer, 0, BlockLength);
// ... decode buffer and copy the result somewhere else
}
Edit 2: If you are storing the data as strings and not as raw bytes, use Convert.ToBase64String() and Convert.FromBase64String() as the safest conversion solution.
Edit 3: From his edit:
private static List<byte[]> splitByteArray(string longString)
{
byte[] source = Convert.FromBase64String(longString);
List<byte[]> result = new List<byte[]>();
for (int i = 0; i < source.Length; i += 128)
{
byte[] buffer = new byte[128];
Buffer.BlockCopy(source, i, buffer, 0, 128);
result.Add(buffer);
}
return result;
}
I'd say something like this would do it:
byte[] text = Encoding.UTF8.GetBytes(longString);
int len = 128;
for (int i = 0; i < text.Length; )
{
int j = 0;
byte[] chunk = new byte[len];
while (++j < chunk.Length && i < text.Length)
{
chunk[j] = text[i++];
}
Convert(chunk); //do something with the chunk
}
Why do you need to break the string into variable length chunks? Fixed-length chunks, or no chunks at all, would simplify this a lot.
why not use a framework instead of doing the byte-stuff yourself?
http://www.codinghorror.com/blog/archives/001275.html
"the public keys are different"?
You encrypt with a private key, and decrypt with the public key that corresponds to the private key.
Anything else will give you gibberish.

Categories

Resources