hash_hmac с 3 параметрами в php, эквивалент csharp, javascript

ОПИСАНИЕ:

Кажется, я не могу понять, как PHP производит следующее:

echo hash_hmac("sha1", "what is this", true);
echo PHP_EOL; // end of line
echo base64_encode(hash_hmac("sha1", "what is this", true));

Ссылка для просмотра вывода в Интернете (необходимо скопировать/вставить).

Как сказано в документации, вам нужны данные и ключ с надлежащим выводом для создания хэша SHA1 HMAC.

string hash_hmac(string $algo, string $data, string $key [, bool $raw_output = false])

Я хочу создать точный вывод с помощью csharp и javascript.


ПЫТАЛИСЬ:

Это нормально, когда у меня есть данные и ключ, и я могу создать один и тот же хэш SHA1 HMAC на csharp и javascript.

// PHP
echo base64_encode(hash_hmac("sha1", "data", "key", true));

Ссылка для просмотра вывода в Интернете (необходимо скопировать/вставить).

// CSharp
public static void Main(string[] args)
{
    Console.WriteLine(CreatePhpSha1HmacHash("data", "key"));
}

public static string CreatePhpSha1HmacHash(string data, string key)
{
    if (data == null)
    {
        data = string.Empty;
    }

    var encoding = new System.Text.UTF8Encoding(); // It's UTF-8 for my example

    var keyBytes = encoding.GetBytes(key);
    var dataBytes = encoding.GetBytes(data);

    using (var hmac = new System.Security.Cryptography.HMACSHA1(keyBytes))
    {
        var hash = hmac.ComputeHash(dataBytes);

        return Convert.ToBase64String(hash);
    }
}

Ссылка для просмотра выходных данных в Интернете (необходимо скопировать/вставить).

// Javascript
var hash = CryptoJS.HmacSHA1('data', 'key');
var base64 = CryptoJS.enc.Base64.stringify(hash);

console.log('Sha1 hmac hash: ' + base64);

Ссылка для просмотра вывода в Интернете.


ВОПРОС:

Как я могу создать точный вывод в виде примера php, показанного в описании, если он не использует два обязательных параметра? Может кто-нибудь объяснить мне, что делает php в этом случае?


ОТВЕТ:

@GentlemanMax: PHP внутренне преобразует TRUE в STRING, поэтому KEY будет преобразован в "1" как строковое значение. Когда для параметра raw_output установлено значение TRUE, он выводит необработанные двоичные данные. FALSE выводит шестнадцатеричные символы нижнего регистра.


РЕШЕНИЕ:

// CSharp
public static void Main(string[] args)
{
    // echo base64_encode(hash_hmac("sha1", "what is this", true));
    // echo base64_encode(hash_hmac("sha1", "what is this", true, false));
    Console.WriteLine(ToBase64EncodedHmacSha1("what is this", "1", false));
    Console.WriteLine(ToBase64EncodedHmacSha1("what is this", "1", false.ToString()));

    // echo base64_encode(hash_hmac("sha1", "what is this", true, true));
    Console.WriteLine(ToBase64EncodedHmacSha1("what is this", "1", true));
    Console.WriteLine(ToBase64EncodedHmacSha1("what is this", "1", true.ToString()));
}

public static string ToBase64EncodedHmacSha1(string data, string key, bool rawOutput = false)
{
    bool result;

    if (bool.TryParse(key, out result))
    {
        key = result ? 1.ToString() : 0.ToString();
    }

    var keyBytes = Encoding.UTF8.GetBytes(key);
    var dataBytes = Encoding.UTF8.GetBytes(data);

    using (var hmac = new HMACSHA1(keyBytes))
    {
        var hash = hmac.ComputeHash(dataBytes);

        if (rawOutput)
        {
            // output: raw binary
            return Convert.ToBase64String(hash);
        }

        // Convert an array of bytes to a string of hex digits.
        var hex = string.Concat(hash.Select(x => x.ToString("x2").ToLower()));

        var hexBytes = Encoding.UTF8.GetBytes(hex);

        // output: lowercase hexits
        return Convert.ToBase64String(hexBytes);
    }
}

Ссылка для просмотра выходных данных в Интернете (необходимо скопировать/вставить).


// Javascript 
function toBase64EncodedHmacSha1(data, key, rawOutput) {
    // if boolean, cast to string
    if (typeof(key) === 'boolean') {
        key = key ? '1' : '0';
    }

    // optional
    if (typeof(rawOutput) === 'undefined') {
        rawOutput = false;
    }

    // check type
    if (typeof(rawOutput) !== 'boolean') {
        throw new Error('Raw output is Boolean value: true/false');
    }

    var hash = CryptoJS.HmacSHA1(data, key);

    if (rawOutput) {
        // output: raw binary
        return CryptoJS.enc.Base64.stringify(hash);
    }

    var hex = CryptoJS.enc.Hex.stringify(hash);
    var wordArray = CryptoJS.enc.Utf8.parse(hex);

    // output: lowercase hexits
    return CryptoJS.enc.Base64.stringify(wordArray);
}

// echo base64_encode(hash_hmac("sha1", "what is this", true));
// echo base64_encode(hash_hmac("sha1", "what is this", true, false));
console.log(toBase64EncodedHmacSha1('what is this', true));
console.log(toBase64EncodedHmacSha1('what is this', true, false));

// echo base64_encode(hash_hmac("sha1", "what is this", true, true));
console.log(toBase64EncodedHmacSha1('what is this', true, true));

console.log(toBase64EncodedHmacSha1('what is this', true, 'This will throw error'));

Ссылка для просмотра вывода в Интернете.


person Admir    schedule 11.08.2017    source источник


Ответы (1)


Ключевым выводом здесь является то, что PHP будет внутренне приводить true к строке. В php true приводит к "1", поэтому

hash_hmac("sha1", "data", true);

Точно эквивалентно

hash_hmac("sha1", "data", "1")

Если вы не передадите 4-й параметр в hash_hmac, он выводит хэш в шестнадцатеричном формате. Это не то, что вы делаете в своем С# или javascript. Вот некоторые эквиваленты, с которыми вы можете работать:

//PHP
hash_hmac("sha1", "data", true)

будет выводиться так же, как

//JS
var hash = CryptoJS.HmacSHA1('data', "1")
console.log ( CryptoJS.enc.Hex.stringify(hash) ); //Note .Hex instead of .Base64

Сходным образом,

//PHP
base64_encode(hash_hmac("sha1", "data", true, true));

это то же самое, что делать

//JS
var hash = CryptoJS.HmacSHA1('data', "1")
console.log ( CryptoJS.enc.Base64.stringify(hash) );

Кроме того, PHP попытается преобразовать все нестроковые значения для $key в строку. Вы всегда можете проверить, к чему что-то приводится, вызвав strval($key), чтобы увидеть, что вы на самом деле используете для ключа.

person TheGentleman    schedule 11.08.2017