Skip to content

Commit

Permalink
Update of hmac encryption config values
Browse files Browse the repository at this point in the history
  • Loading branch information
tswagger committed Nov 22, 2023
1 parent 795a214 commit 2570a7c
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 90 deletions.
14 changes: 7 additions & 7 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,19 @@ protected function redirectToDeniedUrl(): RedirectResponse
#### Config\AuthToken

If you are using the HMAC authentication you need to update the encryption settings in **app/Config/AuthToken.php**.
You will need to update and set the encryption key `$hmacEncryption['key']`. This should be set using **.env** and/or system
environment variables. Instructions on how to do that can be found in the
You will need to update and set the encryption key in `$hmacEncryptionKeys`. This should be set using **.env** and/or
system environment variables. Instructions on how to do that can be found in the
[Setting Your Encryption Key](https://codeigniter.com/user_guide/libraries/encryption.html#setting-your-encryption-key)
section of the CodeIgniter 4 documentation and in [HMAC SHA256 Token Authenticator](./docs/references/authentication/hmac.md#hmac-secret-key-encryption).

You also may wish to adjust the default Driver `$hmacEncryption['driver']` and the default Digest `$hmacEncryption['digest']`,
these currently default to `'OpenSSL'` and `'SHA512'` respectively.
You also may wish to adjust the default Driver `$hmacEncryptionDefaultDriver` and the default Digest
`$hmacEncryptionDefaultDigest`, these currently default to `'OpenSSL'` and `'SHA512'` respectively.

#### Encrypt Existing Keys

After updating the `$hmacEncryption['key']` value, you will need to run `php spark shield:hmac encrypt` in order to encrypt
any existing HMAC tokens. This only needs to be run if you have existing unencrypted HMAC secretKeys in stored in the
database.
After updating the key in `$hmacEncryptionKeys` value, you will need to run `php spark shield:hmac encrypt` in order
to encrypt any existing HMAC tokens. This only needs to be run if you have existing unencrypted HMAC secretKeys in
stored in the database.

## Version 1.0.0-beta.6 to 1.0.0-beta.7

Expand Down
8 changes: 4 additions & 4 deletions docs/guides/api_hmac_keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ $user->revokeAllHmacTokens();
## HMAC Secret Key Encryption

The HMAC Secret Key is stored encrypted. Before you start using HMAC, you will need to set/override the encryption key
`$hmacEncryption['key']` in **app/Config/AuthToken.php**. This should be set using **.env** and/or system environment variables.
Instructions on how to do that can be found in the
in `$hmacEncryptionKeys` in **app/Config/AuthToken.php**. This should be set using **.env** and/or system
environment variables. Instructions on how to do that can be found in the
[Setting Your Encryption Key](https://codeigniter.com/user_guide/libraries/encryption.html#setting-your-encryption-key)
section of the CodeIgniter 4 documentation.

You will also be able to adjust the default Driver `$hmacEncryption['driver']` and the default Digest
`$hmacEncryption['digest']`, these default to `'OpenSSL'` and `'SHA512'` respectively.
You will also be able to adjust the default Driver `$hmacEncryptionDefaultDriver` and the default Digest
`$hmacEncryptionDefaultDigest`, these default to `'OpenSSL'` and `'SHA512'` respectively.

See [HMAC SHA256 Token Authenticator](../references/authentication/hmac.md#hmac-secret-key-encryption) for additional
details on setting these values.
Expand Down
61 changes: 30 additions & 31 deletions docs/references/authentication/hmac.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,47 +160,48 @@ if ($user->hmacTokenCant('forums.manage')) {
## HMAC Secret Key Encryption

The HMAC Secret Key is stored encrypted. Before you start using HMAC, you will need to set/override the encryption key
`$hmacEncryption['key']` in **app/Config/AuthToken.php**. This should be set using **.env** and/or system environment variables.
Instructions on how to do that can be found in the
in `$hmacEncryptionKeys` in **app/Config/AuthToken.php**. This should be set using **.env** and/or system
environment variables. Instructions on how to do that can be found in the
[Setting Your Encryption Key](https://codeigniter.com/user_guide/libraries/encryption.html#setting-your-encryption-key)
section of the CodeIgniter 4 documentation.

You will also be able to adjust the default Driver `$hmacEncryption['driver']` and the default Digest
`$hmacEncryption['digest']`, these default to `'OpenSSL'` and `'SHA512'` respectively. All three properties (`$hmacEncryption['key']`,
`$hmacEncryption['driver']`, and `$hmacEncryption['digest']`) are set in array format (see below).
You will also be able to adjust the default Driver `$hmacEncryptionDefaultDriver` and the default Digest
`$hmacEncryptionDefaultDigest`, these default to `'OpenSSL'` and `'SHA512'` respectively. These can also be
overridden for an individual key by including them in the keys array.

```php
public array $hmacEncryption = [
'key' => [
'k1' => 'hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7',
public array $hmacEncryptionKeys = [
'k1' => [
'key' => 'hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7',
],
'driver' => ['k1' => 'OpenSSL'],
'digest' => ['k1' => 'SHA512'],
'currentKey' => 'k1',
];

public string $hmacEncryptionCurrentKey = 'k1';
public string $hmacEncryptionDefaultDriver = 'OpenSSL';
public string $hmacEncryptionDefaultDigest = 'SHA512';
```

When it is time to update your encryption keys you will need to add an additional key to the above arrays. Then adjust
the `$hmacEncryption['currentKey']` to point at the new key. After the new encryption key is in place, run
`php spark shield:hmac reencrypt` to re-encrypt all existing keys with the new encryption key. You will need to leave
the old key in the array as it will be used read the existing 'Secret Keys' during re-encryption.
When it is time to update your encryption keys you will need to add an additional key to the above
`$hmacEncryptionKeys` array. Then adjust the `$hmacEncryptionCurrentKey` to point at the new key. After the new
encryption key is in place, run `php spark shield:hmac reencrypt` to re-encrypt all existing keys with the new
encryption key. You will need to leave the old key in the array as it will be used read the existing 'Secret Keys'
during re-encryption.

```php
public array $hmacEncryption = [
'key' => [
'k1' => 'hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7',
'k2' => 'hex2bin:451df599363b19be1434605fff8556a0bbfc50bede1bb33793dcde4d97fce4b0',
],
'driver' => [
'k1' => 'OpenSSL',
'k2' => 'OpenSSL',
public array $hmacEncryptionKeys = [
'k1' => [
'key' => 'hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7',
],
'digest' => [
'k1' => 'SHA512',
'k2' => 'SHA512',
'k2' => [
'key' => 'hex2bin:451df599363b19be1434605fff8556a0bbfc50bede1bb33793dcde4d97fce4b0',
'digest' => 'SHA256',
],
'currentKey' => 'k2',
];

public string $hmacEncryptionCurrentKey = 'k2';
public string $hmacEncryptionDefaultDriver = 'OpenSSL';
public string $hmacEncryptionDefaultDigest = 'SHA512';

```

```console
Expand All @@ -211,10 +212,8 @@ You can (and should) set these values using environment variable and/or the **.e
the values as JSON strings:

```text
authtoken.hmacEncryption.key = '{"k1":"hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7","k2":"hex2bin:451df599363b19be1434605fff8556a0bbfc50bede1bb33793dcde4d97fce4b0"}'
authtoken.hmacEncryption.driver = '{"k1":"OpenSSL","k2":"OpenSSL"}'
authtoken.hmacEncryption.digest = '{"k1":"SHA512","k2":"SHA512"}'
authtoken.hmacEncryption.currentKey = k2
authtoken.hmacEncryptionKeys = '{"k1":{"key":"hex2bin:923dfab5ddca0c7784c2c388a848a704f5e048736c1a852c862959da62ade8c7"},"k2":{"key":"hex2bin:451df599363b19be1434605fff8556a0bbfc50bede1bb33793dcde4d97fce4b0"}}'
authtoken.hmacEncryptionCurrentKey = k2
```

Depending on the set length of the Secret Key and the type of encryption used, it is possible for the encrypted value to
Expand Down
4 changes: 1 addition & 3 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@
<env name="COMPOSER_DISABLE_XDEBUG_WARN" value="1"/>

<!-- Default HMAC encryption key -->
<env name="authtoken.hmacEncryption.key" value="{&quot;k1&quot;:&quot;hex2bin:178ed94fd0b6d57dd31dd6b22fc601fab8ad191efac165a5f3f30a8ac09d813d&quot;,&quot;k2&quot;:&quot;hex2bin:b0ab85bd0320824c496db2f40eb47c8712a6dfcfdf99b805988e22bdea6b9203&quot;}"/>
<env name="authtoken.hmacEncryption.driver" value="{&quot;k1&quot;:&quot;OpenSSL&quot;,&quot;k2&quot;:&quot;OpenSSL&quot;}"/>
<env name="authtoken.hmacEncryption.digest" value="{&quot;k1&quot;:&quot;SHA512&quot;,&quot;k2&quot;:&quot;SHA512&quot;}"/>
<env name="authtoken.hmacEncryptionKeys" value="{&quot;k1&quot;:{&quot;key&quot;:&quot;hex2bin:178ed94fd0b6d57dd31dd6b22fc601fab8ad191efac165a5f3f30a8ac09d813d&quot;},&quot;k2&quot;:{&quot;key&quot;:&quot;hex2bin:b0ab85bd0320824c496db2f40eb47c8712a6dfcfdf99b805988e22bdea6b9203&quot;}}"/>

<!-- Database configuration -->
<env name="database.tests.strictOn" value="true"/>
Expand Down
14 changes: 7 additions & 7 deletions src/Authentication/HMAC/HmacEncrypter.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function __construct()
{
$this->authConfig = config('AuthToken');

$this->getEncrypter($this->authConfig->hmacEncryption['currentKey']);
$this->getEncrypter($this->authConfig->hmacEncryptionCurrentKey);
}

/**
Expand Down Expand Up @@ -77,7 +77,7 @@ public function decrypt(string $encString): string
*/
public function encrypt(string $rawString): string
{
$currentKey = $this->authConfig->hmacEncryption['currentKey'];
$currentKey = $this->authConfig->hmacEncryptionCurrentKey;

$encryptedString = '$b6$' . $currentKey . '$' . base64_encode($this->encrypter[$currentKey]->encrypt($rawString));

Expand All @@ -101,7 +101,7 @@ public function isEncrypted(string $string): bool
*/
public function isEncryptedWithCurrentKey(string $string): bool
{
$currentKey = $this->authConfig->hmacEncryption['currentKey'];
$currentKey = $this->authConfig->hmacEncryptionCurrentKey;

return preg_match('/^\$b6\$' . $currentKey . '\$/', $string) === 1;
}
Expand All @@ -126,15 +126,15 @@ public function generateSecretKey(): string
private function getEncrypter(string $encrypterKey): EncrypterInterface
{
if (! isset($this->encrypter[$encrypterKey])) {
if (! isset($this->authConfig->hmacEncryption['key'][$encrypterKey])) {
if (! isset($this->authConfig->hmacEncryptionKeys[$encrypterKey]['key'])) {
throw new RuntimeException('Encryption key does not exist.');
}

$config = new Encryption();

$config->key = $this->authConfig->hmacEncryption['key'][$encrypterKey];
$config->driver = $this->authConfig->hmacEncryption['driver'][$encrypterKey];
$config->digest = $this->authConfig->hmacEncryption['digest'][$encrypterKey];
$config->key = $this->authConfig->hmacEncryptionKeys[$encrypterKey]['key'];
$config->driver = $this->authConfig->hmacEncryptionKeys[$encrypterKey]['driver'] ?? $this->authConfig->hmacEncryptionDefaultDriver;
$config->digest = $this->authConfig->hmacEncryptionKeys[$encrypterKey]['digest'] ?? $this->authConfig->hmacEncryptionDefaultDigest;

$this->encrypter[$encrypterKey] = Services::encrypter($config);
}
Expand Down
61 changes: 40 additions & 21 deletions src/Config/AuthToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,36 +76,55 @@ class AuthToken extends BaseAuthToken
* --------------------------------------------------------------------
* This sets the key to be used when encrypting a user's HMAC Secret Key.
*
* 'key' is an array of keys which will facilitate key rotation. Valid
* 'keys' is an array of keys which will facilitate key rotation. Valid
* keyTitles must include only [a-zA-Z0-9_] and should be kept to a
* max of 8 characters.
*
* 'driver' is used when encrypting HMAC Secret Key for storage.
* Available drivers:
* - OpenSSL
* - Sodium
*
* This is an array of drivers values. The keys MUST match and correlate
* to the 'key' array keys.
*
* 'digest' is used when encrypting HMAC Secret Key for storage.
* e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
*
* This is an array of digest values. The keys MUST match and correlate
* to the 'key' array keys.
*
* The valid/current key is identified using 'currentKey'
* Each keyTitle is an associative array containing the required 'key'
* value, and the optional 'driver' and 'digest' values. If the
* 'driver' and 'digest' values are not specified, the default 'driver'
* and 'digest' values will be used.
*
* Old keys will are used to decrypt existing Secret Keys. It is encouraged
* to run 'php spark shield:hmac reencrypt' to update existing Secret
* Key encryptions.
*
* @see https://codeigniter.com/user_guide/libraries/encryption.html
*
* @var array|string
*/
public array $hmacEncryption = [
'key' => ['k1' => ''],
'driver' => ['k1' => 'OpenSSL'],
'digest' => ['k1' => 'SHA512'],
'currentKey' => 'k1',
public $hmacEncryptionKeys = [
'k1' => [
'key' => '',
],
];

/**
* --------------------------------------------------------------------
* HMAC Current Encryption Key Selector
* --------------------------------------------------------------------
* This specifies which of the encryption keys should be used.
*/
public string $hmacEncryptionCurrentKey = 'k1';

/**
* --------------------------------------------------------------------
* HMAC Encryption Key Driver
* --------------------------------------------------------------------
* This specifies which of the encryption drivers should be used.
*
* Available drivers:
* - OpenSSL
* - Sodium
*/
public string $hmacEncryptionDefaultDriver = 'OpenSSL';

/**
* --------------------------------------------------------------------
* HMAC Encryption Key Driver
* --------------------------------------------------------------------
* THis specifies the type of encryption to be used.
* e.g. 'SHA512' or 'SHA256'.
*/
public string $hmacEncryptionDefaultDigest = 'SHA512';
}
27 changes: 11 additions & 16 deletions src/Config/BaseAuthToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@

class BaseAuthToken extends BaseConfig
{
public array $hmacEncryption;
/**
* List of HMAC Encryption Keys
*
* @var array|string
*/
public $hmacEncryptionKeys;

/**
* AuthToken Config Constructor
Expand All @@ -17,18 +22,10 @@ public function __construct()
{
parent::__construct();

$overwriteHmacEncryptionFields = [
'key',
'driver',
'digest',
];

foreach ($overwriteHmacEncryptionFields as $fieldName) {
if (is_string($this->hmacEncryption[$fieldName])) {
$array = json_decode($this->hmacEncryption[$fieldName], true);
if (is_array($array)) {
$this->hmacEncryption[$fieldName] = $array;
}
if (is_string($this->hmacEncryptionKeys)) {
$array = json_decode($this->hmacEncryptionKeys, true);
if (is_array($array)) {
$this->hmacEncryptionKeys = $array;
}
}
}
Expand All @@ -43,9 +40,7 @@ public function __construct()
protected function initEnvValue(&$property, string $name, string $prefix, string $shortPrefix): void
{
switch ($name) {
case 'hmacEncryption.key':
case 'hmacEncryption.driver':
case 'hmacEncryption.digest':
case 'hmacEncryptionKeys':
// if attempting to set property from ENV, first set to empty string
if ($this->getEnvValue($name, $prefix, $shortPrefix) !== null) {
$property = '';
Expand Down
2 changes: 1 addition & 1 deletion tests/Commands/HmacTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public function testReEncrypt(): void
/** @var AuthToken $config */
$config = config('AuthToken');

$config->hmacEncryption['currentKey'] = 'k2';
$config->hmacEncryptionCurrentKey = 'k2';

// new key generated with updated encryption
$token2 = $user->generateHmacToken('bar');
Expand Down

0 comments on commit 2570a7c

Please sign in to comment.