Hmac a sha256 v kombinaci s češtinou (unicode)

Při psaní přihlašování, kde jsem chtěl používat hmac, aby se neposílalo heslo v plain textu, jsem si náhodou všiml, že mi nesedí výsledný hash_hmac, když se v hesle vyskytne znak specifický pro českou abecedu. Prekérní situace… 😎

Drobný příklad, mějme řetězec a klíč.

řetězec:
ščřžýáá je to na nic 123456
klíč:
TLr8zA75tI1q3Jo

php (běžně používané funkce):

hash(sha256) = 8af726e3c15be3687de0b13102667701994323832bb252503f841bf3d3722e34
hash_hmac(sha256) = d39a1c610d009f1f1f569800fc4d74ac8d27a8b8e2011b526bf886f7a066fec1

jquery plugin pro sha256 (jquery.sha256.min.js):

hash(sha256) = 723f6dd8d04fe3ac3f268f1d6b9a938a778ad71d6f699de968206ad4c5909bdf
hash_hmac(sha256) = 83a2bdbd3ba93279fa94c76d31ed506d132f167fc46e4dd203b84ea7e861cf1a

Problém je na světě, ono to nesedí. Hledal jsem i jinou implementaci a přes Wikipedii našel…

javascript (implementace například z http://jssha.sourceforge.net/):

hash(sha256) = 723f6dd8d04fe3ac3f268f1d6b9a938a778ad71d6f699de968206ad4c5909bdf
hash_hmac(sha256) = 83a2bdbd3ba93279fa94c76d31ed506d132f167fc46e4dd203b84ea7e861cf1a

Opět jsou výsledky různé. Stejně jsem kvůli „českým znakům“ potřeboval pracovat s řetězci v Unicodu a ne ASCII, jak nabízí php u funkcí hash a hash_hmac. A hlavně jsem potřeboval v javascriptové i phpčkové části dostávat stejné výsledky.

Implementace sha256 pro php, která umí pracovat s Unicode, se dala najít na internetu celkem snadno – zde, takže stačilo jen ověřit chování. Nastavit pro práci s Unicode ($chrsz = 16;) a doplnit o hmac:

function muj_sha256_hmac($key, $data)
{
  $blocksize = 64;
  if (strlen($key) > $blocksize)
  {
    $key = muj_sha256($key);
  }
  else if (strlen($key) < $blocksize)
  {
    $key = str_pad($key, $blocksize, chr(0x00));
  }
  $ipad = $key ^ str_repeat(chr(0x36), $blocksize);
  $opad = $key ^ str_repeat(chr(0x5C), $blocksize);
  return muj_sha256($opad . pack('H*', muj_sha256($ipad . $data)));
}

U javascriptu se muselo udělat trochu více, ale analogicky podle phpčkového skriptu. Poznámka jen pro budoucnost, až budu trojčit, že mi nesedí hashe :-).

Doplnění 1:

Všechno fungovalo krásně, dokud nedošlo na 64bitový server, protože pak jsem obdržel opět různé údaje. Přitom již minule stačilo php část vyřešit za pomoci mb_convert_encoding() a převést text na UTF-16LE.

hash('sha256', mb_convert_encoding('text v SHA256', 'UTF-16LE'));

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *