예제 #1
0
 public function toPEM()
 {
     if ($this->isPublic()) {
         $der = ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::OID, ASN1::encodeOID(self::OID)) . ASN1::encodeDER(ASN1::NULL_TYPE), false) . ASN1::encodeDER(ASN1::BIT_STRING, chr(0x0) . ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['n'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['e'])), false)), false);
         return wordwrap("-----BEGIN PUBLIC KEY-----\n" . base64_encode($der) . "\n-----END PUBLIC KEY-----\n", 64, "\n", true);
     } else {
         $der = ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::INTEGER_TYPE, chr(0)) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['n'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['e'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['d'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['p'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['q'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['dp'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['dq'])) . ASN1::encodeDER(ASN1::INTEGER_TYPE, Util::base64url_decode($this->data['qi'])), false);
         return wordwrap("-----BEGIN RSA PRIVATE KEY-----\n" . base64_encode($der) . "\n-----END RSA PRIVATE KEY-----\n", 64, "\n", true);
     }
 }
예제 #2
0
 public function verify($signature, $data, $keys, $kid = null)
 {
     $key = $this->selectKey($keys, $kid, array(Key::PUBLIC_PROPERTY => true, '~use' => 'sig'));
     if ($key == null) {
         throw new KeyException('Key not found or is invalid');
     }
     $binary = Util::base64url_decode($signature);
     if ($key->getKeyType() == \SimpleJWT\Keys\ECKey::KTY) {
         // For ECDSA signatures, OpenSSL expects a ASN.1 DER SEQUENCE
         list($r, $s) = str_split($binary, (int) (strlen($binary) / 2));
         // Trim leading zeros
         $r = ltrim($r, "");
         $s = ltrim($s, "");
         // Convert r and s from unsigned big-endian integers to signed two's complement
         if (ord($r[0]) > 0x7f) {
             $r = "" . $r;
         }
         if (ord($s[0]) > 0x7f) {
             $s = "" . $s;
         }
         $binary = ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::INTEGER_TYPE, $r) . ASN1::encodeDER(ASN1::INTEGER_TYPE, $s), false);
     }
     $result = openssl_verify($data, $binary, $key->toPEM(), 'SHA' . $this->size);
     switch ($result) {
         case 1:
             return true;
             break;
         case 0:
             return false;
             break;
         default:
             $messages = array();
             while ($message = openssl_error_string()) {
                 $messages[] = $message;
             }
             throw new CryptException('Cannot verify signature: ' . implode("\n", $messages));
             return false;
             break;
     }
 }
예제 #3
0
 /**
  * Detects the format of key data and returns a key object.
  *
  * The supported formats are:
  *
  * - `php` - JSON web key formatted as a PHP associative array
  * - `json` - JSON web key
  * - `pem` - the public or private key encoded in PEM (base64 encoded DER) format
  * - `jwe` - Encrypted JSON web key
  *
  * @param string $data the key data
  * @param string $format the format
  * @param string $password the password, if the key is password protected
  * @param string $alg the algorithm, if the key is password protected
  * @return Key the key object
  * @throws KeyException if an error occurs in reading the data
  */
 public static function create($data, $format = null, $password = null, $alg = 'PBES2-HS256+A128KW')
 {
     // 1. Detect format
     if ($format == null || $format == 'auto') {
         if (is_array($data)) {
             $format = 'php';
         } elseif (json_decode($data, true) != null) {
             $format = 'json';
         } elseif (substr_count($data, '.') == 5) {
             $format = 'jwe';
         } elseif (preg_match('/-----([^-:]+)-----/', $data)) {
             $format = 'pem';
         }
     }
     if ($format == null || $format == 'auto') {
         throw new KeyException('Cannot detect key format');
     }
     // 2. Decode JSON
     if ($format == 'json') {
         $json = json_decode($data, true);
         if (isset($json['ciphertext'])) {
             $format = 'jwe';
         } else {
             $data = $json;
             $format = 'php';
         }
     }
     // 3. JWE
     if ($format == 'jwe') {
         if ($password == null) {
             throw new KeyException('No password for encrypted key');
         } else {
             $keys = KeySet::createFromSecret($password, 'bin');
             try {
                 $jwe = JWE::decrypt($data, $keys, $alg, isset($data['ciphertext']) ? JWE::JSON_FORMAT : JWE::COMPACT_FORMAT);
                 $data = json_decode($jwe->getPlaintext());
                 $format = 'php';
             } catch (CryptException $e) {
                 throw new KeyException('Cannot decrypt key', 0, $e);
             }
         }
     }
     // 4. PHP/JSON
     if ($format == 'php') {
         if ($data != null && isset($data['kty'])) {
             if (isset(self::$jwk_kty_map[$data['kty']])) {
                 return new self::$jwk_kty_map[$data['kty']]($data, 'php');
             }
         }
     }
     // 4. PEM
     if ($format == 'pem') {
         if (preg_match(Key::PEM_PUBLIC, $data, $matches)) {
             $der = base64_decode($matches[1]);
             if ($der === FALSE) {
                 throw new KeyException('Cannot read PEM key');
             }
             $offset = 0;
             $offset += ASN1::readDER($der, $offset, $value);
             // SEQUENCE
             $offset += ASN1::readDER($der, $offset, $value);
             // SEQUENCE
             $offset += ASN1::readDER($der, $offset, $algorithm);
             // OBJECT IDENTIFIER - AlgorithmIdentifier
             $oid = ASN1::decodeOID($algorithm);
             if (isset(self::$oid_map[$oid])) {
                 return new self::$oid_map[$oid]($data, 'pem');
             }
         } else {
             foreach (self::$pem_map as $regex => $cls) {
                 if (preg_match($regex, $data)) {
                     return new $cls($data, 'pem');
                 }
             }
         }
     }
     // 5. Symmetric key
     if ($format == 'base64url' || $format == 'base64' || $format == 'bin') {
         return new SymmetricKey($data, $format);
     }
     return null;
 }
예제 #4
0
 public function toPEM()
 {
     $oid = $this->getOID($this->data['crv']);
     if ($oid == null) {
         throw new KeyException('Unrecognised EC curve');
     }
     if ($this->isPublic()) {
         $der = ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::OID, ASN1::encodeOID(self::EC_OID)) . ASN1::encodeDER(ASN1::OID, ASN1::encodeOID($oid)), false) . ASN1::encodeDER(ASN1::BIT_STRING, chr(0x0) . chr(0x4) . Util::base64url_decode($this->data['x']) . Util::base64url_decode($this->data['y'])), false);
         return wordwrap("-----BEGIN PUBLIC KEY-----\n" . base64_encode($der) . "\n-----END PUBLIC KEY-----\n", 64, "\n", true);
     } else {
         $der = ASN1::encodeDER(ASN1::SEQUENCE, ASN1::encodeDER(ASN1::INTEGER_TYPE, chr(0x1)) . ASN1::encodeDER(ASN1::OCTET_STRING, Util::base64url_decode($this->data['d'])) . ASN1::encodeDER(0x0, ASN1::encodeDER(ASN1::OID, ASN1::encodeOID($oid)), false, ASN1::CONTEXT_CLASS) . ASN1::encodeDER(0x1, ASN1::encodeDER(ASN1::BIT_STRING, chr(0x0) . chr(0x4) . Util::base64url_decode($this->data['x']) . Util::base64url_decode($this->data['y'])), false, ASN1::CONTEXT_CLASS), false);
         return wordwrap("-----BEGIN EC PRIVATE KEY-----\n" . base64_encode($der) . "\n-----END EC PRIVATE KEY-----\n", 64, "\n", true);
     }
 }