ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
XMLSecurityKey.php
Go to the documentation of this file.
1<?php
3
4use DOMElement;
5use Exception;
6
48{
49 const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
50 const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
51 const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
52 const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
53 const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
54 const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
55 const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
56 const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
57 const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
58 const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
59 const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
60 const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
61
63 private $cryptParams = array();
64
66 public $type = 0;
67
69 public $key = null;
70
72 public $passphrase = "";
73
75 public $iv = null;
76
78 public $name = null;
79
81 public $keyChain = null;
82
84 public $isEncrypted = false;
85
87 public $encryptedCtx = null;
88
90 public $guid = null;
91
97 private $x509Certificate = null;
98
103 private $X509Thumbprint = null;
104
110 public function __construct($type, $params=null)
111 {
112 switch ($type) {
113 case (self::TRIPLEDES_CBC):
114 $this->cryptParams['library'] = 'openssl';
115 $this->cryptParams['cipher'] = 'des-ede3-cbc';
116 $this->cryptParams['type'] = 'symmetric';
117 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
118 $this->cryptParams['keysize'] = 24;
119 $this->cryptParams['blocksize'] = 8;
120 break;
121 case (self::AES128_CBC):
122 $this->cryptParams['library'] = 'openssl';
123 $this->cryptParams['cipher'] = 'aes-128-cbc';
124 $this->cryptParams['type'] = 'symmetric';
125 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
126 $this->cryptParams['keysize'] = 16;
127 $this->cryptParams['blocksize'] = 16;
128 break;
129 case (self::AES192_CBC):
130 $this->cryptParams['library'] = 'openssl';
131 $this->cryptParams['cipher'] = 'aes-192-cbc';
132 $this->cryptParams['type'] = 'symmetric';
133 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
134 $this->cryptParams['keysize'] = 24;
135 $this->cryptParams['blocksize'] = 16;
136 break;
137 case (self::AES256_CBC):
138 $this->cryptParams['library'] = 'openssl';
139 $this->cryptParams['cipher'] = 'aes-256-cbc';
140 $this->cryptParams['type'] = 'symmetric';
141 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
142 $this->cryptParams['keysize'] = 32;
143 $this->cryptParams['blocksize'] = 16;
144 break;
145 case (self::RSA_1_5):
146 $this->cryptParams['library'] = 'openssl';
147 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
148 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
149 if (is_array($params) && ! empty($params['type'])) {
150 if ($params['type'] == 'public' || $params['type'] == 'private') {
151 $this->cryptParams['type'] = $params['type'];
152 break;
153 }
154 }
155 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
156 case (self::RSA_OAEP_MGF1P):
157 $this->cryptParams['library'] = 'openssl';
158 $this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
159 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
160 $this->cryptParams['hash'] = null;
161 if (is_array($params) && ! empty($params['type'])) {
162 if ($params['type'] == 'public' || $params['type'] == 'private') {
163 $this->cryptParams['type'] = $params['type'];
164 break;
165 }
166 }
167 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
168 case (self::RSA_SHA1):
169 $this->cryptParams['library'] = 'openssl';
170 $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
171 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
172 if (is_array($params) && ! empty($params['type'])) {
173 if ($params['type'] == 'public' || $params['type'] == 'private') {
174 $this->cryptParams['type'] = $params['type'];
175 break;
176 }
177 }
178 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
179 case (self::RSA_SHA256):
180 $this->cryptParams['library'] = 'openssl';
181 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
182 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
183 $this->cryptParams['digest'] = 'SHA256';
184 if (is_array($params) && ! empty($params['type'])) {
185 if ($params['type'] == 'public' || $params['type'] == 'private') {
186 $this->cryptParams['type'] = $params['type'];
187 break;
188 }
189 }
190 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
191 case (self::RSA_SHA384):
192 $this->cryptParams['library'] = 'openssl';
193 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
194 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
195 $this->cryptParams['digest'] = 'SHA384';
196 if (is_array($params) && ! empty($params['type'])) {
197 if ($params['type'] == 'public' || $params['type'] == 'private') {
198 $this->cryptParams['type'] = $params['type'];
199 break;
200 }
201 }
202 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
203 case (self::RSA_SHA512):
204 $this->cryptParams['library'] = 'openssl';
205 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
206 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
207 $this->cryptParams['digest'] = 'SHA512';
208 if (is_array($params) && ! empty($params['type'])) {
209 if ($params['type'] == 'public' || $params['type'] == 'private') {
210 $this->cryptParams['type'] = $params['type'];
211 break;
212 }
213 }
214 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
215 case (self::HMAC_SHA1):
216 $this->cryptParams['library'] = $type;
217 $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
218 break;
219 default:
220 throw new Exception('Invalid Key Type');
221 }
222 $this->type = $type;
223 }
224
233 public function getSymmetricKeySize()
234 {
235 if (! isset($this->cryptParams['keysize'])) {
236 return null;
237 }
238 return $this->cryptParams['keysize'];
239 }
240
247 public function generateSessionKey()
248 {
249 if (!isset($this->cryptParams['keysize'])) {
250 throw new Exception('Unknown key size for type "' . $this->type . '".');
251 }
252 $keysize = $this->cryptParams['keysize'];
253
254 $key = openssl_random_pseudo_bytes($keysize);
255
256 if ($this->type === self::TRIPLEDES_CBC) {
257 /* Make sure that the generated key has the proper parity bits set.
258 * Mcrypt doesn't care about the parity bits, but others may care.
259 */
260 for ($i = 0; $i < strlen($key); $i++) {
261 $byte = ord($key[$i]) & 0xfe;
262 $parity = 1;
263 for ($j = 1; $j < 8; $j++) {
264 $parity ^= ($byte >> $j) & 1;
265 }
266 $byte |= $parity;
267 $key[$i] = chr($byte);
268 }
269 }
270
271 $this->key = $key;
272 return $key;
273 }
274
281 public static function getRawThumbprint($cert)
282 {
283
284 $arCert = explode("\n", $cert);
285 $data = '';
286 $inData = false;
287
288 foreach ($arCert AS $curData) {
289 if (! $inData) {
290 if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
291 $inData = true;
292 }
293 } else {
294 if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
295 break;
296 }
297 $data .= trim($curData);
298 }
299 }
300
301 if (! empty($data)) {
302 return strtolower(sha1(base64_decode($data)));
303 }
304
305 return null;
306 }
307
316 public function loadKey($key, $isFile=false, $isCert = false)
317 {
318 if ($isFile) {
319 $this->key = file_get_contents($key);
320 } else {
321 $this->key = $key;
322 }
323 if ($isCert) {
324 $this->key = openssl_x509_read($this->key);
325 openssl_x509_export($this->key, $str_cert);
326 $this->x509Certificate = $str_cert;
327 $this->key = $str_cert;
328 } else {
329 $this->x509Certificate = null;
330 }
331 if ($this->cryptParams['library'] == 'openssl') {
332 switch ($this->cryptParams['type']) {
333 case 'public':
334 if ($isCert) {
335 /* Load the thumbprint if this is an X509 certificate. */
336 $this->X509Thumbprint = self::getRawThumbprint($this->key);
337 }
338 $this->key = openssl_get_publickey($this->key);
339 if (! $this->key) {
340 throw new Exception('Unable to extract public key');
341 }
342 break;
343
344 case 'private':
345 $this->key = openssl_get_privatekey($this->key, $this->passphrase);
346 break;
347
348 case'symmetric':
349 if (strlen($this->key) < $this->cryptParams['keysize']) {
350 throw new Exception('Key must contain at least 25 characters for this cipher');
351 }
352 break;
353
354 default:
355 throw new Exception('Unknown type');
356 }
357 }
358 }
359
368 private function padISO10126($data, $blockSize)
369 {
370 if ($blockSize > 256) {
371 throw new Exception('Block size higher than 256 not allowed');
372 }
373 $padChr = $blockSize - (strlen($data) % $blockSize);
374 $pattern = chr($padChr);
375 return $data . str_repeat($pattern, $padChr);
376 }
377
384 private function unpadISO10126($data)
385 {
386 $padChr = substr($data, -1);
387 $padLen = ord($padChr);
388 return substr($data, 0, -$padLen);
389 }
390
397 private function encryptSymmetric($data)
398 {
399 $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher']));
400 $data = $this->padISO10126($data, $this->cryptParams['blocksize']);
401 $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
402 if (false === $encrypted) {
403 throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string());
404 }
405 return $this->iv . $encrypted;
406 }
407
414 private function decryptSymmetric($data)
415 {
416 $iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']);
417 $this->iv = substr($data, 0, $iv_length);
418 $data = substr($data, $iv_length);
419 $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
420 if (false === $decrypted) {
421 throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string());
422 }
423 return $this->unpadISO10126($decrypted);
424 }
425
433 private function encryptPublic($data)
434 {
435 if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
436 throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string());
437 }
438 return $encrypted;
439 }
440
448 private function decryptPublic($data)
449 {
450 if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
451 throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string());
452 }
453 return $decrypted;
454 }
455
463 private function encryptPrivate($data)
464 {
465 if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
466 throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string());
467 }
468 return $encrypted;
469 }
470
478 private function decryptPrivate($data)
479 {
480 if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
481 throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string());
482 }
483 return $decrypted;
484 }
485
493 private function signOpenSSL($data)
494 {
495 $algo = OPENSSL_ALGO_SHA1;
496 if (! empty($this->cryptParams['digest'])) {
497 $algo = $this->cryptParams['digest'];
498 }
499 if (! openssl_sign($data, $signature, $this->key, $algo)) {
500 throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
501 }
502 return $signature;
503 }
504
521 private function verifyOpenSSL($data, $signature)
522 {
523 $algo = OPENSSL_ALGO_SHA1;
524 if (! empty($this->cryptParams['digest'])) {
525 $algo = $this->cryptParams['digest'];
526 }
527 return openssl_verify($data, $signature, $this->key, $algo);
528 }
529
536 public function encryptData($data)
537 {
538 if ($this->cryptParams['library'] === 'openssl') {
539 switch ($this->cryptParams['type']) {
540 case 'symmetric':
541 return $this->encryptSymmetric($data);
542 case 'public':
543 return $this->encryptPublic($data);
544 case 'private':
545 return $this->encryptPrivate($data);
546 }
547 }
548 }
549
556 public function decryptData($data)
557 {
558 if ($this->cryptParams['library'] === 'openssl') {
559 switch ($this->cryptParams['type']) {
560 case 'symmetric':
561 return $this->decryptSymmetric($data);
562 case 'public':
563 return $this->decryptPublic($data);
564 case 'private':
565 return $this->decryptPrivate($data);
566 }
567 }
568 }
569
576 public function signData($data)
577 {
578 switch ($this->cryptParams['library']) {
579 case 'openssl':
580 return $this->signOpenSSL($data);
581 case (self::HMAC_SHA1):
582 return hash_hmac("sha1", $data, $this->key, true);
583 }
584 }
585
602 public function verifySignature($data, $signature)
603 {
604 switch ($this->cryptParams['library']) {
605 case 'openssl':
606 return $this->verifyOpenSSL($data, $signature);
607 case (self::HMAC_SHA1):
608 $expectedSignature = hash_hmac("sha1", $data, $this->key, true);
609 return strcmp($signature, $expectedSignature) == 0;
610 }
611 }
612
618 public function getAlgorith()
619 {
620 return $this->getAlgorithm();
621 }
622
626 public function getAlgorithm()
627 {
628 return $this->cryptParams['method'];
629 }
630
637 public static function makeAsnSegment($type, $string)
638 {
639 switch ($type) {
640 case 0x02:
641 if (ord($string) > 0x7f)
642 $string = chr(0).$string;
643 break;
644 case 0x03:
645 $string = chr(0).$string;
646 break;
647 }
648
649 $length = strlen($string);
650
651 if ($length < 128) {
652 $output = sprintf("%c%c%s", $type, $length, $string);
653 } else if ($length < 0x0100) {
654 $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
655 } else if ($length < 0x010000) {
656 $output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string);
657 } else {
658 $output = null;
659 }
660 return $output;
661 }
662
670 public static function convertRSA($modulus, $exponent)
671 {
672 /* make an ASN publicKeyInfo */
673 $exponentEncoding = self::makeAsnSegment(0x02, $exponent);
674 $modulusEncoding = self::makeAsnSegment(0x02, $modulus);
675 $sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding);
676 $bitstringEncoding = self::makeAsnSegment(0x03, $sequenceEncoding);
677 $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500");
678 $publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier.$bitstringEncoding);
679
680 /* encode the publicKeyInfo in base64 and add PEM brackets */
681 $publicKeyInfoBase64 = base64_encode($publicKeyInfo);
682 $encoding = "-----BEGIN PUBLIC KEY-----\n";
683 $offset = 0;
684 while ($segment = substr($publicKeyInfoBase64, $offset, 64)) {
685 $encoding = $encoding.$segment."\n";
686 $offset += 64;
687 }
688 return $encoding."-----END PUBLIC KEY-----\n";
689 }
690
694 public function serializeKey($parent)
695 {
696
697 }
698
707 public function getX509Certificate()
708 {
710 }
711
721 public function getX509Thumbprint()
722 {
724 }
725
726
735 public static function fromEncryptedKeyElement(DOMElement $element)
736 {
737
738 $objenc = new XMLSecEnc();
739 $objenc->setNode($element);
740 if (! $objKey = $objenc->locateKey()) {
741 throw new Exception("Unable to locate algorithm for this Encrypted Key");
742 }
743 $objKey->isEncrypted = true;
744 $objKey->encryptedCtx = $objenc;
745 XMLSecEnc::staticLocateKeyInfo($objKey, $element);
746 return $objKey;
747 }
748
749}
sprintf('%.4f', $callTime)
An exception for terminatinating execution or to throw for unit testing.
static staticLocateKeyInfo($objBaseKey=null, $node=null)
Definition: XMLSecEnc.php:410
padISO10126($data, $blockSize)
ISO 10126 Padding.
encryptData($data)
Encrypts the given data (string) using the regarding php-extension, depending on the library assigned...
decryptData($data)
Decrypts the given data (string) using the regarding php-extension, depending on the library assigned...
getSymmetricKeySize()
Retrieve the key size for the symmetric encryption algorithm.
encryptSymmetric($data)
Encrypts the given data (string) using the openssl-extension.
static getRawThumbprint($cert)
Get the raw thumbprint of a certificate.
loadKey($key, $isFile=false, $isCert=false)
Loads the given key, or - with isFile set true - the key from the keyfile.
signOpenSSL($data)
Signs the given data (string) using the openssl-extension.
getX509Certificate()
Retrieve the X509 certificate this key represents.
unpadISO10126($data)
Remove ISO 10126 Padding.
encryptPublic($data)
Encrypts the given public data (string) using the openssl-extension.
encryptPrivate($data)
Encrypts the given private data (string) using the openssl-extension.
decryptPrivate($data)
Decrypts the given private data (string) using the openssl-extension.
signData($data)
Signs the data (string) using the extension assigned to the type in the constructor.
verifyOpenSSL($data, $signature)
Verifies the given data (string) belonging to the given signature using the openssl-extension.
generateSessionKey()
Generates a session key using the openssl-extension.
getX509Thumbprint()
Get the thumbprint of this X509 certificate.
static convertRSA($modulus, $exponent)
Hint: Modulus and Exponent must already be base64 decoded.
static fromEncryptedKeyElement(DOMElement $element)
Create key from an EncryptedKey-element.
decryptPublic($data)
Decrypts the given public data (string) using the openssl-extension.
verifySignature($data, $signature)
Verifies the data (string) against the given signature using the extension assigned to the type in th...
decryptSymmetric($data)
Decrypts the given data (string) using the openssl-extension.
$i
Definition: disco.tpl.php:19
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\s+" &#(? foreach( $entity_files as $file) $output
$algo
Definition: pwgen.php:34
$params
Definition: disable.php:11