HaliteCryptoHelper   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 58
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
dl 0
loc 58
rs 10
c 1
b 0
f 0
wmc 5

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A encrypt() 0 16 2
A decrypt() 0 15 2
1
<?php declare(strict_types=1);
2
3
/**
4
 * Copyright 2022 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\GatewayBundle\Sso2fa\Crypto;
20
21
use Exception;
22
use ParagonIE\Halite\Symmetric\Crypto;
23
use ParagonIE\Halite\Symmetric\EncryptionKey;
24
use ParagonIE\HiddenString\HiddenString;
25
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\Exception\DecryptionFailedException;
26
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\Exception\EncryptionFailedException;
27
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\ValueObject\Configuration;
28
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\ValueObject\CookieValue;
29
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\ValueObject\CookieValueInterface;
30
31
class HaliteCryptoHelper implements CryptoHelperInterface
32
{
33
    private $encryptionKey;
34
35
    public function __construct(Configuration $configuration)
36
    {
37
        // The configured encryption key is used to create a Halite EncryptionKey
38
        $this->encryptionKey = new EncryptionKey(new HiddenString($configuration->getEncryptionKey()));
39
    }
40
41
    /**
42
     * Halite always uses authenticated encryption.
43
     * See: https://github.com/paragonie/halite/blob/v4.x/doc/Classes/Symmetric/Crypto.md#encrypt
44
     *
45
     * It uses XSalsa20 for encryption and BLAKE2b for message Authentication (MAC)
46
     * The keys used for encryption and message authentication are derived from the secret key using a
47
     * HKDF using a salt This means that learning either derived key cannot lead to learning the other
48
     * derived key, or the secret key input in the HKDF. Encrypting many messages using the same
49
     * secret key is not a problem in this design.
50
     */
51
    public function encrypt(CookieValueInterface $cookieValue): string
52
    {
53
        try {
54
            $plainTextCookieValue = new HiddenString($cookieValue->serialize());
55
            // Encryption (we use the default encoding: Halite::ENCODE_BASE64URLSAFE)
56
            $encryptedData = Crypto::encrypt(
57
                $plainTextCookieValue,
58
                $this->encryptionKey
59
            );
60
        } catch (Exception $e) {
61
            throw new EncryptionFailedException(
62
                'Encrypting the CookieValue for failed',
63
                $e
64
            );
65
        }
66
        return $encryptedData;
67
    }
68
69
    /**
70
     * Decrypt the cookie ciphertext back to plain text.
71
     * Again using the encryption key, used to encrypt the data.
72
     * The decrypt method will return a deserialized CookieValue value object
73
     */
74
    public function decrypt(string $cookieData): CookieValue
75
    {
76
        try {
77
            // Decryption: (we use the default encoding: Halite::DECODE_BASE64URLSAFE)
78
            $decryptedData = Crypto::decrypt(
79
                $cookieData,
80
                $this->encryptionKey
81
            );
82
        } catch (Exception $e) {
83
            throw new DecryptionFailedException(
84
                'Decrypting the CookieValue failed, see embedded error message for details',
85
                $e
86
            );
87
        }
88
        return CookieValue::deserialize($decryptedData->getString());
89
    }
90
}
91