web-token / jwt-framework

JWT Framework
MIT License
888 stars 105 forks source link

HMAC: Invalid key length. #294

Closed jbelien closed 3 years ago

jbelien commented 3 years ago

Describe the bug

Hello, I'm trying to upgrade to version 2.2.

Following documentation,
I replaced (source)

$jwk = JWK::create([
  'kty' => 'oct',
  'k'   => $this->privateKey,
  'use' => 'sig',
]);

by

$jwk = JWKFactory::createFromSecret($this->privateKey, [
  'alg' => 'HS256',
  'use' => 'sig',
]);

and replaced (source)

$jsonConverter = new StandardConverter();

$payload = $jsonConverter->encode([
  'aud' => 'GEO-6 API',
  'iat' => time(),
  'iss' => sprintf('geocoder-php-%s', $this->getName()),
  'sub' => $this->clientId,
]);

$algorithmManager = new AlgorithmManager([ new HS512() ]);
$jwsBuilder = new JWSBuilder(
  $jsonConverter,
  $algorithmManager
);

$jws = $jwsBuilder
  ->create()
  ->withPayload($payload)
  ->addSignature($jwk, ['alg' => 'HS512', 'typ' => 'JWT'])
  ->build();

return (new CompactSerializer($jsonConverter))->serialize($jws);

by

$payload = json_encode([
  'aud' => 'GEO-6 API',
  'iat' => time(),
  'iss' => sprintf('geocoder-php-%s', $this->getName()),
  'sub' => $this->clientId,
]);

$algorithmManager = new AlgorithmManager([ new HS512() ]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$jws = $jwsBuilder
  ->create()
  ->withPayload($payload)
  ->addSignature($jwk, ['alg' => 'HS512', 'typ' => 'JWT'])
  ->build();

return (new CompactSerializer())->serialize($jws, 0);

but I now have the following error : "InvalidArgumentException: Invalid key length."


To Reproduce

Steps (from the documentation) to reproduce the behavior:

  1. Create a key with JWKFactory::createFromSecret
    $jwk = JWKFactory::createFromSecret(
    'My Secret Key',       // The shared secret
    [                      // Optional additional members
        'alg' => 'HS256',
        'use' => 'sig'
    ]
    );
  2. Create a signed token with (new JWSBuilder())->build()
    
    // The algorithm manager with the HS256 algorithm.
    $algorithmManager = new AlgorithmManager([
    new HS256(),
    ]);

// We instantiate our JWS Builder. $jwsBuilder = new JWSBuilder($algorithmManager);

// The payload we want to sign. The payload MUST be a string hence we use our JSON Converter. $payload = json_encode([ 'iat' => time(), 'nbf' => time(), 'exp' => time() + 3600, 'iss' => 'My service', 'aud' => 'Your application', ]);

$jws = $jwsBuilder ->create() // We want to create a new JWS ->withPayload($payload) // We set the payload ->addSignature($jwk, ['alg' => 'HS256']) // We add a signature with a simple protected header ->build(); // We build it

3. See the error

PHP Fatal error: Uncaught InvalidArgumentException: Invalid key length. in vendor/web-token/jwt-signature-algorithm-hmac/HS256.php:38 Stack trace:

0 vendor/web-token/jwt-signature-algorithm-hmac/HMAC.php(36): Jose\Component\Signature\Algorithm\HS256->getKey()

1 vendor/web-token/jwt-signature/JWSBuilder.php(170): Jose\Component\Signature\Algorithm\HMAC->hash()

2 test.php(40): Jose\Component\Signature\JWSBuilder->build()

3 {main}

thrown in vendor/web-token/jwt-signature-algorithm-hmac/HS256.php on line 38



**Expected behavior**

Creation of of valid JWS.

**Additional context**

I tried on both PHP 7.4 and PHP 8.0.
I tried with both `HS256` and `HS512` algorithms.
Spomky commented 3 years ago

Hi,

The problem comes from the size of your key My Secret Key. As per the RFC7518 section-3.2, the key size for the SHA-256 function must be at least 256 bits.

A key of the same size as the hash output (for instance, 256 bits for "HS256") or larger MUST be used with this algorithm. (This requirement is based on Section 5.3.4 (Security Effect of the HMAC Key) of NIST SP 800-117 [NIST.800-107], which states that the effective security strength is the minimum of the security strength of the key and two times the size of the internal hash value.)

jbelien commented 3 years ago

Oh, you're absolutely right !

I got confused because it was working just fine with version 1.x (but apparently it didn't check if the key was valid or not). Also got confused with the example in the documentation where I understood that any string (like My Secret Key) could be used.

Is there a way to use any "random" string as a secret (like My Secret Key) ?

Spomky commented 3 years ago

Correct.I will update the documentation as it is not really clear on that point.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 7 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.