Как реализовать concat KDF для использования с JOSE / JWE / JWT

Я пытаюсь написать код для расшифровки токена JWE в PHP, так как существующие библиотеки не поддерживают нужный мне алгоритм (A128CBC+HS256Это устаревший алгоритм).

Моя проблема в том, что я не могу понять, как сгенерировать ключ шифрования контента, который использует «Ключ конкатенации»
Функция деривации »(см. Раздел 5.8.1 здесь: http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf). Символы и объяснение функции идут над моей головой.

Я получаю свои ценности на основе JOSE JSON наброски веб-алгоритмов 06.

Пока что соответствующая часть моего кода выглядит так:

// Derive CBC encryption & integrity keys
$shaSize = 256;
$encryptionKeySize = $shaSize / 2;
$integrityKeySize = $shaSize;

// Calculate the key derivation using Concat KDF for the content
// encryption key
$encryptionSegments = [
$masterKey,         // Z
$encryptionKeySize, // keydatalen
$this->packInt32sBe($encryptionKeySize) . utf8_encode('A128CBC+HS256'), // AlgorithmID
$this->packInt32sBe(0), // PartyUInfo
$this->packInt32sBe(0), // PartyUInfo
'Encryption',           // SuppPubInfo
$this->packInt32sBe(1), // SuppPrivInfo
];

// Calculate the SHA256 digest
$cek = hex2bin(hash('sha256', implode('', $encryptionSegments)));

Возможно актуально, моя функция для получения большого числа с прямым порядком байтов:

public function packInt32sBe($n)
{
if (pack('L', 1) === pack('N', 1)) {
return pack('l', $n);
}

return strrev(pack('l', $n));
}

Единственная переменная, не показанная здесь, $masterKey который является расшифрованным главным ключом контента.

1

Решение

Я закончил тем, что решил это. Не уверен, поможет ли это кому-нибудь еще, но на всякий случай:

// Derive CBC encryption & integrity keys
$shaSize = 256;
$encryptionKeySize = $shaSize / 2;
$integrityKeySize = $shaSize;

// Calculate the key derivation using Concat KDF for the content
// encryption key
$encryptionSegments = [
$this->packInt32sBe(1),
$cmk,                              // Z
$this->packInt32sBe($encryptionKeySize) . utf8_encode('A128CBC+HS256'), // AlgorithmID
$this->packInt32sBe(0), // PartyUInfo
$this->packInt32sBe(0), // PartyUInfo
'Encryption',           // SuppPubInfo
];

// Calculate the SHA256 digest, and then get the first 16 bytes of it
$cek = substr(hex2bin(hash('sha256', implode('', $encryptionSegments))), 0, 16);

Единственная неизвестная переменная здесь $cmk который является моим главным ключом содержимого, также называемым значением «Z». В этом конкретном случае я получил главный ключ, расшифровав его из запроса токена XBOX One.

3

Другие решения

Вот моя собственная реализация в соответствии с той же спецификацией, но проектом # 39:

<?php

class ConcatKDF
{
public static function generate($Z, $encryption_algorithm, $encryption_key_size, $apu = "", $apv = "")
{
$encryption_segments = array(
self::toInt32Bits(1),                                                   // Round number 1
$Z,                                                                     // Z (shared secret)
self::toInt32Bits(strlen($encryption_algorithm)).$encryption_algorithm, // Size of algorithm and algorithm
self::toInt32Bits(strlen($apu)).$apu,                                   // PartyUInfo
self::toInt32Bits(strlen($apv)).$apv,                                   // PartyVInfo
self::toInt32Bits($encryption_key_size),                                // SuppPubInfo (the encryption key size)
"",                                                                     // SuppPrivInfo
);

return substr(hex2bin(hash('sha256', implode('', $encryption_segments))), 0, $encryption_key_size/8);
}

private static function toInt32Bits($value)
{
return hex2bin(str_pad(dechex($value), 8, "0", STR_PAD_LEFT));
}
}

Использование очень просто:

ConcatKDF::generate("The shared key here", 'A128CBC+HS256', 128);

Если у вас есть параметры apu и apv:

ConcatKDF::generate("Another shared key here", 'A128GCM', 128, "Alice", "Bob");
1

По вопросам рекламы [email protected]