Byte array cryptography in C# - c#

I want to create a nice cryptography using bitwise operators.
However I fail to do so.
I want it to have bitwise operators using a byte array to encrypt and decrypt my byte array.
public class Cryptographer
{
private byte[] Keys { get; set; }
public Cryptographer(string password)
{
Keys = Encoding.ASCII.GetBytes(password);
}
public void Encrypt(byte[] data)
{
for(int i = 0; i < data.Length; i++)
{
data[i] = (byte) (data[i] & Keys[i]);
}
}
public void Decrypt(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)(Keys[i] & data[i]);
}
}
}
I know this is wrong, thats why I need help.
I simply want it to use 1 string to encrypt and decrypt all data.

This is what is sometimes known as 'craptography', because it provides the illusion of security while being functionally useless in protecting anything. Use the framework classes if you want to do cryptography right, because it's extremely difficult to roll your own.
Take a look at this for advice on what you are trying to do (encrypt/decrypt) - http://msdn.microsoft.com/en-us/library/e970bs09.aspx. Really your requirements should determine what classes you decide to use. This has good background: http://msdn.microsoft.com/en-us/library/92f9ye3s.aspx
For simple encrypt/decrypt (if this is what you need) DPAPI may be the simplest way.

You seem to be trying to implement the XOR cipher. XOR is ^ in C#:
public void Crypt(byte[] data)
{
for(int i = 0; i < data.Length; i++)
{
data[i] = (byte) (data[i] ^ Keys[i]);
} ↑
}
Since the Encrypt and Decrypt method do exactly the same, you need only one method.
Note, however, that this is just a toy and not suitable to secure data in real-world scenarios. Have a look at the System.Security.Cryptography Namespace which provides many implementations of proven algorithms. Using these correctly is still hard to get right though.

Use Xor ^ operator and not And &. Also you should not assume that data and key are the same length.
public class Cryptographer
{
private byte[] Keys { get; set; }
public Cryptographer(string password)
{
Keys = Encoding.ASCII.GetBytes(password);
}
public void Encrypt(byte[] data)
{
for(int i = 0; i < data.Length; i++)
{
data[i] = (byte) (data[i] ^ Keys[i % Keys.Length]);
}
}
public void Decrypt(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)(Keys[i % Keys.Length] ^ data[i]);
}
}
}

static void Main(string[] args)
{
Int32 a = 138;
Console.WriteLine("first int: " + a.ToString());
byte[] bytes = BitConverter.GetBytes(a);
var bits = new BitArray(bytes);
String lol = ToBitString(bits);
Console.WriteLine("bit int: " + lol);
lol = lol.Substring(1, lol.Length - 1) + lol[0];
Console.WriteLine("left : " + lol);
byte[] bytes_new = GetBytes(lol);
byte[] key = { 12, 13, 24, 85 };
var bits2 = new BitArray(key);
String lol2 = ToBitString(bits2);
Console.WriteLine("key : " + lol2);
byte[] cryptedBytes = Crypt(bytes_new, key);
var bits3 = new BitArray(cryptedBytes);
String lol3 = ToBitString(bits3);
Console.WriteLine(" XOR: " + lol3);
byte[] deCryptedBytes = Crypt(cryptedBytes, key);
var bits4 = new BitArray(cryptedBytes);
String lol4 = ToBitString(bits4);
Console.WriteLine(" DEXOR: " + lol4);
int a_new = BitConverter.ToInt32(bytes_new, 0);
Console.WriteLine("and int: " + a_new.ToString());
Console.ReadLine();
}
public static byte[] Crypt(byte[] data, byte[] key)
{
byte[] toCrypt = data;
for (int i = 0; i < toCrypt.Length; i++)
{
toCrypt[i] = (byte)(toCrypt[i] ^ key[i]);
}
return toCrypt;
}
private static String ToBitString(BitArray bits)
{
var sb = new StringBuilder();
for (int i = bits.Count - 1; i >= 0; i--)
{
char c = bits[i] ? '1' : '0';
sb.Append(c);
}
return sb.ToString();
}
private static byte[] GetBytes(string bitString)
{
byte[] result = Enumerable.Range(0, bitString.Length / 8).
Select(pos => Convert.ToByte(
bitString.Substring(pos * 8, 8),
2)
).ToArray();
List<byte> mahByteArray = new List<byte>();
for (int i = result.Length - 1; i >= 0; i--)
{
mahByteArray.Add(result[i]);
}
return mahByteArray.ToArray();
}

Remember, there is no such thing as a 'secure' cipher. Any encryption method that can be written can be broken.
With that being said, using simple bitwise techniques for encryption is inviting a not too bright hacker to break your encryption. There are guys/gals that sit around all day long with nothing better to do.
Use one of the encryption libraries that uses a large key and do something 'unusual' to that key before using it. Even so, remember, there are people employed and not employed to do nothing but break cryptographic messages all around the world; 24 by 7.
The Germans thought they had an un-breakable system in WW II. They called it Enigma. Do some reading on it and you will discover that it was broken even before the war broke out!

Related

Packing bytes manually to send on network

I have an object that has the following variables:
bool firstBool;
float firstFloat; (0.0 to 1.0)
float secondFloat (0.0 to 1.0)
int firstInt; (0 to 10,000)
I was using a ToString method to get a string that I can send over the network. Scaling up I have encountered issues with the amount of data this is taking up.
the string looks like this at the moment:
"false:1.0:1.0:10000" this is 19 characters at 2 bytes per so 38 bytes
I know that I can save on this size by manually storing the data in 4 bytes like this:
A|B|B|B|B|B|B|B
C|C|C|C|C|C|C|D
D|D|D|D|D|D|D|D
D|D|D|D|D|X|X|X
A = bool(0 or 1), B = int(0 to 128), C = int(0 to 128), D = int(0 to 16384), X = Leftover bits
I convert the float(0.0 to 1.0) to int(0 to 128) since I can rebuild them on the other end and the accuracy isn't super important.
I have been experimenting with BitArray and byte[] to convert the data into and out of the binary structure.
After some experiments I ended up with this serialization process(I know it needs to be cleaned up and optimized)
public byte[] Serialize() {
byte[] firstFloatBytes = BitConverter.GetBytes(Mathf.FloorToInt(firstFloat * 128)); //Convert the float to int from (0 to 128)
byte[] secondFloatBytes = BitConverter.GetBytes(Mathf.FloorToInt(secondFloat * 128)); //Convert the float to int from (0 to 128)
byte[] firstIntData = BitConverter.GetBytes(Mathf.FloorToInt(firstInt)); // Get the bytes for the int
BitArray data = new BitArray(32); // create the size 32 bitarray to hold all the data
int i = 0; // create the index value
data[i] = firstBool; // set the 0 bit
BitArray ffBits = new BitArray(firstFloatBytes);
for(i = 1; i < 8; i++) {
data[i] = ffBits[i-1]; // Set bits 1 to 7
}
BitArray sfBits = new BitArray(secondFloatBytes);
for(i = 8; i < 15; i++) {
data[i] = sfBits[i-8]; // Set bits 8 to 14
}
BitArray fiBits = new BitArray(firstIntData);
for(i = 15; i < 29; i++) {
data[i] = fiBits[i-15]; // Set bits 15 to 28
}
byte[] output = new byte[4]; // create a byte[] to hold the output
data.CopyTo(output,0); // Copy the bits to the byte[]
return output;
}
Getting the information back out of this structure is much more complicated than getting it into this form. I figure I can probably workout something using the bitwise operators and bitmasks.
This is proving to be more complicated than I was expecting. I thought it would be very easy to access the bits of a byte[] to manipulate the data directly, extract ranges of bits, then convert back to the values required to rebuild the object. Are there best practices for this type of data serialization? Does anyone know of a tutorial or example reference I could read?
Standard and efficient serialization methods are:
Using BinaryWriter / BinaryReader:
public byte[] Serialize()
{
using(var s = new MemoryStream())
using(var w = new BinaryWriter(s))
{
w.Write(firstBool);
w.Write(firstFloat);
...
return s.ToArray();
}
}
public void Deserialize(byte[] bytes)
{
using(var s = new MemoryStream(bytes))
using(var r = new BinaryReader(s))
{
firstBool = r.ReadBool();
firstFload = r.ReadFloat();
...
}
}
Using protobuf.net
BinaryWriter / BinaryReader is much faster (around 7 times). Protobuf is more flexible, easy to use, very popular and serializes into around 33% fewer bytes. (of course these numbers are orders of magnitude and depend on what you serialize and how).
Now basically BinaryWriter will write 1 + 4 + 4 + 4 = 13 bytes. You shrink it to 5 bytes by converting the values to bool, byte, byte, short first by rounding it the way you want. Finally it's easy to merge the bool with one of your bytes to get 4 bytes if you really want to.
I don't really discourage manual serialization. But it has to be worth the price in terms of performance. The code is quite unreadable. Use bit masks and binary shifts on bytes directly but keep it as simple as possible. Don't use BitArray. It's slow and not more readable.
Here is a simple method for pack/unpack. But you loose accuracy converting a float to only 7/8 bits
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
foreach (Data data in Data.input)
{
Data.Print(data);
Data results = Data.Unpack(Data.Pack(data));
Data.Print(results);
}
Console.ReadLine();
}
}
public class Data
{
public static List<Data> input = new List<Data>() {
new Data() { firstBool = true, firstFloat = 0.2345F, secondFloat = 0.432F, firstInt = 12},
new Data() { firstBool = true, firstFloat = 0.3445F, secondFloat = 0.432F, firstInt = 11},
new Data() { firstBool = false, firstFloat = 0.2365F, secondFloat = 0.432F, firstInt = 9},
new Data() { firstBool = false, firstFloat = 0.545F, secondFloat = 0.432F, firstInt = 8},
new Data() { firstBool = true, firstFloat = 0.2367F, secondFloat = 0.432F, firstInt = 7}
};
public bool firstBool { get; set; }
public float firstFloat {get; set; } //(0.0 to 1.0)
public float secondFloat {get; set; } //(0.0 to 1.0)
public int firstInt { get; set; } //(0 to 10,000)
public static byte[] Pack(Data data)
{
byte[] results = new byte[4];
results[0] = (byte)((data.firstBool ? 0x80 : 0x00) | (byte)(data.firstFloat * 128));
results[1] = (byte)(data.secondFloat * 256);
results[2] = (byte)((data.firstInt >> 8) & 0xFF);
results[3] = (byte)(data.firstInt & 0xFF);
return results;
}
public static Data Unpack(byte[] data)
{
Data results = new Data();
results.firstBool = ((data[0] & 0x80) == 0) ? false : true;
results.firstFloat = ((float)(data[0] & 0x7F)) / 128.0F;
results.secondFloat = (float)data[1] / 256.0F;
results.firstInt = (data[2] << 8) | data[3];
return results;
}
public static void Print(Data data)
{
Console.WriteLine("Bool : '{0}', 1st Float : '{1}', 2nd Float : '{2}', Int : '{3}'",
data.firstBool,
data.firstFloat,
data.secondFloat,
data.firstInt
);
}
}
}

How to simplify these methods to avoid confusion?

I've come here today to ask a question about these methods. I've taken lead on a personal project as a hobby and unfortunately I can't contact the old developer to ask what these methods even do. I'm pretty new to C# so I was asking if anyone could help me in simplifying them, to avoid the confusion I'm having? If anyone could actually tell me what they do also that would really help.
I'm just a little confused about them as of now... They were in the utilities folder. The project is an emulation server for a game, sending and receiving packets is the main focus.
public static int DecodeInt32(byte[] v)
{
if ((v[0] | v[1] | v[2] | v[3]) < 0)
{
return -1;
}
return (v[0] << 0x18) + (v[1] << 0x10) + (v[2] << 8) + v[3];
}
public static int DecodeInt16(byte[] v)
{
if ((v[0] | v[1]) < 0)
{
return -1;
}
return (v[0] << 8) + v[1];
}
Here is a part of code that uses them, might help in finding out?
using (BinaryReader Reader = new BinaryReader(new MemoryStream(Data)))
{
if (Data.Length < 4)
return;
int MsgLen = Utilities.DecodeInt32(Reader.ReadBytes(4));
if ((Reader.BaseStream.Length - 4) < MsgLen)
{
this._halfData = Data;
this._halfDataRecieved = true;
return;
}
else if (MsgLen < 0 || MsgLen > 5120)//TODO: Const somewhere.
return;
byte[] Packet = Reader.ReadBytes(MsgLen);
using (BinaryReader R = new BinaryReader(new MemoryStream(Packet)))
{
int Header = Utilities.DecodeInt16(R.ReadBytes(2));
byte[] Content = new byte[Packet.Length - 2];
Buffer.BlockCopy(Packet, 2, Content, 0, Packet.Length - 2);
ClientPacket Message = new ClientPacket(Header, Content);
try
{
Server.GetGame().GetPacketManager().TryExecutePacket(this, Message);
}
catch (Exception e)
{
ExceptionLogger.LogException(e);
}
this._deciphered = false;
}
if (Reader.BaseStream.Length - 4 > MsgLen)
{
byte[] Extra = new byte[Reader.BaseStream.Length - Reader.BaseStream.Position];
Buffer.BlockCopy(Data, (int)Reader.BaseStream.Position, Extra, 0, (int)(Reader.BaseStream.Length - Reader.BaseStream.Position));
this._deciphered = true;
HandleMoreData(Extra);
}
}
The BinaryReader has the methods ReadInt16 and ReadInt32 (and many others). Therefore you could replace the decoding methods.
int MsgLen = Utilities.DecodeInt32(Reader.ReadBytes(4));
becomes
int MsgLen = Reader.ReadInt32();
I assume that the Endianness of the bytes is right for the BinaryReader methods.

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

Try To Code HMAC-SHA256 using C#.Net

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;
}

Rfc2898 / PBKDF2 with SHA256 as digest in c#

I want to use Rfc2898 in c# to derive a key. I also need to use SHA256 as Digest for Rfc2898. I found the class Rfc2898DeriveBytes, but it uses SHA-1 and I don't see a way to make it use a different digest.
Is there a way to use Rfc2898 in c# with SHA256 as digest (short of implementing it from scratch)?
.NET Core has a new implementation of Rfc2898DeriveBytes.
The CoreFX version no longer has the the hashing algorithm hard-coded
The code is available on Github. It was merged to master on March 2017 and has been shipped with .NET Core 2.0.
For those who need it, .NET Framework 4.7.2 includes an overload of Rfc2898DeriveBytes that allows the hashing algorithm to be specified:
byte[] bytes;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256))
{
bytes = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
The HashAlgorithmName options at the moment are:
MD5
SHA1
SHA256
SHA384
SHA512
See Bruno Garcia's answer.
At the time I started this answer, Rfc2898DeriveBytes was not configurable to use a different hash function. In the meantime, though, it has been improved; see Bruno Garcia's answer. The following function can be used to generate a hashed version of a user-provided password to store in a database for authentication purposes.
For users of older .NET frameworks, this is still useful:
// NOTE: The iteration count should
// be as high as possible without causing
// unreasonable delay. Note also that the password
// and salt are byte arrays, not strings. After use,
// the password and salt should be cleared (with Array.Clear)
public static byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount){
using(var hmac=new System.Security.Cryptography.HMACSHA256(password)){
int hashLength=hmac.HashSize/8;
if((hmac.HashSize&7)!=0)
hashLength++;
int keyLength=dklen/hashLength;
if((long)dklen>(0xFFFFFFFFL*hashLength) || dklen<0)
throw new ArgumentOutOfRangeException("dklen");
if(dklen%hashLength!=0)
keyLength++;
byte[] extendedkey=new byte[salt.Length+4];
Buffer.BlockCopy(salt,0,extendedkey,0,salt.Length);
using(var ms=new System.IO.MemoryStream()){
for(int i=0;i<keyLength;i++){
extendedkey[salt.Length]=(byte)(((i+1)>>24)&0xFF);
extendedkey[salt.Length+1]=(byte)(((i+1)>>16)&0xFF);
extendedkey[salt.Length+2]=(byte)(((i+1)>>8)&0xFF);
extendedkey[salt.Length+3]=(byte)(((i+1))&0xFF);
byte[] u=hmac.ComputeHash(extendedkey);
Array.Clear(extendedkey,salt.Length,4);
byte[] f=u;
for(int j=1;j<iterationCount;j++){
u=hmac.ComputeHash(u);
for(int k=0;k<f.Length;k++){
f[k]^=u[k];
}
}
ms.Write(f,0,f.Length);
Array.Clear(u,0,u.Length);
Array.Clear(f,0,f.Length);
}
byte[] dk=new byte[dklen];
ms.Position=0;
ms.Read(dk,0,dklen);
ms.Position=0;
for(long i=0;i<ms.Length;i++){
ms.WriteByte(0);
}
Array.Clear(extendedkey,0,extendedkey.Length);
return dk;
}
}
The BCL Rfc2898DeriveBytes is hardcoded to use sha-1.
KeyDerivation.Pbkdf2 allows for exactly the same output, but it also allows HMAC SHA-256 and HMAC SHA-512. It's faster too; on my machine by around 5 times - and that's good for security, because it allows for more rounds, which makes life for crackers harder (incidentally sha-512 is a lot less gpu-friendly than sha-256 or sha1). And the api is simpler, to boot:
byte[] salt = ...
string password = ...
var rounds = 50000; // pick something bearable
var num_bytes_requested = 16; // 128 bits is fine
var prf = KeyDerivationPrf.HMACSHA512; // or sha256, or sha1
byte[] hashed = KeyDerivation.Pbkdf2(password, salt, prf, rounds, num_bytes_requested);
It's from the nuget package Microsoft.AspNetCore.Cryptography.KeyDerivation which does not depend on asp.net core; it runs on .net 4.5.1 or .net standard 1.3 or higher.
You could use Bouncy Castle. The C# specification lists the algorithm "PBEwithHmacSHA-256", which can only be PBKDF2 with SHA-256.
I know this is an old question, but for anyone that comes across it, you can now use KeyDerivation.Pbkdf2 from the Microsoft.AspNetCore.Cryptography.KeyDerivation nuget package. It is what is used in asp.net core.
Unfortunately it will add a ton of references that aren't really needed. You could just copy the code and paste it into your own project (although you will now have to maintain cryto code which is a PITA)
For what it's worth, here's a copy of Microsoft's implementation but with SHA-1 replaced with SHA512:
namespace System.Security.Cryptography
{
using System.Globalization;
using System.IO;
using System.Text;
[System.Runtime.InteropServices.ComVisible(true)]
public class Rfc2898DeriveBytes_HMACSHA512 : DeriveBytes
{
private byte[] m_buffer;
private byte[] m_salt;
private HMACSHA512 m_HMACSHA512; // The pseudo-random generator function used in PBKDF2
private uint m_iterations;
private uint m_block;
private int m_startIndex;
private int m_endIndex;
private static RNGCryptoServiceProvider _rng;
private static RNGCryptoServiceProvider StaticRandomNumberGenerator
{
get
{
if (_rng == null)
{
_rng = new RNGCryptoServiceProvider();
}
return _rng;
}
}
private const int BlockSize = 20;
//
// public constructors
//
public Rfc2898DeriveBytes_HMACSHA512(string password, int saltSize) : this(password, saltSize, 1000) { }
public Rfc2898DeriveBytes_HMACSHA512(string password, int saltSize, int iterations)
{
if (saltSize < 0)
throw new ArgumentOutOfRangeException("saltSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
byte[] salt = new byte[saltSize];
StaticRandomNumberGenerator.GetBytes(salt);
Salt = salt;
IterationCount = iterations;
m_HMACSHA512 = new HMACSHA512(new UTF8Encoding(false).GetBytes(password));
Initialize();
}
public Rfc2898DeriveBytes_HMACSHA512(string password, byte[] salt) : this(password, salt, 1000) { }
public Rfc2898DeriveBytes_HMACSHA512(string password, byte[] salt, int iterations) : this(new UTF8Encoding(false).GetBytes(password), salt, iterations) { }
public Rfc2898DeriveBytes_HMACSHA512(byte[] password, byte[] salt, int iterations)
{
Salt = salt;
IterationCount = iterations;
m_HMACSHA512 = new HMACSHA512(password);
Initialize();
}
//
// public properties
//
public int IterationCount
{
get { return (int)m_iterations; }
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
m_iterations = (uint)value;
Initialize();
}
}
public byte[] Salt
{
get { return (byte[])m_salt.Clone(); }
set
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length < 8)
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Cryptography_PasswordDerivedBytes_FewBytesSalt")));
m_salt = (byte[])value.Clone();
Initialize();
}
}
//
// public methods
//
public override byte[] GetBytes(int cb)
{
if (cb <= 0)
throw new ArgumentOutOfRangeException("cb", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
byte[] password = new byte[cb];
int offset = 0;
int size = m_endIndex - m_startIndex;
if (size > 0)
{
if (cb >= size)
{
Buffer.InternalBlockCopy(m_buffer, m_startIndex, password, 0, size);
m_startIndex = m_endIndex = 0;
offset += size;
}
else
{
Buffer.InternalBlockCopy(m_buffer, m_startIndex, password, 0, cb);
m_startIndex += cb;
return password;
}
}
//BCLDebug.Assert(m_startIndex == 0 && m_endIndex == 0, "Invalid start or end index in the internal buffer.");
while (offset < cb)
{
byte[] T_block = Func();
int remainder = cb - offset;
if (remainder > BlockSize)
{
Buffer.InternalBlockCopy(T_block, 0, password, offset, BlockSize);
offset += BlockSize;
}
else
{
Buffer.InternalBlockCopy(T_block, 0, password, offset, remainder);
offset += remainder;
Buffer.InternalBlockCopy(T_block, remainder, m_buffer, m_startIndex, BlockSize - remainder);
m_endIndex += (BlockSize - remainder);
return password;
}
}
return password;
}
public override void Reset()
{
Initialize();
}
private void Initialize()
{
if (m_buffer != null)
Array.Clear(m_buffer, 0, m_buffer.Length);
m_buffer = new byte[BlockSize];
m_block = 1;
m_startIndex = m_endIndex = 0;
}
internal static byte[] Int(uint i)
{
byte[] b = BitConverter.GetBytes(i);
byte[] littleEndianBytes = { b[3], b[2], b[1], b[0] };
return BitConverter.IsLittleEndian ? littleEndianBytes : b;
}
// This function is defined as follow :
// Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i)
// where i is the block number.
private byte[] Func()
{
byte[] INT_block = Int(m_block);
m_HMACSHA512.TransformBlock(m_salt, 0, m_salt.Length, m_salt, 0);
m_HMACSHA512.TransformFinalBlock(INT_block, 0, INT_block.Length);
byte[] temp = m_HMACSHA512.Hash;
m_HMACSHA512.Initialize();
byte[] ret = temp;
for (int i = 2; i <= m_iterations; i++)
{
temp = m_HMACSHA512.ComputeHash(temp);
for (int j = 0; j < BlockSize; j++)
{
ret[j] ^= temp[j];
}
}
// increment the block count.
m_block++;
return ret;
}
}
}
In addition to replacing HMACSHA1 with HMACSHA512, you need to add a StaticRandomNumberGenerator property because Utils.StaticRandomNumberGenerator is internal in the microsoft assembly, and you need to add the static byte[] Int(uint i) method because microsoft's Utils.Int is also internal. Other than that, the code works.
Although this is an old question, since I added reference to this question in my Question Configurable Rfc2898DeriveBytes where I asked whether a generic implementation of the Rfc2898DeriveBytes algorithm was correct.
I have now tested and validated that it generates the exact same hash values if HMACSHA1 is provided for TAlgorithm as the .NET implementation of Rfc2898DeriveBytes
In order to use the class, one must provide the constructor for the HMAC algorithm requiring a byte array as the first argument.
e.g.:
var rfcGenSha1 = new Rfc2898DeriveBytes<HMACSHA1>(b => new HMACSHA1(b), key, ...)
var rfcGenSha256 = new Rfc2898DeriveBytes<HMACSHA256>(b => new HMACSHA256(b), key, ...)
This requires the algorithm to inherit HMAC at this point, I'm believe one might be able to Reduce the restriction to require inheritance from KeyedHashAlgorithm instead of HMAC, as long as the constructor of the algorithm accepts an array of bytes to the constructor.

Categories

Resources