Having trouble with AWS4 Signature tutorial, hash doesn't match example - c#

I'm working through the tutorial on AWS, trying to calculate the Authorization header and I'm stuck. (Tutorial here: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html)
I've narrowed down my problem to a step at the end of task 3. I can create the signing key as they described and get the same result as they do,
c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9
I can calculate the stringToSign as they describe and I get a matching result,
AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
But when I try to sign the string my result doesn't match their result.
var kha = KeyedHashAlgorithm.Create("HMACSHA256");
kha.Key = Encoding.UTF8.GetBytes("c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9");
var sts = "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/iam/aws4_request\nf536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59";
var signature = HexEncode(kha.ComputeHash(Encoding.UTF8.GetBytes(sts)));
When I run this my signature comes out as
fe52b221b5173b501c9863cec59554224072ca34c1c827ec5fb8a257f97637b1
but they say it should be
5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
In task 2 I run my HexEncode function as part of creating the HashedCanonicalRequest and that is coming out fine so I don't think it is that function but here it is just in case:
private static string HexEncode(byte[] data, bool lowercase = true)
{
var sb = new StringBuilder();
for (var i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString(lowercase ? "x2" : "X2"));
}
return sb.ToString();
}
I've tried various ways of writing the sts like using
#"AWS4-HMAC-SHA256
20150830T123600Z
20150830/us-east-1/iam/aws4_request
f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59"
instead of using \n but nothing has worked. I also read through a few of the other postings here on SO but none of those seemed to help either.
Update:
I created this fiddle just to prove to myself that it isn't something environmental but it gets the same answer as my local code.
https://dotnetfiddle.net/A5mVp9

So it turns out that using
kha.Key = Encoding.UTF8.GetBytes("c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9");
is incorrect. That string is hex encoded (because that's what it says to do in the tutorial) but you are supposed to use the byte-array version and not hex encode it. They showed the hex encoded just for display purposes but didn't do a good job of saying to use the regular byte array and DO NOT HEX ENCODE IT! Anyways, that's what solves this.
If you want to see it in action, write a hex decoder:
public static byte[] DecodeHex(string hex)
{
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;
}
and hex decode the string I listed and use that byte array in the hashing.
kha.Key = DecodeHex("c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9");

Related

Decoding 'code string' to UTF8 and string

First, sorry about my knowledge ...
Above all I have string type value %B3%F3%C7%F9.
Since I receive it from other processor, I don't know how it made... (just I receive this string)
What I only know are
this is something encoded Korean language (I guess it is 농협)
the encode method is one of utf-8 or euc-kr
What I wnat to do is to decode this strange and coded string to utf-8 string.
(for example, decode %B3%F3%C7%F9 to 농협 and assign it string type variable)
Thanks for your attention
(I'm working in ASP.NET Core 1.1)
Your % values are basically URL encoding, so %F9 represents a byte value of 249, for example.
So the first thing you need to do is convert this into a byte array. I've done this a potentially inefficient way in my example. Once you've done that, you need to convert that byte array into a string using the EUC-KR encoding type.
public static void Main()
{
string data = "%B3%F3%C7%F9";
byte[] bData = new byte[data.Length / 3];
for (int i = 0; i < data.Length; i += 3)
{
int pos = i / 3;
bData[pos] = Convert.ToByte(data.Substring(i + 1, 2), 16);
}
data = System.Text.Encoding.GetEncoding("euc-kr").GetString(bData);
Console.WriteLine(data);
}
Fiddle

Creating ASN1 encoded signature in C# to send to Java

I have a private/public secure cert. My Java counterparts have the public key. I have the need to take a string, sign it, and send it along to Java to then verify the data and signature.
There appears to be a well known issue with how Microsoft and the rest of the world encodes/signs data, something about the way bytes are handled. It's so well known, that I can't find a solution. If they take my string and the private key, they can obviously sign it correctly, and verify it. If I take my string, I can sign and verify it within .Net fine. I have seen a slew of methods for converting from ASN1 to Microsoft's format (I think P1363), but not converting from Microsoft, C#, to ASN1 for Java. I don't what is going on well enough to understand how to reverse engineer.
I've explored http://www.codeproject.com/Articles/25487/Cryptographic-Interoperability-Keys but the final result wasn't what the java side needed. I can sign a string, and I get a signature, but Java guys are telling me it needs to start with MC, first bytes are indicators. I am not seeing this.
Thanks!
A solution has been found, and looks like some of the other examples I've been seeing, but for some reason this works better: (method named after the guy who solved it for me ;)
private static byte[] Rays(byte[] sigBytes)
{
bool highMsbR = (sigBytes[0] & 0x80) != 0;
bool highMsbS = (sigBytes[20] & 0x80) != 0;
MemoryStream stream = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((byte)0x30);
int len = 44 + (highMsbR ? 1 : 0) + (highMsbS ? 1 : 0);
writer.Write((byte)len);
// r
writer.Write((byte)0x02);
writer.Write((byte)(highMsbR ? 21 : 20));
if (highMsbR)
writer.Write((byte)0);
for (int i = 0; i < 20; i++)
writer.Write(sigBytes[i]);
// s
writer.Write((byte)0x02);
writer.Write((byte)(highMsbS ? 21 : 20));
if (highMsbS)
writer.Write((byte)0);
for (int i = 20; i < 40; i++)
writer.Write(sigBytes[i]);
}
byte[] bytes = stream.ToArray();
return bytes;
}

How to get character code at < 126

I'm simply creating a 256 byte array in my server-side application and then sending it to client.
C#:
byte[] arr = new byte[256];
for (int i = 0; i < 256;i++ )
{
arr[i] = (byte)i;
}
and then I want to get all character codes (exactly, byte codes from characters) in client-side with JavaScript.
JavaScript:
for(var i = 0;i<data.length;i++) {
console.log(data.charCodeAt(i));
}
The characters after 126, charCodeAt(...) returns 65536.
Exactly I want to know how can I get this character codes after 126?
There are some very good tips on how to parse binary data using charCodeAt in this blog post:
http://fhtr.blogspot.com/2009/12/3d-models-and-parsing-binary-data-with.html
You can also use jDataView if you want to easily read binary data in JavaScript:
http://blog.vjeux.com/2011/javascript/jdataview-read-binary-file.html

Search ReadAllBytes for specific values

I am writing a program that reads '.exe' files and stores their hex values in an array of bytes for comparison with an array containing a series of values. (like a very simple virus scanner)
byte[] buffer = File.ReadAllBytes(currentDirectoryContents[j]);
I have then used BitConverter to create a single string of these values
string hex = BitConverter.ToString(buffer);
The next step is to search this string for a series of values(definitions) and return positive for a match. This is where I am running into problems. My definitions are hex values but created and saved in notepad as defintions.xyz
string[] definitions = File.ReadAllLines(#"C:\definitions.xyz");
I had been trying to read them into a string array and compare the definition elements of the array with string hex
bool[] test = new bool[currentDirectoryContents.Length];
test[j] = hex.Contains(definitions[i]);
This IS a section from a piece of homework, which is why I am not posting my entire code for the program. I had not used C# before last Friday so am most likely making silly mistakes at this point.
Any advice much appreciated :)
It is pretty unclear exactly what kind of format you use of the definitions. Base64 is a good encoding for a byte[], you can rapidly convert back and forth with Convert.ToBase64String and Convert.FromBase64String(). But your question suggests the bytes are encoded in hex. Let's assume it looks like "01020304" for a new byte[] { 1, 2, 3, 4}. Then this helper function converts such a string back to a byte[]:
static byte[] Hex2Bytes(string hex) {
if (hex.Length % 2 != 0) throw new ArgumentException();
var retval = new byte[hex.Length / 2];
for (int ix = 0; ix < hex.Length; ix += 2) {
retval[ix / 2] = byte.Parse(hex.Substring(ix, 2), System.Globalization.NumberStyles.HexNumber);
}
return retval;
}
You can now do a fast pattern search with an algorithm like Boyer-Moore.
I expect you understand that this is a very inefficient way to do it. But except for that, you should just do something like this:
bool[] test = new bool[currentDirectoryContents.Length];
for(int i=0;i<test.Length;i++){
byte[] buffer = File.ReadAllBytes(currentDirectoryContents[j]);
string hex = BitConverter.ToString(buffer);
test[i] = ContainsAny(hex, definitions);
}
bool ContainsAny(string s, string[] values){
foreach(string value in values){
if(s.Contains(value){
return true;
}
}
return false;
}
If you can use LINQ, you can do it like this:
var test = currentDirectoryContents.Select(
file=>definitions.Any(
definition =>
BitConverter.ToString(
File.ReadAllBytes(file)
).Contains(definition)
)
).ToArray();
Also, make sure that your definitions-file is formatted in a way that matches the output of BitConverter.ToString(): upper-case with dashes separating each encoded byte:
12-AB-F0-34
54-AC-FF-01-02

C# Create an Auth Token from Guid combined with 40Char Hex string (UUID)

I am writing an asp.net MVC app that drives an IPhone application.
I want the Iphone to send me its UUID looks like this:
2b6f0cc904d137be2e1730235f5664094b831186
On the server I want to generate a Guid:
466853EB-157D-4795-B4D4-32658D85A0E0
On both the Iphone and the Server I need a simple aglorithm to combine these 2 values into an Auth token that can be passed around. Both the IPhone and the ASP.NET MVC app need to be able to compute the value over and over based on the UUID and the GUID.
So this needs to be a simple algorithm with no libraries from the .net framework.
Full Solution Here
public void Test()
{
var DeviceId = Guid.NewGuid();
var newId = "2b6f0cc904d137be2e1730235f5664094b831186";
var guidBytes = DeviceId.ToByteArray();
var iphoneBytes = StringToByteArray(newId);
byte[] xor = new byte[guidBytes.Length];
for (int i=0;i<guidBytes.Length;i++)
{
xor[i] = (byte) (guidBytes[i] ^ iphoneBytes[i]);
}
var result = ByteArrayToString(xor);
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
Well, the iPhone ID looks like a hex string, so converting both to binary and XORing the bytes ought to do it. You could store the result as an array, hex string, or base-64 encoded string as appropriate.
The way you refer to this as an "auth token" is a little concerning, however. Session ids must be unpredictable. You might consider generating an array of cryptographically random data on the server instead of a GUID.
Edit
// Convert the server GUID to a byte array.
byte[] guidBytes = severGuid.ToByteArray();
// Convert the iPhone device ID to an array
byte[] idBytes = StringToByteArray(iPhoneId);
Sadly, it seems .NET doesn't have a built-in method to convert to/from hex strings, but this subject has been covered before: Convert byte array to hex string and vice versa
// Once you've XORed the bytes, conver the result to a string.
string outputString = ByteArrayToString(outputBytes);
Just as a side note, all the "auth token" mechanisms I've worked with (at least) concatenated a constant value (a "secret") with the current time, then hashed them together then sent the hash and the date. The server then reconstructed the hash from the received date and known "secret" and then compared to the received hash (signature).
My point here was "concatenated with date" - this allows the resulting signature to be different every time which in theory should be more secure.
Rather than XORing, which loses information, you could just concatenate these hex digits.
Why do you even need the GUID? The phone ID is unique, the GUID seems to add no value.
I thought you can use two way algorithm. It mean the algorithm can be encode and decode like Base64, SHA256, AES

Categories