How can I calculate a CRC32 as a signed integer in C#? - c#

I'm a PHP developer and a little out of my element in C#. In PHP, there's a crc32() function which returns a signed integer for any string that you pass in.
So this is what I'm used to:
<?php
echo crc32("test");
// displays -662733300
I would like to do the same thing in C#. I came across this C# class library but understand little about it. According to his instructions, I'm supposed to do this:
// first convert string to byte-array
String input = "test";
byte[] bytes = new byte[input.length * sizeof(char)];
System.Buffer.BlockCopy(input.ToCharArray(), 0, bytes, 0, bytes.Length);
// then calculate the value
Crc32 crc32 = new Crc32();
String output = "";
foreach (byte b in crc32.ComputeHash(bytes))
{
output += b.ToString("x2").ToLower();
}
That gives me an output string of 27d86d6a. What do I need to do instead to return a signed integer? (Which in this example should equal -662733300)

Try use BitConverter.ToInt32 method:
var crcVal = BitConverter.ToInt32(crc32.ComputeHash(bytes), 0);
EDIT
It's seems you use different Crc32 algorithm implementation, try the following one:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
public class Program
{
public void Main()
{
// first convert string to byte-array
String input = "test";
byte[] bytes = new byte[input.Length * sizeof(char)];
System.Buffer.BlockCopy(input.ToCharArray(), 0, bytes, 0, bytes.Length);
// then calculate the value
var crcVal = crc32(input);
Console.WriteLine((int)crcVal);
}
public uint crc32(string input) {
var table = new uint[]{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
unchecked
{
uint crc = (uint)(((uint)0) ^ (-1));
var len = input.Length;
for (var i=0; i < len; i++) {
crc = (crc >> 8) ^ table[
(crc ^ (byte)input[i]) & 0xFF
];
}
crc = (uint)(crc ^ (-1));
if (crc < 0) {
crc += (uint)4294967296;
}
return crc;
}
}
}
Demo

Related

How to Decrypt a ciphersaber hexadecimal text in pure C#

I am trying to decrypt a ciphersaber encrypted hexadecimal message using an IV mixing round of 20 with the key MyKey.
The messages is:
bad85d9e7f5aff959b6b332b44af2cc554d8a6eb
I am doing this in pure C# and it should return the message: Hola Mundo
using System;
using System.Text;
public class Program
{
public static void Main(string[] args)
{
// Hexadecimal text
string hexText = "bad85d9e7f5aff959b6b332b44af2cc554d8a6eb";
// Convert hexadecimal text to byte array
byte[] encryptedData = new byte[hexText.Length / 2];
for (int i = 0; i < encryptedData.Length; i++)
{
encryptedData[i] = Convert.ToByte(hexText.Substring(i * 2, 2), 16);
}
// IV length
int ivLength = 1;
// Key loop iterations
int keyIterations = 20;
// Encryption key
string encryptionKey = "MyKey";
// Convert encryption key to byte array
byte[] keyData = Encoding.UTF8.GetBytes(encryptionKey);
// Create an array to store the IV
byte[] ivData = new byte[ivLength];
// Copy the first `ivLength` bytes of the encrypted data to the IV array
Array.Copy(encryptedData, 0, ivData, 0, ivLength);
// Create an array to store the encrypted message
byte[] messageData = new byte[encryptedData.Length - ivLength];
// Copy the remaining bytes of the encrypted data to the message data array
Array.Copy(encryptedData, ivLength, messageData, 0, messageData.Length);
// Create an array to store the decrypted message
byte[] decryptedData = new byte[messageData.Length];
// Perform the decryption
for (int i = 0; i < messageData.Length; i++)
{
decryptedData[i] = (byte)(messageData[i] ^ keyData[i % keyData.Length]);
for (int j = 0; j < keyIterations; j++)
{
decryptedData[i] = (byte)(decryptedData[i] ^ ivData[j % ivData.Length]);
}
}
// Convert the decrypted data to a string and print it
string decryptedMessage = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("Decrypted message: " + decryptedMessage);
}
}
Now when I try it returns: �$�#���Jf=�I���
What mistake am I making in the code or am I implementing it wrong?
I tested the text with the following site to see if it was ok: https://ruletheweb.co.uk/cgi-bin/saber.cgi
CipherSaber uses as IV the first 10 bytes of the encrypted message. The rest is the actual ciphertext. The IV is appended to the key (giving the key setup input), which is used as input to the CipherSaber key setup, see CipherSaber, Technical description, 1st section.
In the posted code, an IV length of 1 is applied instead of 10, which incorrectly determines IV (and thus key setup input) and actual ciphertext. The correct determination of IV and actual ciphertext is:
private static (byte[], byte[]) SeparateIvCiphertext(byte[] ivCiphertext)
{
int ivLen = 10;
byte[] iv = new byte[ivLen];
Buffer.BlockCopy(ivCiphertext, 0, iv, 0, iv.Length);
byte[] ciphertext = new byte[ivCiphertext.Length - iv.Length];
Buffer.BlockCopy(ivCiphertext, iv.Length, ciphertext, 0, ciphertext.Length);
return (iv, ciphertext);
}
and of the key setup input:
private static byte[] GetKeySetupInput(byte[] key, byte[] iv)
{
byte[] keySetupInput = new byte[key.Length + iv.Length];
Buffer.BlockCopy(key, 0, keySetupInput, 0, key.Length);
Buffer.BlockCopy(iv, 0, keySetupInput, key.Length, iv.Length);
return keySetupInput;
}
Furthermore, the decryption itself seems to be implemented incorrectly or at least incompletely. CipherSaber uses RC4 as its encryption/decryption algorithm, which can be divided into a key setup and the actual encryption/decryption:
The referenced website performs decryption using CipherSaber-2. Compared to the original CipherSaber (referred to as CipherSaber-1), a modified key setup is used in which the CipherSaber-1/RC4 key setup is repeated multiple times, 20 times in the case of the posted data.
A description of the CipherSaber-1/RC4 key setup can be found here, Key-scheduling algorithm (KSA), a possible implementation for CipherSaber-2 is:
private static byte[] sBox = new byte[256];
private static void KeySetup(byte[] input, int iterations)
{
for (int i = 0; i < 256; i++)
{
sBox[i] = (byte)i;
}
int j = 0;
for (int cs2loop = 0; cs2loop < iterations; cs2loop++) // CipherSaber-2 modification
{
for (int i = 0; i < 256; i++)
{
j = (j + sBox[i] + input[i % input.Length]) % 256;
Swap(ref sBox[i], ref sBox[j]);
}
}
}
private static void Swap(ref byte val1, ref byte val2)
{
if (val1 == val2) return;
val1 = (byte)(val1 ^ val2);
val2 = (byte)(val2 ^ val1);
val1 = (byte)(val1 ^ val2);
}
The loop marked CipherSaber-2 modification in the code snippet is the modification compared to CipherSaber-1/RC4!
The actual encryption/decryption is described here, Pseudo-random generation algorithm (PRGA), a possible implememtation is:
private static byte[] Process(byte[] input)
{
int i = 0, j = 0;
byte[] result = new byte[input.Length];
for (int k = 0; k < input.Length; k++)
{
i = (i + 1) % 256;
j = (j + sBox[i]) % 256;
Swap(ref sBox[i], ref sBox[j]);
result[k] = (byte)(sBox[(sBox[i] + sBox[j]) % 256] ^ input[k]);
}
return result;
}
Note that this algorithm is used for both encryption and decryption.
With this, the posted encrypted message can be decrypted as follows:
using System;
using System.Text;
...
byte[] key = Encoding.UTF8.GetBytes("MyKey");
byte[] encryptedData = Convert.FromHexString("bad85d9e7f5aff959b6b332b44af2cc554d8a6eb");
(byte[] iv, byte[] ciphertext) = SeparateIvCiphertext(encryptedData);
byte[] keySetupInput = GetKeySetupInput(key, iv);
int iterations = 20;
KeySetup(keySetupInput, iterations);
byte[] plaintext = Process(ciphertext);
Console.WriteLine(Encoding.UTF8.GetString(plaintext)); // Hola Mundo
which gives Hola Mundo as plaintext.

Trying to reproduce PHP's pack("H*") function in C#

this is my code in C# :
public static String MD5Encrypt(String str, Boolean raw_output=false)
{
// Use input string to calculate MD5 hash
String output;
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(str);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
output = sb.ToString();
if (raw_output)
{
output = pack(output);
}
return output;
}
public static String pack(String S)
{
string MultiByte = "";
for (int i = 0; i <= S.Length - 1; i += 2)
{
MultiByte += Convert.ToChar(HexToDec(S.Substring(i, 2)));
}
return MultiByte;
}
private static int HexToDec(String hex)
{
//Int32.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
return Convert.ToInt32(hex, 16);
}
To reproduce what is done in php by this way :
md5($str, true);
OR
pack('H*', md5( $str ));
I tried many things but can't get the same on the two sides in some cases of word.
For example, Trying this test on the string "8tv7er5j"
PHP Side :
9c36ad446f83ca38619e12d9e1b3c39e <= md5("8tv7er5j");
œ6­DoƒÊ8ažÙá³Ãž <= md5("8tv7er5j", true) or pack("H*", md5("8tv7er5j"))
C# Side :
9c36ad446f83ca38619e12d9e1b3c39e <= MD5Encrypt("8tv7er5j")
6­DoÊ8aÙá³Ã <= MD5Encrypt("8tv7er5j", true) or pack( MD5Encrypt("8tv7er5j") )
Why ? Encoding problem ?
EDIT 1 :
I have the good result, but bad encoded with this this function for pack() :
if ((hex.Length % 2) == 1) hex += '0';
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
So, System.Text.Encoding.UTF8.GetString(bytes) give me :
�6�Do��8a���Þ
And System.Text.Encoding.ASCII.GetString(bytes)
?6?Do??8a??????
...
I encountered same scenario where I am in need of php's pack-unpack-md5 functions in C#. Most important was that I need to match out of all these 3 functions with php.
I created my own functions and then validated(verified) my output with functions at onlinephpfunctions.com. The output was same when I parsed with DefaultEncoding. FYI, I checked my application's encoding(Encoding.Default.ToString()) and it was System.Text.SBCSCodePageEncoding
Pack
private static string pack(string input)
{
//only for H32 & H*
return Encoding.Default.GetString(FromHex(input));
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
MD5
private static string md5(string input)
{
byte[] asciiBytes = Encoding.Default.GetBytes(input);
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
return hashedString;
}
Unpack
private static string unpack(string p1, string input)
{
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
string a = Convert.ToInt32(input[i]).ToString("X");
output.Append(a);
}
return output.ToString();
}
PS: User can enhance these functions with other formats
I guess that PHP defaults to Latin1 so the code should look like :
public static String PhpMd5Raw(string str)
{
var md5 = System.Security.Cryptography.MD5.Create();
var inputBytes = System.Text.Encoding.ASCII.GetBytes(str);
var hashBytes = md5.ComputeHash(inputBytes);
var latin1Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
return latin1Encoding.GetString(hashBytes);
}
If you are going to feed the result as a key for HMAC-SHA1 hashing keep it as bytes[] and initialize the HMACSHA1 with the return value of this function: DO NOT convert it to a string and back to bytes, I have spent hours because of this mistake.
public static byte[] PackH(string hex)
{
if ((hex.Length % 2) == 1) hex += '0';
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
I know this is an old question. I am posting my answer for anyone who might reach this page searching for it.
The following code is the full conversion of the pearl function pack("H*") to c#.
public static String Pack(String input)
{
input = input.Replace("-", " ");
byte[] hashBytes = new byte[input.Length / 2];
for (int i = 0; i < hashBytes.Length; i++)
{
hashBytes[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
}
return Encoding.UTF7.GetString(hashBytes); // for perl/php
}
I'm sorry. I didn't go with the questions completely. But if php code is as below,
$testpack = pack("H*" , "you value");
and if can't read the $testpack values(due to some non support format), then first do base64_encode as below and echo it.
echo base64_encode($testpack);
Then use Risky Pathak answer. For complete this answer I'll post his answer with some small modification like base 64 encoding etc.
var hex = "you value";
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
var res = Convert.ToBase64String(raw);
Console.WriteLine(res);
Now if you compare both of values, those should be similar.
And all credit should go to the Risky Pathak answer.
The same in c# can be reached with Hex.Decode() method.
And bin2hex() in php is Hex.Encode().

Dotnet Hex string to Java

Have a problem, much like this post: How to read a .NET Guid into a Java UUID.
Except, from a remote svc I get a hex str formatted like this: ABCDEFGH-IJKL-MNOP-QRST-123456.
I need to match the GUID.ToByteArray() generated .net byte array GH-EF-CD-AB-KL-IJ-OP-MN- QR- ST-12-34-56 in Java for hashing purposes.
I'm kinda at a loss as to how to parse this. Do I cut off the QRST-123456 part and perhaps use something like the Commons IO EndianUtils on the other part, then stitch the 2 arrays back together as well? Seems way too complicated.
I can rearrange the string, but I shouldn't have to do any of these. Mr. Google doesn't wanna help me neither..
BTW, what is the logic in Little Endian land that keeps those last 6 char unchanged?
Yes, for reference, here's what I've done {sorry for 'answer', but had trouble formatting it properly in comment}:
String s = "3C0EA2F3-B3A0-8FB0-23F0-9F36DEAA3F7E";
String[] splitz = s.split("-");
String rebuilt = "";
for (int i = 0; i < 3; i++) {
// Split into 2 char chunks. '..' = nbr of chars in chunks
String[] parts = splitz[i].split("(?<=\\G..)");
for (int k = parts.length -1; k >=0; k--) {
rebuilt += parts[k];
}
}
rebuilt += splitz[3]+splitz[4];
I know, it's hacky, but it'll do for testing.
Make it into a byte[] and skip the first 3 bytes:
package guid;
import java.util.Arrays;
public class GuidConvert {
static byte[] convertUuidToBytes(String guid) {
String hexdigits = guid.replaceAll("-", "");
byte[] bytes = new byte[hexdigits.length()/2];
for (int i = 0; i < bytes.length; i++) {
int x = Integer.parseInt(hexdigits.substring(i*2, (i+1)*2), 16);
bytes[i] = (byte) x;
}
return bytes;
}
static String bytesToHexString(byte[] bytes) {
StringBuilder buf = new StringBuilder();
for (byte b : bytes) {
int i = b >= 0 ? b : (int) b + 256;
buf.append(Integer.toHexString(i / 16));
buf.append(Integer.toHexString(i % 16));
}
return buf.toString();
}
public static void main(String[] args) {
String guid = "3C0EA2F3-B3A0-8FB0-23F0-9F36DEAA3F7E";
byte[] bytes = convertUuidToBytes(guid);
System.err.println("GUID = "+ guid);
System.err.println("bytes = "+ bytesToHexString(bytes));
byte[] tail = Arrays.copyOfRange(bytes, 3, bytes.length);
System.err.println("tail = "+ bytesToHexString(tail));
}
}
The last group of 6 bytes is not reversed because it is an array of bytes. The first four groups are reversed because they are a four-byte integer followed by three two-byte integers.

Compare password hashes between C# and ColdFusion (CFMX_COMPAT)

I have a password hash that is stored in a table and is put there by the following coldfusion script-
#Hash(Encrypt(Form.UserPassword,GetSiteVars.EnCode))#
I am trying to add some outside functionality within a c# application. I would like to be able to take advantage of the data that already exists so that I can authenticate users. Does anyone know how I can replicate the above coldfusion code in c#?
Thanks for any thoughts.
I looked through the Railo code as someone else here mentioned in comments.
Following is CFMX_Compat ported to C# from the Railo Java source. See below for an example of usage.
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace RailoUtil
{
// SOURCE: Railo Source Code License LGPL v2
// http://wiki.getrailo.org/wiki/RailoLicense
public class RailoCFMXCompat
{
private String m_Key;
private int m_LFSR_A = 0x13579bdf;
private int m_LFSR_B = 0x2468ace0;
private int m_LFSR_C = unchecked((int)0xfdb97531);
private int m_Mask_A = unchecked((int)0x80000062);
private int m_Mask_B = 0x40000020;
private int m_Mask_C = 0x10000002;
private int m_Rot0_A = 0x7fffffff;
private int m_Rot0_B = 0x3fffffff;
private int m_Rot0_C = 0xfffffff;
private int m_Rot1_A = unchecked((int)0x80000000);
private int m_Rot1_B = unchecked((int)0xc0000000);
private int m_Rot1_C = unchecked((int)0xf0000000);
public byte[] transformString(String key, byte[] inBytes)
{
setKey(key);
int length = inBytes.Length;
byte[] outBytes = new byte[length];
for (int i = 0; i < length; i++)
{
outBytes[i] = transformByte(inBytes[i]);
}
return outBytes;
}
private byte transformByte(byte target)
{
byte crypto = 0;
int b = m_LFSR_B & 1;
int c = m_LFSR_C & 1;
for (int i = 0; i < 8; i++)
{
if (0 != (m_LFSR_A & 1))
{
m_LFSR_A = m_LFSR_A ^ m_Mask_A >> 1 | m_Rot1_A;
if (0 != (m_LFSR_B & 1))
{
m_LFSR_B = m_LFSR_B ^ m_Mask_B >> 1 | m_Rot1_B;
b = 1;
}
else
{
m_LFSR_B = m_LFSR_B >> 1 & m_Rot0_B;
b = 0;
}
}
else
{
m_LFSR_A = (m_LFSR_A >> 1) & m_Rot0_A;
if (0 != (m_LFSR_C & 1))
{
m_LFSR_C = m_LFSR_C ^ m_Mask_C >> 1 | m_Rot1_C;
c = 1;
}
else
{
m_LFSR_C = m_LFSR_C >> 1 & m_Rot0_C;
c = 0;
}
}
crypto = (byte)(crypto << 1 | b ^ c);
}
target ^= crypto;
return target;
}
private void setKey(String key)
{
int i = 0;
m_Key = key;
if (String.IsNullOrEmpty(key)) key = "Default Seed";
char[] Seed = new char[key.Length >= 12 ? key.Length : 12];
Array.Copy(m_Key.ToCharArray(), Seed, m_Key.Length);
int originalLength = m_Key.Length;
for (i = 0; originalLength + i < 12; i++)
Seed[originalLength + i] = Seed[i];
for (i = 0; i < 4; i++)
{
m_LFSR_A = (m_LFSR_A <<= 8) | Seed[i + 4];
m_LFSR_B = (m_LFSR_B <<= 8) | Seed[i + 4];
m_LFSR_C = (m_LFSR_C <<= 8) | Seed[i + 4];
}
if (0 == m_LFSR_A) m_LFSR_A = 0x13579bdf;
if (0 == m_LFSR_B) m_LFSR_B = 0x2468ace0;
if (0 == m_LFSR_C) m_LFSR_C = unchecked((int)0xfdb97531);
}
}
}
Here is a usage example that Hex-encodes the encrypted text, and then decrypts the same thing.
RailoCFMXCompat cfmx = new RailoCFMXCompat();
UTF8Encoding encoding = new UTF8Encoding();
//encrypt my string
byte[] encrypted = cfmx.transformString("mySecretKey", encoding.GetBytes("clear text"));
string encryptedHex = BitConverter.ToString(encrypted); //72-07-AA-1B-89-CB-01-96-4F-51
//decrypt my string
byte[] encryptedBytes = HexToBytes("72-07-AA-1B-89-CB-01-96-4F-51");
byte[] decrypted = cfmx.transformString("mySecretKey", encryptedBytes);
string cleartext = encoding.GetString(decrypted);
MD5 is the default hashing algorithm for the hash(). I'm not a C# programmer, but it shouldn't be too hard to create an MD5 hash to compare to your ColdFusion result.
As for encrypt(), is there a reason you're encrypting the username before hashing it? I can't think of any benefit to doing this, but that doesn't mean there isn't one. I would simply do:
Hash( UCase( GetPass.username ) )
Which should be easier to replicate in C#.
I'll leave the original answer content below for historical reference, but it should be noted that this is NOT a working answer to the original question.
Instead, see the top-voted answer in this thread, by #Terrapin in January 2011. I hope the OP sees this and can change the accepted answer. Heck, I'll even flag the mods to see if anything can be done about this.
To build on the answer by Edward Smith, and the follow-up comments by czuroski, here is my solution.
First, you need an XOR function in C#, which I've taken from here and modified slightly.
using System;
using System.Collections.Generic;
using System.Text;
namespace SimpleXOREncryption
{
public static class EncryptorDecryptor
{
public static string EncryptDecrypt(string textToEncrypt, int key)
{
StringBuilder inSb = new StringBuilder(textToEncrypt);
StringBuilder outSb = new StringBuilder(textToEncrypt.Length);
char c;
for (int i = 0; i < textToEncrypt.Length; i++)
{
c = inSb[i];
c = (char)(c ^ key);
outSb.Append(c);
}
return outSb.ToString();
}
}
}
Then, take the result of the XOR and base-64 encode it. After you have that string, MD5 hash it. The result should match the result from the original code snippet:
#Hash(Encrypt(Form.UserPassword,GetSiteVars.EnCode))#
One of the solutions would be to have the DB do the hashing and encription, could be easier...
The default "encryption" in CF is simply an XOR:
ciphertext = base64_encode(plaintext ^ key)
So, to decrypt:
plaintext = base64_decode(ciphertext) ^ key
The default hash, as mentioned, is md5.
Edit:
Well, further research shows this is not true - just one of those pervasive myths.
I can't find any documentation of the actual algorithm for the CFMX_COMPAT encryption method.
Sorry about the wild goose chase.

Convert an integer to a byte[] of specific length

I'm trying to create a function (C#) that will take 2 integers (a value to become a byte[], a value to set the length of the array to) and return a byte[] representing the value. Right now, I have a function which only returns byte[]s of a length of 4 (I'm presuming 32-bit).
For instance, something like InttoByteArray(0x01, 2) should return a byte[] of {0x00, 0x01}.
Does anyone have a solution to this?
You could use the following
static public byte[] ToByteArray(object anyValue, int length)
{
if (length > 0)
{
int rawsize = Marshal.SizeOf(anyValue);
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.StructureToPtr(anyValue, buffer, false);
byte[] rawdatas = new byte[rawsize * length];
Marshal.Copy(buffer, rawdatas, (rawsize * (length - 1)), rawsize);
Marshal.FreeHGlobal(buffer);
return rawdatas;
}
return new byte[0];
}
Some test cases are:
byte x = 45;
byte[] x_bytes = ToByteArray(x, 1);
int y = 234;
byte[] y_bytes = ToByteArray(y, 5);
int z = 234;
byte[] z_bytes = ToByteArray(z, 0);
This will create an array of whatever size the type is that you pass in. If you want to only return byte arrays, it should be pretty easy to change. Right now its in a more generic form
To get what you want in your example you could do this:
int a = 0x01;
byte[] a_bytes = ToByteArray(Convert.ToByte(a), 2);
You can use the BitConverter utility class for this. Though I don't think it allows you to specify the length of the array when you're converting an int. But you can always truncate the result.
http://msdn.microsoft.com/en-us/library/de8fssa4.aspx
Take your current algorithm and chop off bytes from the array if the length specified is less than 4, or pad it with zeroes if it's more than 4. Sounds like you already have it solved to me.
You'd want some loop like:
for(int i = arrayLen - 1 ; i >= 0; i--) {
resultArray[i] = (theInt >> (i*8)) & 0xff;
}
byte[] IntToByteArray(int number, int bytes)
{
if(bytes > 4 || bytes < 0)
{
throw new ArgumentOutOfRangeException("bytes");
}
byte[] result = new byte[bytes];
for(int i = bytes-1; i >=0; i--)
{
result[i] = (number >> (8*i)) & 0xFF;
}
return result;
}
It fills the result array from right to left with the the bytes from less to most significant.
byte byte1 = (byte)((mut & 0xFF) ^ (mut3 & 0xFF));
byte byte2 = (byte)((mut1 & 0xFF) ^ (mut2 & 0xFF));
quoted from
C#: Cannot convert from ulong to byte

Categories