2

I'm using HMAC exactly as intended to verify the integrity of a message. However, the message is really an associative array (or a hash).

Since this will be done on various platforms (within and outside our control), we need a standard way to convert the array to a string.

I've seen pipes being used as separators in many places. This vulnerability in AWS is the kind of thing I wanna avoid.

Say, my message is {a:1,b:2}, would converting it to a1b2 be fine?

Or should I go for something like 1|2 (Then the key order becomes important).

Another solution would have been JSON conversion, but JSON doesn't guarantee key order, so it may give different results in different libraries.

Various ideas we are discussing:

data = {:c=>3,:a=>1,:b=>2}
data.sort.join
"a1b2c3"
data.values.sort.join
"123"
data.sort.join('|')
"a|1|b|2|c|3"

I'm inclined towards the first or the third choice, but are there any ways I can judge my approach?

Nemo
  • 1,567
  • 1
  • 13
  • 11
  • 1
    The only requirement I am aware of is that each unique associative array must map onto a *single*, *unique* byte representation. – Stephen Touset Feb 04 '15 at 08:41
  • What would be the best way of making sure that happens? – Nemo Feb 04 '15 at 08:42
  • There is no "best" way, insofar as there are only ways that satisfy that requirement, and there are ways that don't. I'd suggest any method is "best" that is *obviously* correct and, secondarily, produces the smallest inputs to the HMAC function (to reduce the number of calls to the underlying compression function and therefore maximizing performance). – Stephen Touset Feb 04 '15 at 19:36

1 Answers1

1

You could encode like this:

x1key1y1data1x2key2y2data2

Where x1 is the lenght of the key, and y1 is the lenght of the data.

This way you ensure that the keys are in the same order, and you can put any binary data on it. Just define a limit for the key and data lenght, and use padding to make sure x and y uses the same lenght:

004key1005test1002k1025long random binaŕy śtring

You don't need to care about separators, json or anything. And you can decode the string with a PHP snippet like this:

$data = "004key1005test1002k1025long random binary string";
$len = 3; // up to 999 bytes of data
$start=0;

while ($start < strlen($data) - $len) {
        $stringSize=intval(substr($data, $start, $len));
        echo "String size: $stringSize\n";
        $stringData = substr($data, $start + $len, $stringSize);
        echo "String data: $stringData \n";
        $start += $len + $stringSize;
}

The execution will show this:

String size: 4
String data: key1 
String size: 5
String data: test1 
String size: 2
String data: k1 
String size: 25
String data: long random binary string 
ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
  • actually in order to ensure order you need to sort it by key with a fixed comparator. And remeber to also specify the encoding. Personally I would concatenate zero terminated UTF8 bytes (if \0 cannot occur in data). – eckes Feb 04 '15 at 22:02