1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
<?php
/**
* Keyring.php
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* @author Moritz Strohm <strohm@data-quest.de>
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @since 6.0
*/
/**
* The Keyring class stores cryptographic keyrings in the database.
*
* @property int $id database column
* @property string $range_id database column
* @property string $range_type database column
* @property string $public_key database column
* @property string $private_key database column
* @property string $passphrase database column
* @property int $mkdate database column
* @property int $chdate database column
*/
class Keyring extends SimpleORMap
{
private const ALGORTIHM_RS256 = 'RSA-OAEP-256';
protected static function configure($config = [])
{
$config['db_table'] = 'keyrings';
parent::configure($config);
}
/**
* This method generates a new keyring.
*
* @param string $range_id The ID of the range for which to generate the keyring.
*
* @param string $range_type The type of range for which to generate the keyring.
*
* @param string $passphrase An optional passphrase for the keyring. This should not be stored
* as plain text in here, but instead in a cryptographically hashed form.
*
* @param string $algorithm The algorithm to use for the new keyring.
*
* @return Keyring The generated keyring.
*
* @throws \Studip\KeyringException In case no keyring can be generated, a KeyringException is thrown.
*/
public static function generate(
string $range_id,
string $range_type,
string $passphrase = '',
string $algorithm = self::ALGORTIHM_RS256
) : Keyring
{
if ($algorithm === self::ALGORTIHM_RS256) {
$private_key = phpseclib3\Crypt\RSA::createKey(4096);
if ($passphrase) {
$private_key = $private_key->withPassword($passphrase);
}
//Explicitly set OAEP as padding method:
$private_key->withPadding(\phpseclib\Crypt\RSA::ENCRYPTION_OAEP);
//Explicitly set sha256:
$private_key->withHash('sha256');
$public_key = $private_key->getPublicKey();
$keyring = new self();
$keyring->range_id = $range_id;
$keyring->range_type = $range_type;
$keyring->private_key = $private_key;
$keyring->public_key = $public_key;
if ($passphrase) {
$hasher = UserManagement::getPwdHasher();
$keyring->passphrase = $hasher->HashPassword($passphrase);
}
if ($keyring->store()) {
return $keyring;
}
throw new \Studip\KeyringException(
_('Es konnte kein Schlüsselpaar erzeugt werden.'),
\Studip\KeyringException::CREATION_FAILED
);
} else {
throw new \Studip\KeyringException(
sprintf(
_('Der Schlüsselalgorithmus %s wird nicht unterstützt.'),
$algorithm
),
\Studip\KeyringException::UNSUPPORTED_KEY_ALGORITHM
);
}
}
/**
* Generates a new keyring from a public key.
* This method will not attempt to re-create the private key from the public key.
* Instead, the public key is the only part of the key that is stored in a new
* keyring instance.
*
* @param \OAT\Library\Lti1p3Core\Security\Key\KeyInterface|string $key The public key.
*
* @param string $range_type The range type for the keyring.
*
* @param string $range_id The range-ID for the keyring.
*
* @return Keyring|null A keyring, if it can be created or null in case of failure to do so.
*/
public static function createFromPublicKey(
\OAT\Library\Lti1p3Core\Security\Key\KeyInterface|string $key,
string $range_type,
string $range_id
) : ?Keyring
{
$keyring = new self();
$keyring->range_type = $range_type;
$keyring->range_id = $range_id;
$keyring->private_key = '';
if (is_string($key)) {
$keyring->public_key = $key;
} else {
//Instance of KeyInterface:
$content = $key->getContent();
if (!$content || empty($content['n']) || empty($content['e'])) {
//No key present or base or exponent missing.
return null;
}
$loaded_key = \phpseclib3\Crypt\RSA::loadPublicKey([
'e' => new \phpseclib3\Math\BigInteger(base64_decode(strtr($content['e'], '-_', '+/'))),
'n' => new \phpseclib3\Math\BigInteger(base64_decode(strtr($content['n'], '-_', '+/'))),
]);
$keyring->public_key = $loaded_key->toString('PKCS8');
}
return $keyring;
}
/**
* Converts the keyring to a KeyChain instance of the Lti1p3Core library.
*
* @return \OAT\Library\Lti1p3Core\Security\Key\KeyChain A KeyChain representation
* of the keyring.
*/
public function toKeyChain() : \OAT\Library\Lti1p3Core\Security\Key\KeyChain
{
$public_key = new \OAT\Library\Lti1p3Core\Security\Key\Key(
$this->public_key
);
//A private key is optional.
$private_key = null;
if ($this->private_key) {
$private_key = new \OAT\Library\Lti1p3Core\Security\Key\Key(
$this->private_key,
$this->passphrase ?? null
);
}
return new \OAT\Library\Lti1p3Core\Security\Key\KeyChain(
$this->id,
$this->range_id,
$public_key,
$private_key
);
}
}
|