Skip to content

Instantly share code, notes, and snippets.

@amrishodiq
Created January 16, 2012 20:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save amrishodiq/1622737 to your computer and use it in GitHub Desktop.
Save amrishodiq/1622737 to your computer and use it in GitHub Desktop.
Triple DES encryption and MD5 for Windows Phone 7 with C#
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text;
namespace PhoneApp1
{
public class CryptoUtilities
{
public static string GetMD5Hash(string input)
{
byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
MD5Managed md5 = new MD5Managed();
byte[] hash = md5.ComputeHash(bs);
StringBuilder sb = new StringBuilder();
foreach (byte b in hash)
{
sb.Append(b.ToString("x2").ToLower());
}
return sb.ToString();
}
private static System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
public static string EncryptString(string Value, string KeyString)
{
byte[] Key = DurianBerryProducts.DESCrytography.DoPadWithString(encoding.GetBytes(KeyString), 24, (byte)0);
byte[] plainText = new byte[1024];
plainText = DurianBerryProducts.DESCrytography.DoPadWithString(encoding.GetBytes(Value), 8, (byte)0);
byte[] cipherText = null;
DurianBerryProducts.DESCrytography.TripleDES(plainText, ref cipherText, Key, true);
string result = Convert.ToBase64String(cipherText);
result = result.Replace("+", "-").Replace("/", "_");
return result;
}
public static string DecryptString(string Value, string KeyString)
{
byte[] Key = DurianBerryProducts.DESCrytography.DoPadWithString(encoding.GetBytes(KeyString), 24, (byte)0);
byte[] plainText = Convert.FromBase64String(Value.Replace("-", "+").Replace("_", "/"));
byte[] cipherText = null;
DurianBerryProducts.DESCrytography.TripleDES(plainText, ref cipherText, Key, false);
string result = encoding.GetString(cipherText, 0, cipherText.Length).Replace(Convert.ToChar(0x0).ToString(), "");
return result;
}
}
}
using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
/// <summary>
/// I picked this class from somewhere named BroccoliProducts. It's a good class indeed,
/// but I found this class did not support my requirements to use TripleDES with ECB mode,
/// no padding (or padding with null). So I make some changes.
/// </summary>
namespace DurianBerryProducts
{
/// <summary>
/// Declaration of DESCrytography class
/// </summary>
public static class DESCrytography
{
/////////////////////////////////////////////////////////////
// Nested classes
/// <summary>
/// Declaration of BLOCK8BYTE class
/// </summary>
internal class BLOCK8BYTE
{
/////////////////////////////////////////////////////////
// Constants
public const int BYTE_LENGTH = 8;
/////////////////////////////////////////////////////////
// Attributes
internal byte[] m_data = new byte[BYTE_LENGTH];
/////////////////////////////////////////////////////////
// Operations
public void Reset()
{
// Reset bytes
Array.Clear(m_data, 0, BYTE_LENGTH);
}
public void Set(BLOCK8BYTE Source)
{
// Copy source data to this
this.Set(Source.m_data, 0);
}
public void Set(byte[] buffer, int iOffset)
{
// Set contents by copying array
Array.Copy(buffer, iOffset, m_data, 0, BYTE_LENGTH);
}
public void Xor(BLOCK8BYTE A, BLOCK8BYTE B)
{
// Set byte to A ^ B
for (int iOffset = 0; iOffset < BYTE_LENGTH; iOffset++)
m_data[iOffset] = Convert.ToByte(A.m_data[iOffset] ^ B.m_data[iOffset]);
}
public void SetBit(int iByteOffset, int iBitOffset, bool bFlag)
{
// Compose mask
byte mask = Convert.ToByte(1 << iBitOffset);
if (((m_data[iByteOffset] & mask) == mask) != bFlag)
m_data[iByteOffset] ^= mask;
}
public bool GetBit(int iByteOffset, int iBitOffset)
{
// call sibling function
return ((this.m_data[iByteOffset] >> iBitOffset) & 0x01) == 0x01;
}
public void ShiftLeftWrapped(BLOCK8BYTE S, int iBitShift)
{
// this shift is only applied to the first 32 bits, and parity bit is ignored
// Declaration of local variables
int iByteOffset = 0;
bool bBit = false;
// Copy byte and shift regardless
for (iByteOffset = 0; iByteOffset < 4; iByteOffset++)
m_data[iByteOffset] = Convert.ToByte((S.m_data[iByteOffset] << iBitShift) & 0xFF);
// if shifting by 1...
if (iBitShift == 1)
{
// repair bits on right of BYTE
for (iByteOffset = 0; iByteOffset < 3; iByteOffset++)
{
// get repairing bit offsets
bBit = S.GetBit(iByteOffset + 1, 7);
this.SetBit(iByteOffset, 1, bBit);
}
// wrap around the final bit
this.SetBit(3, 1, S.GetBit(0, 7));
}
else if (iBitShift == 2)
{
// repair bits on right of BYTE
for (iByteOffset = 0; iByteOffset < 3; iByteOffset++)
{
// get repairing bit offsets
bBit = S.GetBit(iByteOffset + 1, 7);
this.SetBit(iByteOffset, 2, bBit);
bBit = S.GetBit(iByteOffset + 1, 6);
this.SetBit(iByteOffset, 1, bBit);
}
// wrap around the final bit
this.SetBit(3, 2, S.GetBit(0, 7));
this.SetBit(3, 1, S.GetBit(0, 6));
}
#if DEBUG
else
Debug.Assert(false);
#endif // #if DEBUG
}
}
/// <summary>
/// Declaration of KEY_SET class
/// </summary>
internal class KEY_SET
{
/////////////////////////////////////////////////////////
// Constants
public const int KEY_COUNT = 17;
/////////////////////////////////////////////////////////
// Attributes
internal BLOCK8BYTE[] m_array;
/////////////////////////////////////////////////////////
// Construction
internal KEY_SET()
{
// Create array
m_array = new BLOCK8BYTE[KEY_COUNT];
for (int i1 = 0; i1 < KEY_COUNT; i1++)
m_array[i1] = new BLOCK8BYTE();
}
/////////////////////////////////////////////////////////
// Operations
public BLOCK8BYTE GetAt(int iArrayOffset)
{
return m_array[iArrayOffset];
}
}
/// <summary>
/// Declaration of WORKING_SET class
/// </summary>
internal class WORKING_SET
{
/////////////////////////////////////////////////////////
// Attributes
internal BLOCK8BYTE IP = new BLOCK8BYTE();
internal BLOCK8BYTE[] Ln = new BLOCK8BYTE[17];
internal BLOCK8BYTE[] Rn = new BLOCK8BYTE[17];
internal BLOCK8BYTE RnExpand = new BLOCK8BYTE();
internal BLOCK8BYTE XorBlock = new BLOCK8BYTE();
internal BLOCK8BYTE SBoxValues = new BLOCK8BYTE();
internal BLOCK8BYTE f = new BLOCK8BYTE();
internal BLOCK8BYTE X = new BLOCK8BYTE();
internal BLOCK8BYTE DataBlockIn = new BLOCK8BYTE();
internal BLOCK8BYTE DataBlockOut = new BLOCK8BYTE();
internal BLOCK8BYTE DecryptXorBlock = new BLOCK8BYTE();
/////////////////////////////////////////////////////////
// Construction
internal WORKING_SET()
{
// Build the arrays
for (int i1 = 0; i1 < 17; i1++)
{
Ln[i1] = new BLOCK8BYTE();
Rn[i1] = new BLOCK8BYTE();
}
}
/////////////////////////////////////////////////////////
// Operations
internal void Scrub()
{
// Scrub data
IP.Reset();
for (int i1 = 0; i1 < 17; i1++)
{
Ln[i1].Reset();
Rn[i1].Reset();
}
RnExpand.Reset();
XorBlock.Reset();
SBoxValues.Reset();
f.Reset();
X.Reset();
DataBlockIn.Reset();
DataBlockOut.Reset();
DecryptXorBlock.Reset();
}
}
/////////////////////////////////////////////////////////////
// Constants
public const int KEY_BYTE_LENGTH = 8;
public const int BITS_PER_BYTE = 8;
/////////////////////////////////////////////////////////////
#region DES Tables
/* PERMUTED CHOICE 1 (PCl) */
private static byte[] bytePC1 = {
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4,
};
/* PERMUTED CHOICE 2 (PC2) */
private static byte[] bytePC2 = {
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32,
};
/* INITIAL PERMUTATION (IP) */
private static byte[] byteIP = {
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
};
/* REVERSE FINAL PERMUTATION (IP-1) */
private static byte[] byteRFP = {
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25,
};
/* E BIT-SELECTION TABLE */
private static byte[] byteE = {
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1
};
/* PERMUTATION FUNCTION P */
private static byte[] byteP = {
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
};
// Schedule of left shifts for C and D blocks
private static byte[] byteShifts = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
// S-Boxes
private static byte[,] byteSBox = new byte[,] {
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8,15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
{12, 1, 10, 15, 9, 2, 6, 8,0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5,6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3,7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10,11, 14, 1, 7, 6, 0, 8, 13},
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10,14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14,10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7,9, 5, 0, 15, 14, 2, 3, 12},
{13, 2, 8, 4, 6, 15, 11, 1,10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2,0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13,15, 12, 9, 0, 3, 5, 6, 11}
};
#endregion DES Tables
/////////////////////////////////////////////////////////////
#region Static Operations - DES
public static bool IsValidDESKey(byte[] Key)
{
// Shortcuts
if (Key == null)
return false;
if (Key.Length != KEY_BYTE_LENGTH)
return false;
if (!IsStrongDESKey(Key))
return false;
// Make sure end bits have odd parity
for (int iByteOffset = 0; iByteOffset < KEY_BYTE_LENGTH; iByteOffset++)
{
// Add bits for this byte
int iTotalBits = 0;
byte Mask = 1;
for (int iBitOffset = 0; iBitOffset < BITS_PER_BYTE; iBitOffset++)
{
if ((Key[iByteOffset] & Mask) != 0)
iTotalBits++;
Mask <<= 1;
}
// If the total bits is not odd...
if ((iTotalBits % 2) != 1)
return false;
}
// Return success
return true;
}
public static bool IsStrongDESKey(byte[] Key)
{
// Compare by large integer
UInt64 uiKey = BitConverter.ToUInt64(Key, 0);
// Find weak keys...
if (
(uiKey == 0x0000000000000000) ||
(uiKey == 0x00000000FFFFFFFF) ||
(uiKey == 0xE0E0E0E0F1F1F1F1) ||
(uiKey == 0x1F1F1F1F0E0E0E0E)
)
return false;
// Find semi-weak keys...
if (
(uiKey == 0x011F011F010E010E) ||
(uiKey == 0x1F011F010E010E01) ||
(uiKey == 0x01E001E001F101F1) ||
(uiKey == 0xE001E001F101F101) ||
(uiKey == 0x01FE01FE01FE01FE) ||
(uiKey == 0xFE01FE01FE01FE01) ||
(uiKey == 0x1FE01FE00EF10EF1) ||
(uiKey == 0xE01FE01FF10EF10E) ||
(uiKey == 0x1FFE1FFE0EFE0EFE) ||
(uiKey == 0xFE1FFE1FFE0EFE0E) ||
(uiKey == 0xE0FEE0FEF1FEF1FE) ||
(uiKey == 0xFEE0FEE0FEF1FEF1)
)
return false;
// Return success
return true;
}
/// <summary>
/// I put this method because I need to implement padding mechanism that uses byte 0 as padding.
/// This is not available by default.
/// </summary>
/// <param name="Input"></param>
/// <param name="PadLength"></param>
/// <param name="Padding"></param>
/// <returns></returns>
public static byte[] DoPadWithString(byte[] Input, int PadLength, byte Padding)
{
int slen = Input.Length;
int i = PadLength - (Input.Length % PadLength);
Debug.WriteLine("SLEN: "+slen);
Debug.WriteLine("I: " + i);
Debug.WriteLine("I: " + (i % PadLength));
Debug.WriteLine("PadLength: " + PadLength);
if ((i > 0) && (i % PadLength < PadLength))
{
Debug.WriteLine("Masuk IF, pad length: "+PadLength);
byte[] res = new byte[((Input.Length / PadLength)+1) * PadLength];
Array.Copy(Input, 0, res, 0, slen);
//slen = Input.Length % PadLength;
Debug.WriteLine("SLEN: " + slen);
//for (i = Input.Length + slen; i < PadLength; i++)
while (slen % PadLength > 0)
{
Debug.WriteLine("+ SLEN: " + slen);
res[slen] = Padding;
slen++;
}
Debug.WriteLine("RES: " + res+"; LENGTH: "+res.Length);
Input = res;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
Debug.WriteLine("Res: " + encoding.GetString(Input, 0, Input.Length));
return Input;
}
else return Input;
}
public static void DES(byte[] bufferIn, ref byte[] bufferOut, byte[] Key, bool bEncrypt)
{
// Shortcuts
if (!IsValidDESKey(Key))
throw new Exception("Invalid DES key.");
// Create the output buffer
_createBufferOut(bufferIn.Length, ref bufferOut, bEncrypt);
// Expand the keys into Kn
KEY_SET[] Kn = new KEY_SET[1] {
_expandKey(Key, 0)
};
// Apply DES keys
_desAlgorithm(bufferIn, ref bufferOut, Kn, bEncrypt);
// If decrypting...
if (!bEncrypt)
_removePadding(ref bufferOut);
}
#endregion Static Operations - DES
/////////////////////////////////////////////////////////////
#region Static Operations - TripleDES
/// <summary>
/// Sorry, I commented some lines to match my requirement. I don't need to check
/// wether there are any same sub keys or not.
/// </summary>
/// <param name="Key"></param>
/// <returns></returns>
public static bool IsValidTripleDESKey(byte[] Key)
{
// Shortcuts
if (Key == null)
return false;
if (Key.Length != (3 * KEY_BYTE_LENGTH))
return false;
// Check each part of the key
/*
byte[] SubKey = new byte[KEY_BYTE_LENGTH];
for (int iKeyLoop = 0; iKeyLoop < 3; iKeyLoop++)
{
// Get sub-key
Array.Copy(Key, iKeyLoop * 8, SubKey, 0, KEY_BYTE_LENGTH);
// Check this DES key
if (!IsValidDESKey(SubKey))
return false;
}
// Keys must not be equal
/*
bool bAEqualsB = true;
bool bAEqualsC = true;
bool bBEqualsC = true;
for (int iByteOffset = 0; iByteOffset < KEY_BYTE_LENGTH; iByteOffset++)
{
if (Key[iByteOffset] != Key[iByteOffset + KEY_BYTE_LENGTH])
bAEqualsB = false;
if (Key[iByteOffset] != Key[iByteOffset + KEY_BYTE_LENGTH + KEY_BYTE_LENGTH])
bAEqualsC = false;
if (Key[iByteOffset + KEY_BYTE_LENGTH] != Key[iByteOffset + KEY_BYTE_LENGTH + KEY_BYTE_LENGTH])
bBEqualsC = false;
}
if ((bAEqualsB) || (bAEqualsC) || (bBEqualsC))
return false;
*/
// Return success
return true;
}
/// <summary>
/// Sorry, I need to comment _removePadding because I implement my own padding mechanism. So I don't need the original remove padding.
/// </summary>
/// <param name="bufferIn"></param>
/// <param name="bufferOut"></param>
/// <param name="Key"></param>
/// <param name="bEncrypt"></param>
public static void TripleDES(byte[] bufferIn, ref byte[] bufferOut, byte[] Key, bool bEncrypt)
{
// Shortcuts
if (!IsValidTripleDESKey(Key))
throw new Exception("Invalid DES key.");
// Create the output buffer
_createBufferOut(bufferIn.Length, ref bufferOut, bEncrypt);
// Expand the keys into Kn
KEY_SET[] Kn = new KEY_SET[3] {
_expandKey(Key, 0),
_expandKey(Key, 8),
_expandKey(Key, 16)
};
// Apply DES keys
_desAlgorithm(bufferIn, ref bufferOut, Kn, bEncrypt);
// If decrypting...
//if (!bEncrypt)
// _removePadding(ref bufferOut);
}
#endregion Static Operations - TripleDES
/////////////////////////////////////////////////////////////
#region Static Operations
private static void _incKey(byte[] Key, int iInc)
{
#if DEBUG
Debug.Assert(Key.Length == KEY_BYTE_LENGTH);
#endif // #if DEBUG
// shortcuts
if (iInc == 0)
return;
// Add the increment
int iCarry = iInc;
for (int iByteOffset = 0; iByteOffset < KEY_BYTE_LENGTH; iByteOffset++)
{
int iTemp = Key[iByteOffset] + iCarry;
iCarry = iTemp >> 8;
Key[iByteOffset] = Convert.ToByte(iTemp & 0xFF);
if (iCarry == 0)
break;
}
}
private static void _modifyKeyParity(byte[] Key)
{
#if DEBUG
Debug.Assert(Key.Length == KEY_BYTE_LENGTH);
#endif // #if DEBUG
// Make sure end bits have odd parity
for (int iByteOffset = 0; iByteOffset < KEY_BYTE_LENGTH; iByteOffset++)
{
// Add bits for this byte
int iTotalBits = 0;
byte Mask = 1;
for (int iBitOffset = 0; iBitOffset < BITS_PER_BYTE; iBitOffset++)
{
if ((Key[iByteOffset] & Mask) != 0)
iTotalBits++;
Mask <<= 1;
}
// If the total bits is not odd...
if ((iTotalBits % 2) != 1)
{
// Flip the first bit to retain odd parity
Key[iByteOffset] ^= 0x01;
}
}
}
private static KEY_SET _expandKey(byte[] Key, int iOffset)
{
//
// Expand an 8 byte DES key into a set of permuted keys
//
// Declare return variable
KEY_SET Ftmp = new KEY_SET();
// Declaration of local variables
int iTableOffset, iArrayOffset, iPermOffset, iByteOffset, iBitOffset;
bool bBit;
// Put key into an 8-bit block
BLOCK8BYTE K = new BLOCK8BYTE();
K.Set(Key, iOffset);
// Permutate Kp with PC1
BLOCK8BYTE Kp = new BLOCK8BYTE();
for (iArrayOffset = 0; iArrayOffset < bytePC1.Length; iArrayOffset++)
{
// Get permute offset
iPermOffset = bytePC1[iArrayOffset];
iPermOffset--;
// Get and set bit
Kp.SetBit(
_bitAddressToByteOffset(iArrayOffset, 7),
_bitAddressToBitOffset(iArrayOffset, 7),
K.GetBit(
_bitAddressToByteOffset(iPermOffset, 8),
_bitAddressToBitOffset(iPermOffset, 8)
)
);
}
// Create 17 blocks of C and D from Kp
BLOCK8BYTE[] KpCn = new BLOCK8BYTE[17];
BLOCK8BYTE[] KpDn = new BLOCK8BYTE[17];
for (iArrayOffset = 0; iArrayOffset < 17; iArrayOffset++)
{
KpCn[iArrayOffset] = new BLOCK8BYTE();
KpDn[iArrayOffset] = new BLOCK8BYTE();
}
for (iArrayOffset = 0; iArrayOffset < 32; iArrayOffset++)
{
// Set bit in KpCn
iByteOffset = _bitAddressToByteOffset(iArrayOffset, 8);
iBitOffset = _bitAddressToBitOffset(iArrayOffset, 8);
bBit = Kp.GetBit(iByteOffset, iBitOffset);
KpCn[0].SetBit(iByteOffset, iBitOffset, bBit);
// Set bit in KpDn
bBit = Kp.GetBit(iByteOffset + 4, iBitOffset);
KpDn[0].SetBit(iByteOffset, iBitOffset, bBit);
}
for (iArrayOffset = 1; iArrayOffset < 17; iArrayOffset++)
{
// Shift left wrapped
KpCn[iArrayOffset].ShiftLeftWrapped(KpCn[iArrayOffset - 1], byteShifts[iArrayOffset - 1]);
KpDn[iArrayOffset].ShiftLeftWrapped(KpDn[iArrayOffset - 1], byteShifts[iArrayOffset - 1]);
}
// Create 17 keys Kn
for (iArrayOffset = 0; iArrayOffset < 17; iArrayOffset++)
{
// Loop through the bits
for (iTableOffset = 0; iTableOffset < 48; iTableOffset++)
{
// Get address if bit
iPermOffset = bytePC2[iTableOffset];
iPermOffset--;
// Convert to byte and bit offsets
iByteOffset = _bitAddressToByteOffset(iPermOffset, 7);
iBitOffset = _bitAddressToBitOffset(iPermOffset, 7);
// Get bit
if (iByteOffset < 4)
bBit = KpCn[iArrayOffset].GetBit(iByteOffset, iBitOffset);
else
bBit = KpDn[iArrayOffset].GetBit(iByteOffset - 4, iBitOffset);
// Set bit
iByteOffset = _bitAddressToByteOffset(iTableOffset, 6);
iBitOffset = _bitAddressToBitOffset(iTableOffset, 6);
Ftmp.GetAt(iArrayOffset).SetBit(iByteOffset, iBitOffset, bBit);
}
}
// Return variable
return Ftmp;
}
private static void _createBufferOut(int iBufferInLength, ref byte[] bufferOut, bool bEncrypt)
{
//
// Create a buffer for the output, which may be trimmed later
//
// If encrypting...
int iOutputLength;
if (bEncrypt)
{
if ((iBufferInLength % KEY_BYTE_LENGTH) != 0)
{
iOutputLength = ((iBufferInLength / KEY_BYTE_LENGTH) + 1) * KEY_BYTE_LENGTH;
//iOutputLength = ((iBufferInLength / KEY_BYTE_LENGTH)) * KEY_BYTE_LENGTH;
}
else
{
//iOutputLength = iBufferInLength + KEY_BYTE_LENGTH;
iOutputLength = iBufferInLength;
}
}
else
{
if (iBufferInLength < 8)
throw new Exception("DES cypher-text must be at least 8 bytes.");
if ((iBufferInLength % 8) != 0)
throw new Exception("DES cypher-text must be a factor of 8 bytes in length.");
iOutputLength = iBufferInLength;
}
// Create buffer
if ((bufferOut == null) || (bufferOut.Length != iOutputLength))
bufferOut = new byte[iOutputLength];
else
Array.Clear(bufferOut, 0, bufferOut.Length);
}
private static void _removePadding(ref byte[] bufferOut)
{
//
// Remove the padding after decrypting
//
// Get the padding...
byte Padding = bufferOut[bufferOut.Length - 1];
if ((Padding == 0) || (Padding > 8))
throw new Exception("Invalid padding on DES data.");
// Confirm padding
bool bPaddingOk = true;
for (int iByteOffset = 1; iByteOffset < Padding; iByteOffset++)
{
if (bufferOut[bufferOut.Length - 1 - iByteOffset] != Padding)
{
bPaddingOk = false;
break;
}
}
if (bPaddingOk)
{
// Chop off the padding
Array.Resize(ref bufferOut, bufferOut.Length - Padding);
}
else
throw new Exception("Invalid padding on DES data.");
}
private static void _desAlgorithm(byte[] bufferIn, ref byte[] bufferOut, KEY_SET[] KeySets, bool bEncrypt)
{
//
// Apply the DES algorithm to each block
//
// Declare a workset set of variables
WORKING_SET workingSet = new WORKING_SET();
// encode/decode blocks
int iBufferPos = 0;
while (true)
{
// Check buffer position
if (bEncrypt)
{
// If end of buffer...
if (iBufferPos >= bufferOut.Length)
break;
// Calulate remaining bytes
int iRemainder = (bufferIn.Length - iBufferPos);
if (iRemainder >= 8)
workingSet.DataBlockIn.Set(bufferIn, iBufferPos);
else
{
// Copy part-block
workingSet.DataBlockIn.Reset();
if (iRemainder > 0)
Array.Copy(bufferIn, iBufferPos, workingSet.DataBlockIn.m_data, 0, iRemainder);
// Get the padding byte
byte Padding = Convert.ToByte(KEY_BYTE_LENGTH - iRemainder);
// Add padding to block
for (int iByteOffset = iRemainder; iByteOffset < KEY_BYTE_LENGTH; iByteOffset++)
workingSet.DataBlockIn.m_data[iByteOffset] = Padding;
}
}
else
{
// If end of buffer...
if (iBufferPos >= bufferIn.Length)
break;
// Get the next block
workingSet.DataBlockIn.Set(bufferIn, iBufferPos);
}
// if encrypting and not the first block...
if ((bEncrypt) && (iBufferPos > 0))
{
// Amri commented these lines since Amri need EBC, not CBC
// Apply succession => XOR M with previous block
//workingSet.DataBlockIn.Xor(workingSet.DataBlockOut, workingSet.DataBlockIn);
}
// Apply the algorithm
workingSet.DataBlockOut.Set(workingSet.DataBlockIn);
_lowLevel_desAlgorithm(workingSet, KeySets, bEncrypt);
// If decrypting...
if (!bEncrypt)
{
// Amri commented these lines since Amri need EBC, not CBC
// Retain the succession
//if (iBufferPos > 0)
// workingSet.DataBlockOut.Xor(workingSet.DecryptXorBlock, workingSet.DataBlockOut);
// Retain the last block
workingSet.DecryptXorBlock.Set(workingSet.DataBlockIn);
}
// Update buffer out
Array.Copy(workingSet.DataBlockOut.m_data, 0, bufferOut, iBufferPos, 8);
// Move on
iBufferPos += 8;
}
// Scrub the working set
workingSet.Scrub();
}
private static void _lowLevel_desAlgorithm(WORKING_SET workingSet, KEY_SET[] KeySets, bool bEncrypt)
{
//
// Apply 1 or 3 keys to a block of data
//
// Declaration of local variables
int iTableOffset;
int iArrayOffset;
int iPermOffset;
int iByteOffset;
int iBitOffset;
// Loop through keys
for (int iKeySetOffset = 0; iKeySetOffset < KeySets.Length; iKeySetOffset++)
{
// Permute with byteIP
workingSet.IP.Reset();
for (iTableOffset = 0; iTableOffset < byteIP.Length; iTableOffset++)
{
// Get perm offset
iPermOffset = byteIP[iTableOffset];
iPermOffset--;
// Get and set bit
workingSet.IP.SetBit(
_bitAddressToByteOffset(iTableOffset, 8),
_bitAddressToBitOffset(iTableOffset, 8),
workingSet.DataBlockOut.GetBit(
_bitAddressToByteOffset(iPermOffset, 8),
_bitAddressToBitOffset(iPermOffset, 8)
)
);
}
// Create Ln[0] and Rn[0]
workingSet.Ln[0].Reset();
workingSet.Rn[0].Reset();
for (iArrayOffset = 0; iArrayOffset < 32; iArrayOffset++)
{
iByteOffset = _bitAddressToByteOffset(iArrayOffset, 8);
iBitOffset = _bitAddressToBitOffset(iArrayOffset, 8);
workingSet.Ln[0].SetBit(iByteOffset, iBitOffset, workingSet.IP.GetBit(iByteOffset, iBitOffset));
workingSet.Rn[0].SetBit(iByteOffset, iBitOffset, workingSet.IP.GetBit(iByteOffset + 4, iBitOffset));
}
// Loop through 17 interations
for (int iBlockOffset = 1; iBlockOffset < 17; iBlockOffset++)
{
// Get the array offset
int iKeyOffset;
if (bEncrypt != (iKeySetOffset == 1))
iKeyOffset = iBlockOffset;
else
iKeyOffset = 17 - iBlockOffset;
// Set Ln[N] = Rn[N-1]
workingSet.Ln[iBlockOffset].Set(workingSet.Rn[iBlockOffset - 1]);
// Set Rn[N] = Ln[0] + f(R[N-1],K[N])
for (iTableOffset = 0; iTableOffset < byteE.Length; iTableOffset++)
{
// Get perm offset
iPermOffset = byteE[iTableOffset];
iPermOffset--;
// Get and set bit
workingSet.RnExpand.SetBit(
_bitAddressToByteOffset(iTableOffset, 6),
_bitAddressToBitOffset(iTableOffset, 6),
workingSet.Rn[iBlockOffset - 1].GetBit(
_bitAddressToByteOffset(iPermOffset, 8),
_bitAddressToBitOffset(iPermOffset, 8)
)
);
}
// XOR expanded block with K-block
if (bEncrypt != (iKeySetOffset == 1))
workingSet.XorBlock.Xor(workingSet.RnExpand, KeySets[iKeySetOffset].GetAt(iKeyOffset));
else
workingSet.XorBlock.Xor(workingSet.RnExpand, KeySets[KeySets.Length - 1 - iKeySetOffset].GetAt(iKeyOffset));
// Set S-Box values
workingSet.SBoxValues.Reset();
for (iTableOffset = 0; iTableOffset < 8; iTableOffset++)
{
// Calculate m and n
int m = ((workingSet.XorBlock.GetBit(iTableOffset, 7) ? 1 : 0) << 1) | (workingSet.XorBlock.GetBit(iTableOffset, 2) ? 1 : 0);
int n = (workingSet.XorBlock.m_data[iTableOffset] >> 3) & 0x0F;
// Get s-box value
iPermOffset = byteSBox[(iTableOffset * 4) + m, n];
workingSet.SBoxValues.m_data[iTableOffset] = (byte)(iPermOffset << 4);
}
// Permute with P -> f
workingSet.f.Reset();
for (iTableOffset = 0; iTableOffset < byteP.Length; iTableOffset++)
{
// Get perm offset
iPermOffset = byteP[iTableOffset];
iPermOffset--;
// Get and set bit
workingSet.f.SetBit(
_bitAddressToByteOffset(iTableOffset, 4),
_bitAddressToBitOffset(iTableOffset, 4),
workingSet.SBoxValues.GetBit(
_bitAddressToByteOffset(iPermOffset, 4),
_bitAddressToBitOffset(iPermOffset, 4)
)
);
}
// Rn[N] = Ln[N-1] ^ f
workingSet.Rn[iBlockOffset].Reset();
for (iTableOffset = 0; iTableOffset < 8; iTableOffset++)
{
// Get Ln[N-1] -> A
byte A = workingSet.Ln[iBlockOffset - 1].m_data[(iTableOffset >> 1)];
if ((iTableOffset % 2) == 0)
A >>= 4;
else
A &= 0x0F;
// Get f -> B
byte B = Convert.ToByte(workingSet.f.m_data[iTableOffset] >> 4);
// Update Rn[N]
if ((iTableOffset % 2) == 0)
workingSet.Rn[iBlockOffset].m_data[iTableOffset >> 1] |= Convert.ToByte((A ^ B) << 4);
else
workingSet.Rn[iBlockOffset].m_data[iTableOffset >> 1] |= Convert.ToByte(A ^ B);
}
}
// X = R16 L16
workingSet.X.Reset();
for (iTableOffset = 0; iTableOffset < 4; iTableOffset++)
{
workingSet.X.m_data[iTableOffset] = workingSet.Rn[16].m_data[iTableOffset];
workingSet.X.m_data[iTableOffset + 4] = workingSet.Ln[16].m_data[iTableOffset];
}
// C = X perm IP
workingSet.DataBlockOut.Reset();
for (iTableOffset = 0; iTableOffset < byteRFP.Length; iTableOffset++)
{
// Get perm offset
iPermOffset = byteRFP[iTableOffset];
iPermOffset--;
// Get and set bit
workingSet.DataBlockOut.SetBit(
_bitAddressToByteOffset(iTableOffset, 8),
_bitAddressToBitOffset(iTableOffset, 8),
workingSet.X.GetBit(
_bitAddressToByteOffset(iPermOffset, 8),
_bitAddressToBitOffset(iPermOffset, 8)
)
);
}
} // key loop
}
#endregion Static Operations
/////////////////////////////////////////////////////////////
// Helper Operations
private static int _bitAddressToByteOffset(int iTableAddress, int iTableWidth)
{
int iFtmp = iTableAddress / iTableWidth;
return iFtmp;
}
private static int _bitAddressToBitOffset(int iTableAddress, int iTableWidth)
{
int iFtmp = BITS_PER_BYTE - 1 - (iTableAddress % iTableWidth);
return iFtmp;
}
/////////////////////////////////////////////////////////////
#region Debug Operations
#if DEBUG
#if !SILVERLIGHT
private static void MicrosoftDESEncrypt(byte[] bufferIn, ref byte[] bufferOut, byte[] Key, bool bEncrypt, bool bDESMode)
{
// Declaration of key and IV
byte[] bufferTemp = new byte[1024];
byte[] IV;
if(bDESMode)
IV = new byte[8];
else
IV = new byte[8*3];
// Declare a crypto object
ICryptoTransform crypto;
if (bDESMode)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Padding = PaddingMode.PKCS7;
if (bEncrypt)
crypto = des.CreateEncryptor(Key, IV);
else
crypto = des.CreateDecryptor(Key, IV);
}
else
{
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
tripleDes.Padding = PaddingMode.PKCS7;
if (bEncrypt)
crypto = tripleDes.CreateEncryptor(Key, IV);
else
crypto = tripleDes.CreateDecryptor(Key, IV);
}
// a memory stream for the cyrpto
using(MemoryStream ms = new MemoryStream())
{
// Create a CryptoStream using the memory stream
using (CryptoStream encStream = new CryptoStream(ms, crypto, CryptoStreamMode.Write))
{
// Encrypt/decrypt and flush
encStream.Write(bufferIn, 0, bufferIn.Length);
encStream.Flush();
encStream.FlushFinalBlock();
encStream.Close();
// Get the data into a buffer
bufferOut = ms.ToArray();
}
}
}
#endif // #if !SILVERLIGHT
#endif // #if DEBUG
#if DEBUG
#if !SILVERLIGHT
public static void _assertBufferMatch(byte[] A, byte[] B)
{
// Compare outputs
Debug.Assert(A.Length == B.Length);
for (int iOffset = 0; iOffset < A.Length; iOffset++)
Debug.Assert(A[iOffset] == B[iOffset]);
}
#endif // #if !SILVERLIGHT
#endif // #if DEBUG
#if DEBUG
#if !SILVERLIGHT
public static void Test()
{
//
// This function encrypts and encrypts data using our DES algorithm, and
// ensures the results are the same as the Microsoft algorithm with default padding settings.
//
// Declaration of local variables
Random rnd = new Random(1);
byte[] DesKey, Des3Key;
byte[] plainText = null, cypherText = null, plainText2 = null, msCypherText = null, msPlainText2 = null;
// Compare the DES algorithm with the Microsoft algorithm
for (int iTest = 0; iTest < 100*1000; iTest++)
{
// Dump progress
if ((iTest % 200) == 0)
Trace.TraceInformation("Test {0}", iTest);
// Generate test data
DesKey = DESCrytography.CreateDesKey(rnd);
Des3Key = DESCrytography.CreateTripleDesKey(rnd);
int iLength = rnd.Next(0, 256);
if ((plainText == null) || (plainText.Length != iLength))
plainText = new byte[iLength];
rnd.NextBytes(plainText);
// DES Test
{
// Encrypt using our algorithm
DESCrytography.DES(plainText, ref cypherText, DesKey, true);
// Decrypt using our algorithm
DESCrytography.DES(cypherText, ref plainText2, DesKey, false);
// Compare outputs
_assertBufferMatch(plainText,plainText2);
// Encrypt using Microsoft algorithm
MicrosoftDESEncrypt(plainText, ref msCypherText, DesKey, true, true);
// Decrypt using Microsoft algorithm
MicrosoftDESEncrypt(msCypherText, ref msPlainText2, DesKey, false, true);
// Compare outputs
_assertBufferMatch(plainText, msPlainText2);
// Make sure Microsoft and our algorithms are the same
_assertBufferMatch(cypherText, msCypherText);
}
// TripleDES Test
{
// Encrypt using our algorithm
DESCrytography.TripleDES(plainText, ref cypherText, Des3Key, true);
// Decrypt using our algorithm
DESCrytography.TripleDES(cypherText, ref plainText2, Des3Key, false);
// Compare outputs
_assertBufferMatch(plainText, plainText2);
// Encrypt using Microsoft algorithm
MicrosoftDESEncrypt(plainText, ref msCypherText, Des3Key, true, false);
// Decrypt using Microsoft algorithm
MicrosoftDESEncrypt(msCypherText, ref msPlainText2, Des3Key, false, false);
// Compare outputs
_assertBufferMatch(plainText, msPlainText2);
// Make sure Microsoft and our algorithms are the same
_assertBufferMatch(cypherText, msCypherText);
}
} // for-loop
}
#endif // #if !SILVERLIGHT
#endif // #if DEBUG
#endregion Debug Operations
}
}
//Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Text;
// **************************************************************
// * Raw implementation of the MD5 hash algorithm
// * from RFC 1321.
// *
// * Written By: Reid Borsuk and Jenny Zheng
// * Copyright (c) Microsoft Corporation. All rights reserved.
// **************************************************************
// Simple struct for the (a,b,c,d) which is used to compute the mesage digest.
struct ABCDStruct
{
public uint A;
public uint B;
public uint C;
public uint D;
}
public sealed class MD5Core
{
//Prevent CSC from adding a default public constructor
private MD5Core() { }
public static byte[] GetHash(string input, Encoding encoding)
{
if (null == input)
throw new System.ArgumentNullException("input", "Unable to calculate hash over null input data");
if (null == encoding)
throw new System.ArgumentNullException("encoding", "Unable to calculate hash over a string without a default encoding. Consider using the GetHash(string) overload to use UTF8 Encoding");
byte[] target = encoding.GetBytes(input);
return GetHash(target);
}
public static byte[] GetHash(string input)
{
return GetHash(input, new UTF8Encoding());
}
public static string GetHashString(byte[] input)
{
if (null == input)
throw new System.ArgumentNullException("input", "Unable to calculate hash over null input data");
string retval = BitConverter.ToString(GetHash(input));
retval = retval.Replace("-", "");
return retval;
}
public static string GetHashString(string input, Encoding encoding)
{
if (null == input)
throw new System.ArgumentNullException("input", "Unable to calculate hash over null input data");
if (null == encoding)
throw new System.ArgumentNullException("encoding", "Unable to calculate hash over a string without a default encoding. Consider using the GetHashString(string) overload to use UTF8 Encoding");
byte[] target = encoding.GetBytes(input);
return GetHashString(target);
}
public static string GetHashString(string input)
{
return GetHashString(input, new UTF8Encoding());
}
public static byte[] GetHash(byte[] input)
{
if (null == input)
throw new System.ArgumentNullException("input", "Unable to calculate hash over null input data");
//Intitial values defined in RFC 1321
ABCDStruct abcd = new ABCDStruct();
abcd.A = 0x67452301;
abcd.B = 0xefcdab89;
abcd.C = 0x98badcfe;
abcd.D = 0x10325476;
//We pass in the input array by block, the final block of data must be handled specialy for padding & length embeding
int startIndex = 0;
while (startIndex <= input.Length - 64)
{
MD5Core.GetHashBlock(input, ref abcd, startIndex);
startIndex += 64;
}
// The final data block.
return MD5Core.GetHashFinalBlock(input, startIndex, input.Length - startIndex, abcd, (Int64)input.Length * 8);
}
internal static byte[] GetHashFinalBlock(byte[] input, int ibStart, int cbSize, ABCDStruct ABCD, Int64 len)
{
byte[] working = new byte[64];
byte[] length = BitConverter.GetBytes(len);
//Padding is a single bit 1, followed by the number of 0s required to make size congruent to 448 modulo 512. Step 1 of RFC 1321
//The CLR ensures that our buffer is 0-assigned, we don't need to explicitly set it. This is why it ends up being quicker to just
//use a temporary array rather then doing in-place assignment (5% for small inputs)
Array.Copy(input, ibStart, working, 0, cbSize);
working[cbSize] = 0x80;
//We have enough room to store the length in this chunk
if (cbSize < 56)
{
Array.Copy(length, 0, working, 56, 8);
GetHashBlock(working, ref ABCD, 0);
}
else //We need an aditional chunk to store the length
{
GetHashBlock(working, ref ABCD, 0);
//Create an entirely new chunk due to the 0-assigned trick mentioned above, to avoid an extra function call clearing the array
working = new byte[64];
Array.Copy(length, 0, working, 56, 8);
GetHashBlock(working, ref ABCD, 0);
}
byte[] output = new byte[16];
Array.Copy(BitConverter.GetBytes(ABCD.A), 0, output, 0, 4);
Array.Copy(BitConverter.GetBytes(ABCD.B), 0, output, 4, 4);
Array.Copy(BitConverter.GetBytes(ABCD.C), 0, output, 8, 4);
Array.Copy(BitConverter.GetBytes(ABCD.D), 0, output, 12, 4);
return output;
}
// Performs a single block transform of MD5 for a given set of ABCD inputs
/* If implementing your own hashing framework, be sure to set the initial ABCD correctly according to RFC 1321:
// A = 0x67452301;
// B = 0xefcdab89;
// C = 0x98badcfe;
// D = 0x10325476;
*/
internal static void GetHashBlock(byte[] input, ref ABCDStruct ABCDValue, int ibStart)
{
uint[] temp = Converter(input, ibStart);
uint a = ABCDValue.A;
uint b = ABCDValue.B;
uint c = ABCDValue.C;
uint d = ABCDValue.D;
a = r1(a, b, c, d, temp[0], 7, 0xd76aa478);
d = r1(d, a, b, c, temp[1], 12, 0xe8c7b756);
c = r1(c, d, a, b, temp[2], 17, 0x242070db);
b = r1(b, c, d, a, temp[3], 22, 0xc1bdceee);
a = r1(a, b, c, d, temp[4], 7, 0xf57c0faf);
d = r1(d, a, b, c, temp[5], 12, 0x4787c62a);
c = r1(c, d, a, b, temp[6], 17, 0xa8304613);
b = r1(b, c, d, a, temp[7], 22, 0xfd469501);
a = r1(a, b, c, d, temp[8], 7, 0x698098d8);
d = r1(d, a, b, c, temp[9], 12, 0x8b44f7af);
c = r1(c, d, a, b, temp[10], 17, 0xffff5bb1);
b = r1(b, c, d, a, temp[11], 22, 0x895cd7be);
a = r1(a, b, c, d, temp[12], 7, 0x6b901122);
d = r1(d, a, b, c, temp[13], 12, 0xfd987193);
c = r1(c, d, a, b, temp[14], 17, 0xa679438e);
b = r1(b, c, d, a, temp[15], 22, 0x49b40821);
a = r2(a, b, c, d, temp[1], 5, 0xf61e2562);
d = r2(d, a, b, c, temp[6], 9, 0xc040b340);
c = r2(c, d, a, b, temp[11], 14, 0x265e5a51);
b = r2(b, c, d, a, temp[0], 20, 0xe9b6c7aa);
a = r2(a, b, c, d, temp[5], 5, 0xd62f105d);
d = r2(d, a, b, c, temp[10], 9, 0x02441453);
c = r2(c, d, a, b, temp[15], 14, 0xd8a1e681);
b = r2(b, c, d, a, temp[4], 20, 0xe7d3fbc8);
a = r2(a, b, c, d, temp[9], 5, 0x21e1cde6);
d = r2(d, a, b, c, temp[14], 9, 0xc33707d6);
c = r2(c, d, a, b, temp[3], 14, 0xf4d50d87);
b = r2(b, c, d, a, temp[8], 20, 0x455a14ed);
a = r2(a, b, c, d, temp[13], 5, 0xa9e3e905);
d = r2(d, a, b, c, temp[2], 9, 0xfcefa3f8);
c = r2(c, d, a, b, temp[7], 14, 0x676f02d9);
b = r2(b, c, d, a, temp[12], 20, 0x8d2a4c8a);
a = r3(a, b, c, d, temp[5], 4, 0xfffa3942);
d = r3(d, a, b, c, temp[8], 11, 0x8771f681);
c = r3(c, d, a, b, temp[11], 16, 0x6d9d6122);
b = r3(b, c, d, a, temp[14], 23, 0xfde5380c);
a = r3(a, b, c, d, temp[1], 4, 0xa4beea44);
d = r3(d, a, b, c, temp[4], 11, 0x4bdecfa9);
c = r3(c, d, a, b, temp[7], 16, 0xf6bb4b60);
b = r3(b, c, d, a, temp[10], 23, 0xbebfbc70);
a = r3(a, b, c, d, temp[13], 4, 0x289b7ec6);
d = r3(d, a, b, c, temp[0], 11, 0xeaa127fa);
c = r3(c, d, a, b, temp[3], 16, 0xd4ef3085);
b = r3(b, c, d, a, temp[6], 23, 0x04881d05);
a = r3(a, b, c, d, temp[9], 4, 0xd9d4d039);
d = r3(d, a, b, c, temp[12], 11, 0xe6db99e5);
c = r3(c, d, a, b, temp[15], 16, 0x1fa27cf8);
b = r3(b, c, d, a, temp[2], 23, 0xc4ac5665);
a = r4(a, b, c, d, temp[0], 6, 0xf4292244);
d = r4(d, a, b, c, temp[7], 10, 0x432aff97);
c = r4(c, d, a, b, temp[14], 15, 0xab9423a7);
b = r4(b, c, d, a, temp[5], 21, 0xfc93a039);
a = r4(a, b, c, d, temp[12], 6, 0x655b59c3);
d = r4(d, a, b, c, temp[3], 10, 0x8f0ccc92);
c = r4(c, d, a, b, temp[10], 15, 0xffeff47d);
b = r4(b, c, d, a, temp[1], 21, 0x85845dd1);
a = r4(a, b, c, d, temp[8], 6, 0x6fa87e4f);
d = r4(d, a, b, c, temp[15], 10, 0xfe2ce6e0);
c = r4(c, d, a, b, temp[6], 15, 0xa3014314);
b = r4(b, c, d, a, temp[13], 21, 0x4e0811a1);
a = r4(a, b, c, d, temp[4], 6, 0xf7537e82);
d = r4(d, a, b, c, temp[11], 10, 0xbd3af235);
c = r4(c, d, a, b, temp[2], 15, 0x2ad7d2bb);
b = r4(b, c, d, a, temp[9], 21, 0xeb86d391);
ABCDValue.A = unchecked(a + ABCDValue.A);
ABCDValue.B = unchecked(b + ABCDValue.B);
ABCDValue.C = unchecked(c + ABCDValue.C);
ABCDValue.D = unchecked(d + ABCDValue.D);
return;
}
//Manually unrolling these equations nets us a 20% performance improvement
private static uint r1(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + F(b, c, d) + x + t), s))
//F(x, y, z) ((x & y) | ((x ^ 0xFFFFFFFF) & z))
return unchecked(b + LSR((a + ((b & c) | ((b ^ 0xFFFFFFFF) & d)) + x + t), s));
}
private static uint r2(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + G(b, c, d) + x + t), s))
//G(x, y, z) ((x & z) | (y & (z ^ 0xFFFFFFFF)))
return unchecked(b + LSR((a + ((b & d) | (c & (d ^ 0xFFFFFFFF))) + x + t), s));
}
private static uint r3(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + H(b, c, d) + k + i), s))
//H(x, y, z) (x ^ y ^ z)
return unchecked(b + LSR((a + (b ^ c ^ d) + x + t), s));
}
private static uint r4(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + I(b, c, d) + k + i), s))
//I(x, y, z) (y ^ (x | (z ^ 0xFFFFFFFF)))
return unchecked(b + LSR((a + (c ^ (b | (d ^ 0xFFFFFFFF))) + x + t), s));
}
// Implementation of left rotate
// s is an int instead of a uint becuase the CLR requires the argument passed to >>/<< is of
// type int. Doing the demoting inside this function would add overhead.
private static uint LSR(uint i, int s)
{
return ((i << s) | (i >> (32 - s)));
}
//Convert input array into array of UInts
private static uint[] Converter(byte[] input, int ibStart)
{
if (null == input)
throw new System.ArgumentNullException("input", "Unable convert null array to array of uInts");
uint[] result = new uint[16];
for (int i = 0; i < 16; i++)
{
result[i] = (uint)input[ibStart + i * 4];
result[i] += (uint)input[ibStart + i * 4 + 1] << 8;
result[i] += (uint)input[ibStart + i * 4 + 2] << 16;
result[i] += (uint)input[ibStart + i * 4 + 3] << 24;
}
return result;
}
}
//Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Security.Cryptography;
// **************************************************************
// * Raw implementation of the MD5 hash algorithm
// * from RFC 1321.
// *
// * Written By: Reid Borsuk and Jenny Zheng
// * Copyright (c) Microsoft Corporation. All rights reserved.
// **************************************************************
#if SILVERLIGHT
public class MD5Managed : HashAlgorithm
#else
public class MD5Managed : MD5
#endif
{
private byte[] _data;
private ABCDStruct _abcd;
private Int64 _totalLength;
private int _dataSize;
public MD5Managed()
{
base.HashSizeValue = 0x80;
this.Initialize();
}
public override void Initialize()
{
_data = new byte[64];
_dataSize = 0;
_totalLength = 0;
_abcd = new ABCDStruct();
//Intitial values as defined in RFC 1321
_abcd.A = 0x67452301;
_abcd.B = 0xefcdab89;
_abcd.C = 0x98badcfe;
_abcd.D = 0x10325476;
}
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
int startIndex = ibStart;
int totalArrayLength = _dataSize + cbSize;
if (totalArrayLength >= 64)
{
Array.Copy(array, startIndex, _data, _dataSize, 64 - _dataSize);
// Process message of 64 bytes (512 bits)
MD5Core.GetHashBlock(_data, ref _abcd, 0);
startIndex += 64 - _dataSize;
totalArrayLength -= 64;
while (totalArrayLength >= 64)
{
Array.Copy(array, startIndex, _data, 0, 64);
MD5Core.GetHashBlock(array, ref _abcd, startIndex);
totalArrayLength -= 64;
startIndex += 64;
}
_dataSize = totalArrayLength;
Array.Copy(array, startIndex, _data, 0, totalArrayLength);
}
else
{
Array.Copy(array, startIndex, _data, _dataSize, cbSize);
_dataSize = totalArrayLength;
}
_totalLength += cbSize;
}
protected override byte[] HashFinal()
{
base.HashValue = MD5Core.GetHashFinalBlock(_data, 0, _dataSize, _abcd, _totalLength * 8);
return base.HashValue;
}
}
@wayanokie
Copy link

nice code.
can you send me the form please ! to my email mooi88@hotmail.com
and possible for me to build and test it directly on my visual studio
many thanks Wayan from Bali

@wayanokie
Copy link

nice code.
can you send me the form please ! to my email mooi88@hotmail.com
and possible for me to build and test it directly on my visual studio
many thanks Wayan from Bali

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment