Completed
Pull Request — develop (#225)
by
unknown
09:12 queued 07:20
created

IdentityEncrypter::encrypt()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 72
rs 7.0553
c 0
b 0
f 0
cc 9
nc 8
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Copyright 2020 SURFnet B.V.
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\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Encryption;
20
21
use RobRichards\XMLSecLibs\XMLSecurityKey;
22
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\InvalidArgumentException;
23
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Configuration\RemoteVettingConfiguration;
24
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Dto\AttributeListDto;
25
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Value\AttributeCollectionInterface;
26
27
class IdentityEncrypter implements IdentityEncrypterInterface
28
{
29
    /**
30
     * @var RemoteVettingConfiguration $configuration
31
     */
32
    private $configuration;
33
34
    /**
35
     * @var IdentityWriterInterface
36
     */
37
    private $writer;
38
39
    public function __construct(RemoteVettingConfiguration $configuration, IdentityWriterInterface $writer)
40
    {
41
        $this->configuration = $configuration;
42
        $this->writer = $writer;
43
    }
44
45
    public function encrypt($data)
46
    {
47
        $rsaPublicKey = $this->configuration->getPublicKey();
48
49
        if (!is_string($data) || !is_string($rsaPublicKey)) {
50
            // Invalid argument
51
            throw new InvalidArgumentException('Invalid input was provided to the encrypt method');
52
        }
53
54
        // Use AES-256 in GCM
55
        $symmetricAlgorithm = 'aes-256-gcm';
56
57
        // Generate initialisation vector for the symmetric encryption algorithm
58
        $ivLength = openssl_cipher_iv_length($symmetricAlgorithm);
59
        if (false === $ivLength) {
60
            // Error generating key
61
            throw new InvalidArgumentException(
62
                'Unable to generate an initialization vector (iv) based on the selected symmetric encryption algorithm'
63
            );
64
        }
65
66
        $iv = openssl_random_pseudo_bytes($ivLength);
67
        if (false === $iv) {
68
            // Error generating key
69
            throw new InvalidArgumentException('Unable to generate a correct initialization vector (iv)');
70
        }
71
72
        // Generate a 256 bits AES key
73
        $secretKey = openssl_random_pseudo_bytes(256 / 8);
74
        if (false === $secretKey) {
75
            // Error generating key
76
            throw new InvalidArgumentException('Unable to generate the secret key');
77
        }
78
79
        // Encrypt the data
80
        $tag = '';
81
        $ciphertext = openssl_encrypt($data, $symmetricAlgorithm, $secretKey, 0, $iv, $tag);
82
        if (false === $ciphertext) {
83
            // Encryption failed
84
            throw new InvalidArgumentException(
85
                sprintf('Unable to encrypt the data, ssl error: "%s"', openssl_error_string())
86
            );
87
        }
88
89
        // Encrypt symmetric key
90
        $rsaPublicKeyHandle = openssl_pkey_get_public($rsaPublicKey);
91
        if (false === $rsaPublicKeyHandle) {
92
            // Reading RSA public key failed
93
            throw new InvalidArgumentException('Reading RSA public key failed');
94
        }
95
        $encryptedKey = '';
96
97
        $res = openssl_public_encrypt($secretKey, $encryptedKey, $rsaPublicKeyHandle, OPENSSL_PKCS1_OAEP_PADDING);
98
        if (false === $res) {
99
            // Key encryption failed
100
            openssl_pkey_free($rsaPublicKeyHandle);
101
            throw new InvalidArgumentException('Key encryption failed');
102
        }
103
104
        openssl_pkey_free($rsaPublicKeyHandle);
105
        $output = json_encode(
106
            [
107
                'algorithm' => $symmetricAlgorithm,
108
                'iv' => base64_encode($iv),
109
                'tag' => base64_encode($tag),
110
                'ciphertext' => base64_encode($ciphertext),
111
                'encrypted_key' => base64_encode($encryptedKey),
112
            ]
113
        );
114
115
        $this->writer->write($output);
116
    }
117
}
118