Passed
Branch feature/php83 (e52173)
by Tim
33:00 queued 16:50
created

EncryptionAlgorithmFactory::__construct()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 18
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 7
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 18
rs 9.2222
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\Alg\Encryption;
6
7
use SimpleSAML\Assert\Assert;
8
use SimpleSAML\XMLSecurity\Constants as C;
9
use SimpleSAML\XMLSecurity\Exception\BlacklistedAlgorithmException;
10
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
11
use SimpleSAML\XMLSecurity\Key\KeyInterface;
12
13
use function array_key_exists;
14
use function sprintf;
15
16
/**
17
 * Factory class to create and configure encryption algorithms.
18
 *
19
 * @package simplesamlphp/xml-security
20
 */
21
final class EncryptionAlgorithmFactory
22
{
23
    /**
24
     * An array of blacklisted algorithms.
25
     *
26
     * Defaults to 3DES.
27
     *
28
     * @var string[]
29
     */
30
    public const array DEFAULT_BLACKLIST = [
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 30 at column 23
Loading history...
31
        C::BLOCK_ENC_3DES,
32
    ];
33
34
    /**
35
     * An array of default algorithms that can be used.
36
     *
37
     * @var class-string[]
38
     */
39
    private const array SUPPORTED_DEFAULTS = [
40
        TripleDES::class,
41
        AES::class,
42
    ];
43
44
45
    /**
46
     * A cache of algorithm implementations indexed by algorithm ID.
47
     *
48
     * @var array<string, \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface>
49
     */
50
    protected static array $cache = [];
51
52
    /**
53
     * Whether the factory has been initialized or not.
54
     */
55
    protected static bool $initialized = false;
56
57
58
    /**
59
     * Build a factory that creates algorithms.
60
     *
61
     * @param string[] $blacklist A list of algorithms forbidden for their use.
62
     */
63
    public function __construct(
64
        protected array $blacklist = self::DEFAULT_BLACKLIST,
65
    ) {
66
        // initialize the cache for supported algorithms per known implementation
67
        if (!self::$initialized) {
68
            foreach (self::SUPPORTED_DEFAULTS as $algorithm) {
69
                foreach ($algorithm::getSupportedAlgorithms() as $algId) {
70
                    if (array_key_exists($algId, self::$cache) && !array_key_exists($algId, $this->blacklist)) {
71
                        /*
72
                         * If the key existed before initialization, that means someone registered a handler for this
73
                         * algorithm, so we should respect that and skip registering the default here.
74
                         */
75
                        continue;
76
                    }
77
                    self::$cache[$algId] = $algorithm;
78
                }
79
            }
80
            self::$initialized = true;
81
        }
82
    }
83
84
85
    /**
86
     * Get a new object implementing the given digital signature algorithm.
87
     *
88
     * @param string $algId The identifier of the algorithm desired.
89
     * @param \SimpleSAML\XMLSecurity\Key\KeyInterface $key The key to use with the given algorithm.
90
     *
91
     * @return \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface An object implementing the given
92
     * algorithm.
93
     *
94
     * @throws \SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException If an error occurs, e.g. the given
95
     * algorithm is blacklisted, unknown or the given key is not suitable for it.
96
     */
97
    public function getAlgorithm(
98
        string $algId,
99
        #[\SensitiveParameter]
100
        KeyInterface $key,
101
    ): EncryptionAlgorithmInterface {
102
        Assert::notInArray(
103
            $algId,
104
            $this->blacklist,
105
            sprintf('Blacklisted algorithm: \'%s\'.', $algId),
106
            BlacklistedAlgorithmException::class,
107
        );
108
        Assert::keyExists(
109
            self::$cache,
110
            $algId,
111
            sprintf('Unknown or unsupported algorithm: \'%s\'.', $algId),
112
            UnsupportedAlgorithmException::class,
113
        );
114
115
        return new self::$cache[$algId]($key, $algId);
116
    }
117
118
119
    /**
120
     * Register an implementation of some algorithm(s) for its use.
121
     *
122
     * @param class-string $className
123
     */
124
    public static function registerAlgorithm(string $className): void
125
    {
126
        Assert::implementsInterface(
127
            $className,
128
            EncryptionAlgorithmInterface::class,
129
            sprintf(
130
                'Cannot register algorithm "%s", must implement %s.',
131
                $className,
132
                EncryptionAlgorithmInterface::class,
133
            ),
134
        );
135
136
        foreach ($className::getSupportedAlgorithms() as $algId) {
137
            self::$cache[$algId] = $className;
138
        }
139
    }
140
}
141