I have a problem recreating a password that's hashed in C#. In an online project when a user do the registration process his password is save after passing for this function:
private static string ToMD5Hash(string inputString)
{
using (MD5 md5 = MD5.Create())
{
byte[] data = Encoding.Unicode.GetBytes(inputString);
byte[] hash = md5.ComputeHash(data);
return Convert.ToBase64String(hash);
}
}
I'm working on an offline version that at some point will do a sync with the online version and I can't reproduce the same results on AS3 (Adobe Air). For example the password "1234" after passing to the C# code will be "DwN1hMmef9T0+MWVUPj1Bw==".
Can someone help me out?
My AS3 code is like this:
private function encode():void
{
var ba:ByteArray = new ByteArray();
ba.writeMultiByte("1234","unicode");
var str:String = MD5.hash(ba.toString());
var ba2:ByteArray = new ByteArray();
ba2.writeMultiByte(str.toString(),"unicode");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encodeUTFBytes(ba2.toString());
trace(encoder.toString());
}
When I do the ba.writeMultiByte("1234","unicode"); I get exactly the same ByteArray as in the C# but when I do the MD5.hash(ba.toString()); the new ByteArray is different.
So it looks like it may be a bug in as3corelib's implementation of writing the bits to the digest ByteArray.
It seemingly writes them in big endian format, rather than little endian. Or more specifically, it writes the bits as a collection of 4 integers rather than a collection of bytes, and in the process it mangles the byte order of the bits (which is why you are seeing different Base64 results -- the bytes are in a different order).
You can address this bug by adding on line 184 of MD5.as, in as3corelib, insert the following one line of code:
digest.endian = Endian.LITTLE_ENDIAN;
Also make sure you add an import at the top of the file for import flash.utils.Endian. I've created a public gist of the changes available here
Then it should generate the same byte order as c#, and then it should Base64 encode the same way. I verified it using the following as3 function:
private function encode():void
{
var ba:ByteArray = new ByteArray();
ba.endian = Endian.BIG_ENDIAN
ba.writeMultiByte("1234","unicode");
var str:String = MD5.hashBytes(ba);
var encoder:Base64Encoder = new Base64Encoder();
encoder.encodeBytes(MD5.digest);
trace(encoder.toString()); // DwN1hMmef9T0+MWVUPj1Bw==
}
Look at this.
Be aware that the original download mentioned in that site has a few bugs, so that you have to use the corrected vesion that you can find in the same post.
If you're using AS3CoreLib, do it this way:
Different MD5 with as3corelib.
Related
the below code was used several years ago to generate a binary that was used for encrypting some files, using DES algorithm (I know DES is weak and AES is recommended, but those are not my requirements).
the binary has been encrypting those files, which were successfully decrypted by the submission portal.
DES being a bijective algorithm for a single key, a single input should always yield the same output, and one output can only be obtained from one input.
However, recompiling the code today, the output file obtained is different than what the old binary used to yield. Meaning if i tried submitting the new file on the test portal, it would fail.
However, the code itself has not changed.
As to why I want to recompile the code:
My goal was to migrate the function to another language, and seeing as I was unable to obtain the same output, decided to try step-by-step debugging it in C# to see where the difference was coming from - except the old and new C# binaries are also returning different outputs...
Edit 1:
the input and outputs as requested:
input: hello world
old out: 5ELrrBHwxbNDT9Clywhhvg==
new out: RYZbVdhS+c5nRErRgZxZiw==
but since the key above is not the real key anyway, not sure it would be of help.
Edit 2:
tried all different combinations of CipherMode and PaddingMode, no match still.
Could the .NET / Framework / C# version matter? (newbie question, first time using C#)
although it shouldn't since the underlying algorithm is the same. Any ideas?
the C# code:
String strCryptKey = "12345678";
Byte[] strIVkey = new Byte[8];
strIVkey[0] = 0x13;
strIVkey[1] = 0x14;
strIVkey[2] = 0x15;
strIVkey[3] = 0x16;
strIVkey[4] = 0x17;
strIVkey[5] = 0x18;
strIVkey[6] = 0x19;
strIVkey[7] = 0x20;
string sourceString;
using (var streamReader = new StreamReader(args[0], Encoding.UTF8))
{
sourceString = streamReader.ReadToEnd();
byte[] sourceArray = Encoding.UTF8.GetBytes(sourceString);
MemoryStream tempM = new MemoryStream();
DES des = new DESCryptoServiceProvider();
CryptoStream encStream = new CryptoStream(
tempM,
des.CreateEncryptor(Encoding.UTF8.GetBytes(strCryptKey), strIVkey),
CryptoStreamMode.Write
);
encStream.Write(sourceArray, 0, sourceArray.Length);
encStream.FlushFinalBlock();
String encryptedString = Convert.ToBase64String(tempM.ToArray());
File.WriteAllText(args[1], encryptedString);
}
I am submitting the ACA forms(tax year:2016) to the IRS, getting the below error
<ns3:FormBCTransmitterSubmissionDtl xmlns="urn:us:gov:treasury:irs:ext:aca:air:ty16" xmlns:ns2="urn:us:gov:treasury:irs:common" xmlns:ns3="urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage">
<ACATransmitterSubmissionDetail>
<TransmitterErrorDetailGrp>
<ns2:ErrorMessageDetail>
<ns2:ErrorMessageCd>MANIFEST-025</ns2:ErrorMessageCd>
<ns2:ErrorMessageTxt>Manifest 'ChecksumAugmentationNum' must match the IRS-calculated 'ChecksumAugmentationNum' value of the transmission</ns2:ErrorMessageTxt>
</ns2:ErrorMessageDetail>
</TransmitterErrorDetailGrp>
</ACATransmitterSubmissionDetail>
Attached is our MTOM format we are using to send it through A2A.
https://www.dropbox.com/home?preview=samplemtom.txt
I am also tried the ChecksumAugmentationNum value set as Lower case also.
Have you successfully transmitted for Tax Year 2015? I have seen another post related to this issue, but have not run into this issue while sending TY2015 (to AATS or Production) or TY2016 records to AATS. My checksum calculation has not changed, and is very simple.
I have two methods I use to create the checksum: GetChecksum(string) and GetMD5Hash(MD5, string). This approach worked for TY2015, and I expect it to work for TY2016. IIRC, I took this approach directly from MSDN.
The string I pass into the GetChecksum method is the contents of the Form Data Attachment. In my process, I output the XML document into the file system for audit purposes, so the attachment is a physical file for me to use and reference. I read the attachment into a string variable using File.ReadAllText(string path) method.
After generating the checksum my process also will check the checksum against the database and return whether or not that checksum exists (meaning it was used by another form). In the case where this is true, then I update the Contact Suffix, regenerate the Form Data and then regenerate the checksum; this is per the IRS rules for transmission.
This is what is currently working for me, and hopefully this helps you.
Application Callers:
This is what I am doing to call the Checksum calculation functions/routines. It should be noted, I am physically writing each Form Data XML file to the File System, then reading from that.
string AttachmentFileContents = "";
AttachmentFileContents = File.ReadAllText(FormDataFilePath);
string checkSumAugmentationNumber = new Checksum().GetChecksum(AttachmentFileContents);
Checksum Methods:
These are the two methods I use for Checksum Calculation.
public string GetChecksum(string stringToEncrpyt)
{
string hash = "";
using(MD5 md5Hash = MD5.Create())
{
hash = GetMD5Hash(md5Hash, stringToEncrpyt);
}
return hash;
}
private string GetMD5Hash(MD5 md5Hash, string input)
{
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString("x2"));
}
return sb.ToString();
}
So I have a website for my game
This is an exert of the php that I am using.
$Login = strtolower(trim($Login));
$Pass = strtolower(trim($Pass));
$Repass = strtolower(trim($Repass));
$Salt = $Login.$Pass;
$Salt = md5($Salt);
$Salt = "0x".$Salt;
But now I am faced with an issue that I cant seem to work out. I need to be able to do this encryption through C# WinForms for a client side Launcher(Register, Play Game etc etc)
For the life of me I cant figure out how to make the same binary as it makes in php.
I have tried loads but just cant crack it.
Many thanks if you can help
Though your example code confuses the actual question, I think I have a solution for your actual problem.
I've had the same problem with that md5() medthod, converting some PHP code into C# a while back. Here's what I came up with:
private static string CalculateChecksum(string inputString)
{
var md5 = new MD5CryptoServiceProvider();
var hashbytes = md5.ComputeHash(Encoding.UTF8.GetBytes(inputString));
var hashstring = "";
foreach(var hashbyte in hashbytes)
hashstring += hashbyte.ToString("x2");
return hashstring;
}
There may be a neater solution, but that there is working for me and at the time I was in a hurry.
Anyway, it gives you strings like A48EDF06 ... as you would expect from php's md5()
I am trying to encrypt data with a password and store it inside a ASN.1 encoded CMS message (using C# and BouncyCastle 1.4)
The code I have seems to have two problems:
the data does not seem to be signed with a HMAC, so when I tamper with the encodedData (by enabling the commented out line), the decryption still succeeds.
when I decrypt the data I have tampered with, I get beck corrupted plain text. However only a two blocks of plaintext data are corrupted. This seems to suggest that the encryption does not actually use CBC mode.
(edit: disregard the second point, this is exactly how CBC is supposed to work)
This is what I am testing with:
public void TestMethod1()
{
byte[] data = new byte[1024]; // plaintext: a list of zeroes
CmsEnvelopedDataGenerator generator = new CmsEnvelopedDataGenerator();
CmsPbeKey encryptionKey = new Pkcs5Scheme2PbeKey("foo", new byte[] { 1, 2, 3 }, 2048);
generator.AddPasswordRecipient(encryptionKey, CmsEnvelopedDataGenerator.Aes256Cbc);
CmsProcessableByteArray cmsByteArray = new CmsProcessableByteArray(data);
CmsEnvelopedData envelopeData = generator.Generate(cmsByteArray, CmsEnvelopedDataGenerator.Aes256Cbc);
byte[] encodedData = envelopeData.GetEncoded();
// encodedData[500] = 10; // tamper with the data
RecipientID recipientID = new RecipientID();
CmsEnvelopedData decodedEnvelopeData = new CmsEnvelopedData(encodedData);
RecipientInformation recipient = decodedEnvelopeData.GetRecipientInfos().GetFirstRecipient(recipientID);
byte[] data2 = recipient.GetContent(encryptionKey);
CollectionAssert.AreEqual(data, data2);
}
What am I doing wrong? What would be the correct way to write this?
To add an HMAC to a CMS message, you would have to use a AuthenticatedData-structure.
I am not especially familiar with Bouncy Castle, but from a cursory look at the API, I would say that it does not support AuthenticatedData. In fact, it looks like it only supports SignedData for authentication.
So your options seems to be:
Use another library (or write your own code) to handle the AuthenticatedData-structure.
Calculate the HMAC and provide it in a non-standard way (in a proprietary Attribute or out-of-band).
Use SignedData with an RSA key pair instead.
I'm posting this in the hope it saves somebody else the hours I lost on this really stupid problem involving converting formats of public keys. If anybody sees a simpler solution or a problem, please let me know!
The eCommerce system I'm using sends me some data along with a signature. They also give me their public key in .pem format. The .pem file looks like this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDe+hkicNP7ROHUssGNtHwiT2Ew
HFrSk/qwrcq8v5metRtTTFPE/nmzSkRnTs3GMpi57rBdxBBJW5W9cpNyGUh0jNXc
VrOSClpD5Ri2hER/GcNrxVRP7RlWOqB1C03q4QYmwjHZ+zlM4OUhCCAtSWflB4wC
Ka1g88CjFwRw/PB9kwIDAQAB
-----END PUBLIC KEY-----
Here's the magic code to turn the above into an "RSACryptoServiceProvider" which is capable of verifying the signature. Uses the BouncyCastle library, since .NET apparently (and appallingly cannot do it without some major headaches involving certificate files):
RSACryptoServiceProvider thingee;
using (var reader = File.OpenText(#"c:\pemfile.pem"))
{
var x = new PemReader(reader);
var y = (RsaKeyParameters)x.ReadObject();
thingee = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
var pa = new RSAParameters();
pa.Modulus = y.Modulus.ToByteArray();
pa.Exponent = y.Exponent.ToByteArray();
thingee.ImportParameters(pa);
}
And then the code to actually verify the signature:
var signature = ... //reads from the packet sent by the eCommerce system
var data = ... //reads from the packet sent by the eCommerce system
var sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
byte[] bSignature = Convert.FromBase64String(signature);
///Verify signature, FINALLY:
var hasValidSig = thingee.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), bSignature);
Potential problem: using Encoding.ASCII.GetBytes(data) is almost certainly the wrong way to get the hash. That means they can only send a hash which doesn't have any high bits set.
If this is in a "packet" you should get the raw data from the packet as a byte array. If it is represented as text, it should be in some encoded form - e.g. hex or base64. What does the hash look like?