WSCOMUN  2.1.2
Web Services Comunes para PHP/GVHidra
XMLSecurityKey.php
1 <?php
42 {
43  const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
44  const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
45  const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
46  const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
47  const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
48  const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
49  const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
50  const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
51  const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
52  const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
53  const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
54  const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
56  private $cryptParams = array ();
58  public $type = 0;
60  public $key = null;
62  public $passphrase = "";
64  public $iv = null;
66  public $name = null;
68  public $keyChain = null;
70  public $isEncrypted = false;
72  public $encryptedCtx = null;
74  public $guid = null;
81  private $x509Certificate = null;
87  private $X509Thumbprint = null;
88 
95  public function __construct($type, $params = null)
96  {
97  switch ($type)
98  {
99  case (self::TRIPLEDES_CBC) :
100  $this->cryptParams ['library'] = 'mcrypt';
101  $this->cryptParams ['cipher'] = MCRYPT_TRIPLEDES;
102  $this->cryptParams ['mode'] = MCRYPT_MODE_CBC;
103  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
104  $this->cryptParams ['keysize'] = 24;
105  break;
106  case (self::AES128_CBC) :
107  $this->cryptParams ['library'] = 'mcrypt';
108  $this->cryptParams ['cipher'] = MCRYPT_RIJNDAEL_128;
109  $this->cryptParams ['mode'] = MCRYPT_MODE_CBC;
110  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
111  $this->cryptParams ['keysize'] = 16;
112  break;
113  case (self::AES192_CBC) :
114  $this->cryptParams ['library'] = 'mcrypt';
115  $this->cryptParams ['cipher'] = MCRYPT_RIJNDAEL_128;
116  $this->cryptParams ['mode'] = MCRYPT_MODE_CBC;
117  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
118  $this->cryptParams ['keysize'] = 24;
119  break;
120  case (self::AES256_CBC) :
121  $this->cryptParams ['library'] = 'mcrypt';
122  $this->cryptParams ['cipher'] = MCRYPT_RIJNDAEL_128;
123  $this->cryptParams ['mode'] = MCRYPT_MODE_CBC;
124  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
125  $this->cryptParams ['keysize'] = 32;
126  break;
127  case (self::RSA_1_5) :
128  $this->cryptParams ['library'] = 'openssl';
129  $this->cryptParams ['padding'] = OPENSSL_PKCS1_PADDING;
130  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
131  if (is_array ( $params ) && ! empty ( $params ['type'] ))
132  {
133  if ($params ['type'] == 'public' || $params ['type'] == 'private')
134  {
135  $this->cryptParams ['type'] = $params ['type'];
136  break;
137  }
138  }
139  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
140  case (self::RSA_OAEP_MGF1P) :
141  $this->cryptParams ['library'] = 'openssl';
142  $this->cryptParams ['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
143  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
144  $this->cryptParams ['hash'] = null;
145  if (is_array ( $params ) && ! empty ( $params ['type'] ))
146  {
147  if ($params ['type'] == 'public' || $params ['type'] == 'private')
148  {
149  $this->cryptParams ['type'] = $params ['type'];
150  break;
151  }
152  }
153  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
154  case (self::RSA_SHA1) :
155  $this->cryptParams ['library'] = 'openssl';
156  $this->cryptParams ['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
157  $this->cryptParams ['padding'] = OPENSSL_PKCS1_PADDING;
158  if (is_array ( $params ) && ! empty ( $params ['type'] ))
159  {
160  if ($params ['type'] == 'public' || $params ['type'] == 'private')
161  {
162  $this->cryptParams ['type'] = $params ['type'];
163  break;
164  }
165  }
166  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
167  case (self::RSA_SHA256) :
168  $this->cryptParams ['library'] = 'openssl';
169  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
170  $this->cryptParams ['padding'] = OPENSSL_PKCS1_PADDING;
171  $this->cryptParams ['digest'] = 'SHA256';
172  if (is_array ( $params ) && ! empty ( $params ['type'] ))
173  {
174  if ($params ['type'] == 'public' || $params ['type'] == 'private')
175  {
176  $this->cryptParams ['type'] = $params ['type'];
177  break;
178  }
179  }
180  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
181  case (self::RSA_SHA384) :
182  $this->cryptParams ['library'] = 'openssl';
183  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
184  $this->cryptParams ['padding'] = OPENSSL_PKCS1_PADDING;
185  $this->cryptParams ['digest'] = 'SHA384';
186  if (is_array ( $params ) && ! empty ( $params ['type'] ))
187  {
188  if ($params ['type'] == 'public' || $params ['type'] == 'private')
189  {
190  $this->cryptParams ['type'] = $params ['type'];
191  break;
192  }
193  }
194  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
195  case (self::RSA_SHA512) :
196  $this->cryptParams ['library'] = 'openssl';
197  $this->cryptParams ['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
198  $this->cryptParams ['padding'] = OPENSSL_PKCS1_PADDING;
199  $this->cryptParams ['digest'] = 'SHA512';
200  if (is_array ( $params ) && ! empty ( $params ['type'] ))
201  {
202  if ($params ['type'] == 'public' || $params ['type'] == 'private')
203  {
204  $this->cryptParams ['type'] = $params ['type'];
205  break;
206  }
207  }
208  throw new Exception ( 'Certificate "type" (private/public) must be passed via parameters' );
209  case (self::HMAC_SHA1) :
210  $this->cryptParams ['library'] = $type;
211  $this->cryptParams ['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
212  break;
213  default :
214  throw new Exception ( 'Invalid Key Type' );
215  }
216  $this->type = $type;
217  }
218 
227  public function getSymmetricKeySize()
228  {
229  if (! isset ( $this->cryptParams ['keysize'] ))
230  {
231  return null;
232  }
233  return $this->cryptParams ['keysize'];
234  }
235 
244  public function generateSessionKey()
245  {
246  if (! isset ( $this->cryptParams ['keysize'] ))
247  {
248  throw new Exception ( 'Unknown key size for type "' . $this->type . '".' );
249  }
250  $keysize = $this->cryptParams ['keysize'];
251 
252  if (function_exists ( 'openssl_random_pseudo_bytes' ))
253  {
254  /* We have PHP >= 5.3 - use openssl to generate session key. */
255  $key = openssl_random_pseudo_bytes ( $keysize );
256  }
257  else
258  {
259  /* Generating random key using iv generation routines */
260  $key = mcrypt_create_iv ( $keysize, MCRYPT_RAND );
261  }
262 
263  if ($this->type === self::TRIPLEDES_CBC)
264  {
265  /*
266  * Make sure that the generated key has the proper parity bits set.
267  * Mcrypt doesn't care about the parity bits, but others may care.
268  */
269  for($i = 0; $i < strlen ( $key ); $i ++)
270  {
271  $byte = ord ( $key [$i] ) & 0xfe;
272  $parity = 1;
273  for($j = 1; $j < 8; $j ++)
274  {
275  $parity ^= ($byte >> $j) & 1;
276  }
277  $byte |= $parity;
278  $key [$i] = chr ( $byte );
279  }
280  }
281 
282  $this->key = $key;
283  return $key;
284  }
285 
292  public static function getRawThumbprint($cert)
293  {
294  $arCert = explode ( "\n", $cert );
295  $data = '';
296  $inData = false;
297  foreach ( $arCert as $curData )
298  {
299  if (! $inData)
300  {
301  if (strncmp ( $curData, '-----BEGIN CERTIFICATE', 22 ) == 0)
302  {
303  $inData = true;
304  }
305  }
306  else
307  {
308  if (strncmp ( $curData, '-----END CERTIFICATE', 20 ) == 0)
309  {
310  break;
311  }
312  $data .= trim ( $curData );
313  }
314  }
315  if (! empty ( $data ))
316  {
317  return strtolower ( sha1 ( base64_decode ( $data ) ) );
318  }
319  return null;
320  }
321 
330  public function loadKey($key, $isFile = false, $isCert = false)
331  {
332  if ($isFile)
333  {
334  $this->key = file_get_contents ( $key );
335  }
336  else
337  {
338  $this->key = $key;
339  }
340  if ($isCert)
341  {
342  $str_cert = null;
343  $this->key = openssl_x509_read ( $this->key );
344  openssl_x509_export ( $this->key, $str_cert );
345  $this->x509Certificate = $str_cert;
346  $this->key = $str_cert;
347  }
348  else
349  {
350  $this->x509Certificate = null;
351  }
352  if ($this->cryptParams ['library'] == 'openssl')
353  {
354  if ($this->cryptParams ['type'] == 'public')
355  {
356  if ($isCert)
357  {
358  /* Load the thumbprint if this is an X509 certificate. */
359  $this->X509Thumbprint = self::getRawThumbprint ( $this->key );
360  }
361  $this->key = openssl_get_publickey ( $this->key );
362  if (! $this->key)
363  {
364  throw new Exception ( 'Unable to extract public key' );
365  }
366  }
367  else
368  {
369  $this->key = openssl_get_privatekey ( $this->key, $this->passphrase );
370  }
371  }
372  else if ($this->cryptParams ['cipher'] == MCRYPT_RIJNDAEL_128)
373  {
374  /* Check key length */
375  switch ($this->type)
376  {
377  case (self::AES256_CBC) :
378  if (strlen ( $this->key ) < 25)
379  {
380  throw new Exception ( 'Key must contain at least 25 characters for this cipher' );
381  }
382  break;
383  case (self::AES192_CBC) :
384  if (strlen ( $this->key ) < 17)
385  {
386  throw new Exception ( 'Key must contain at least 17 characters for this cipher' );
387  }
388  break;
389  }
390  }
391  }
392 
399  private function encryptMcrypt($data)
400  {
401  $td = mcrypt_module_open ( $this->cryptParams ['cipher'], '', $this->cryptParams ['mode'], '' );
402  $this->iv = mcrypt_create_iv ( mcrypt_enc_get_iv_size ( $td ), MCRYPT_RAND );
403  mcrypt_generic_init ( $td, $this->key, $this->iv );
404  if ($this->cryptParams ['mode'] == MCRYPT_MODE_CBC)
405  {
406  $bs = mcrypt_enc_get_block_size ( $td );
407  for($datalen0 = $datalen = strlen ( $data ); (($datalen % $bs) != ($bs - 1)); $datalen ++)
408  $data .= chr ( mt_rand ( 1, 127 ) );
409  $data .= chr ( $datalen - $datalen0 + 1 );
410  }
411  $encrypted_data = $this->iv . mcrypt_generic ( $td, $data );
412  mcrypt_generic_deinit ( $td );
413  mcrypt_module_close ( $td );
414  return $encrypted_data;
415  }
416 
423  private function decryptMcrypt($data)
424  {
425  $td = mcrypt_module_open ( $this->cryptParams ['cipher'], '', $this->cryptParams ['mode'], '' );
426  $iv_length = mcrypt_enc_get_iv_size ( $td );
427  $this->iv = substr ( $data, 0, $iv_length );
428  $data = substr ( $data, $iv_length );
429  mcrypt_generic_init ( $td, $this->key, $this->iv );
430  $decrypted_data = mdecrypt_generic ( $td, $data );
431  mcrypt_generic_deinit ( $td );
432  mcrypt_module_close ( $td );
433  if ($this->cryptParams ['mode'] == MCRYPT_MODE_CBC)
434  {
435  $dataLen = strlen ( $decrypted_data );
436  $paddingLength = substr ( $decrypted_data, $dataLen - 1, 1 );
437  $decrypted_data = substr ( $decrypted_data, 0, $dataLen - ord ( $paddingLength ) );
438  }
439  return $decrypted_data;
440  }
441 
449  private function encryptOpenSSL($data)
450  {
451  $encrypted_data = null;
452 
453  if ($this->cryptParams ['type'] == 'public')
454  {
455  if (! openssl_public_encrypt ( $data, $encrypted_data, $this->key, $this->cryptParams ['padding'] ))
456  {
457  throw new Exception ( 'Failure encrypting Data' );
458  }
459  }
460  else
461  {
462  if (! openssl_private_encrypt ( $data, $encrypted_data, $this->key, $this->cryptParams ['padding'] ))
463  {
464  throw new Exception ( 'Failure encrypting Data' );
465  }
466  }
467  return $encrypted_data;
468  }
469 
477  private function decryptOpenSSL($data)
478  {
479  $decrypted = null;
480  if ($this->cryptParams ['type'] == 'public')
481  {
482  if (! openssl_public_decrypt ( $data, $decrypted, $this->key, $this->cryptParams ['padding'] ))
483  {
484  throw new Exception ( 'Failure decrypting Data' );
485  }
486  }
487  else
488  {
489  if (! openssl_private_decrypt ( $data, $decrypted, $this->key, $this->cryptParams ['padding'] ))
490  {
491  throw new Exception ( 'Failure decrypting Data' );
492  }
493  }
494  return $decrypted;
495  }
496 
504  private function signOpenSSL($data)
505  {
506  $signature = null;
507  $algo = OPENSSL_ALGO_SHA1;
508  if (! empty ( $this->cryptParams ['digest'] ))
509  {
510  $algo = $this->cryptParams ['digest'];
511  }
512  if (! openssl_sign ( $data, $signature, $this->key, $algo ))
513  {
514  throw new Exception ( 'Failure Signing Data: ' . openssl_error_string () . ' - ' . $algo );
515  }
516  return $signature;
517  }
518 
526  private function verifyOpenSSL($data, $signature)
527  {
528  $algo = OPENSSL_ALGO_SHA1;
529  if (! empty ( $this->cryptParams ['digest'] ))
530  {
531  $algo = $this->cryptParams ['digest'];
532  }
533  return openssl_verify ( $data, $signature, $this->key, $algo );
534  }
535 
542  public function encryptData($data)
543  {
544  switch ($this->cryptParams ['library'])
545  {
546  case 'mcrypt' :
547  return $this->encryptMcrypt ( $data );
548  case 'openssl' :
549  return $this->encryptOpenSSL ( $data );
550  }
551  }
552 
559  public function decryptData($data)
560  {
561  switch ($this->cryptParams ['library'])
562  {
563  case 'mcrypt' :
564  return $this->decryptMcrypt ( $data );
565  case 'openssl' :
566  return $this->decryptOpenSSL ( $data );
567  }
568  }
569 
576  public function signData($data)
577  {
578  switch ($this->cryptParams ['library'])
579  {
580  case 'openssl' :
581  return $this->signOpenSSL ( $data );
582  case (self::HMAC_SHA1) :
583  return hash_hmac ( "sha1", $data, $this->key, true );
584  }
585  }
586 
594  public function verifySignature($data, $signature)
595  {
596  switch ($this->cryptParams ['library'])
597  {
598  case 'openssl' :
599  return $this->verifyOpenSSL ( $data, $signature );
600  case (self::HMAC_SHA1) :
601  $expectedSignature = hash_hmac ( "sha1", $data, $this->key, true );
602  return strcmp ( $signature, $expectedSignature ) == 0;
603  }
604  }
605 
613  public function getAlgorith()
614  {
615  return $this->getAlgorithm ();
616  }
617 
622  public function getAlgorithm()
623  {
624  return $this->cryptParams ['method'];
625  }
626 
633  public static function makeAsnSegment($type, $string)
634  {
635  switch ($type)
636  {
637  case 0x02 :
638  if (ord ( $string ) > 0x7f)
639  $string = chr ( 0 ) . $string;
640  break;
641  case 0x03 :
642  $string = chr ( 0 ) . $string;
643  break;
644  }
645  $length = strlen ( $string );
646  if ($length < 128)
647  {
648  $output = sprintf ( "%c%c%s", $type, $length, $string );
649  }
650  else if ($length < 0x0100)
651  {
652  $output = sprintf ( "%c%c%c%s", $type, 0x81, $length, $string );
653  }
654  else if ($length < 0x010000)
655  {
656  $output = sprintf ( "%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string );
657  }
658  else
659  {
660  $output = null;
661  }
662  return $output;
663  }
664 
673  public static function convertRSA($modulus, $exponent)
674  {
675  /* make an ASN publicKeyInfo */
676  $exponentEncoding = self::makeAsnSegment ( 0x02, $exponent );
677  $modulusEncoding = self::makeAsnSegment ( 0x02, $modulus );
678  $sequenceEncoding = self::makeAsnSegment ( 0x30, $modulusEncoding . $exponentEncoding );
679  $bitstringEncoding = self::makeAsnSegment ( 0x03, $sequenceEncoding );
680  $rsaAlgorithmIdentifier = pack ( "H*", "300D06092A864886F70D0101010500" );
681  $publicKeyInfo = self::makeAsnSegment ( 0x30, $rsaAlgorithmIdentifier . $bitstringEncoding );
682  /* encode the publicKeyInfo in base64 and add PEM brackets */
683  $publicKeyInfoBase64 = base64_encode ( $publicKeyInfo );
684  $encoding = "-----BEGIN PUBLIC KEY-----\n";
685  $offset = 0;
686  while ( $segment = substr ( $publicKeyInfoBase64, $offset, 64 ) )
687  {
688  $encoding = $encoding . $segment . "\n";
689  $offset += 64;
690  }
691  return $encoding . "-----END PUBLIC KEY-----\n";
692  }
693 
698  public function serializeKey($parent)
699  {
700  }
701 
710  public function getX509Certificate()
711  {
712  return $this->x509Certificate;
713  }
714 
724  public function getX509Thumbprint()
725  {
726  return $this->X509Thumbprint;
727  }
728 
738  public static function fromEncryptedKeyElement(DOMElement $element)
739  {
740  $objenc = new XMLSecEnc ();
741  $objenc->setNode ( $element );
742  if (! $objKey = $objenc->locateKey ())
743  {
744  throw new Exception ( "Unable to locate algorithm for this Encrypted Key" );
745  }
746  $objKey->isEncrypted = true;
747  $objKey->encryptedCtx = $objenc;
748  XMLSecEnc::staticLocateKeyInfo ( $objKey, $element );
749  return $objKey;
750  }
751 
752 }
static convertRSA($modulus, $exponent)
loadKey($key, $isFile=false, $isCert=false)
__construct($type, $params=null)
serializeKey($parent)
verifySignature($data, $signature)
static makeAsnSegment($type, $string)
static staticLocateKeyInfo($objBaseKey=null, $node=null)
Definition: XMLSecEnc.php:462
static fromEncryptedKeyElement(DOMElement $element)
static getRawThumbprint($cert)