/** * Generates a Horde_Mime_Part object, in accordance with RFC 3156, that * contains a public key. * * @return Horde_Mime_Part Object that contains the armored public key. */ public function createMimePart() { $part = new Horde_Mime_Part(); $part->setType('application/pgp-keys'); $part->setHeaderCharset('UTF-8'); $part->setDescription(Horde_Pgp_Translation::t("PGP Public Key")); $part->setContents(strval($this), array('encoding' => '7bit')); return $part; }
/** * Return the unencrypted version of the private key. * * @param string $passphrase The passphrase used to encrypt the key. * * @return Horde_Pgp_Element_PrivateKey Unencrypted key. * @throws Horde_Pgp_Exception */ public function getUnencryptedKey($passphrase = null) { $out = null; foreach ($this->_getSecretKeyPackets() as $k => $v) { if (!strlen($v->encrypted_data)) { continue; } if (is_null($out)) { $out = clone $this->message; } $out[$k] = OpenPGP_Crypt_Symmetric::decryptSecretKey($passphrase, $v); if (is_null($out[$k])) { throw new Horde_Pgp_Exception(Horde_Pgp_Translation::t("Could not unencrypt private key.")); } } return new Horde_Pgp_Element_PrivateKey($out); }
/** * Signs and encrypts a MIME part using PGP. * * @param Horde_Mime_Part $part The part to sign and encrypt. * @param mixed $privkey The private key to use for signing (must * be decrypted). * @param array $opts Additional options: * - cipher: (string) Default symmetric cipher algorithm to use. * - compress: (string) Default compression algorithm. * - pubkeys: (mixed) The public key(s) to use for encryption. * - symmetric: (string) If set, use as symmetric key. * * @return Horde_Mime_Part A signed and encrypted part. * @throws Horde_Pgp_Exception */ public function signAndEncryptPart(Horde_Mime_Part $part, $privkey, array $opts = array()) { /* We use the combined method of sign & encryption in a single * OpenPGP packet (RFC 3156 [6.2]). */ $signed = $this->sign($part->toString(array('canonical' => true, 'headers' => true)), $privkey, $opts); $base = $this->_encryptPart($signed->message, array_merge($opts, array('compress' => 'NONE'))); $base->setDescription(Horde_Pgp_Translation::t("PGP Signed/Encrypted Data")); $base->setContents("This message is in MIME format and has been PGP signed and encrypted.\n"); return $base; }
/** * Verifies text using a PGP public key and a detached signature. * * @param mixed $text The text to be verified * @param mixed $sig The detached signature. * @param mixed $key The public key used for signing. * * @return {@see detach()} * @throws Horde_Pgp_Exception */ public function verifyDetached($text, $sig, $key) { if (is_null($sig)) { if ($text instanceof Horde_Pgp_Element) { $data = $text; } else { $armor = new Horde_Pgp_Armor($text); foreach ($armor as $val) { if ($val instanceof Horde_Pgp_Element_Message || $val instanceof Horde_Pgp_Element_SignedMessage) { $data = $val; break; } } } } else { $sig = Horde_Pgp_Element_Signature::create($sig); $data = new Horde_Pgp_Element_SignedMessage(new OpenPGP_Message(array(new OpenPGP_LiteralDataPacket($text, array('format' => $sig->message[0]->signature_type === 0x0 ? 'b' : 't')), $sig->message[0]))); } return $this->_runInBackend('verify', array($data, Horde_Pgp_Element_PublicKey::create($key)), Horde_Pgp_Translation::t("Could not verify PGP data.")); }
/** * Returns the first matching key for an email address from a public * keyserver. * * @param string $address The email address to search for. * * @return Horde_Pgp_Element_PublicKey The PGP public key. * @throws Horde_Pgp_Exception */ public function getKeyByEmail($address) { /* Connect to the public keyserver. */ $url = $this->_createUrl('/pks/lookup', array('op' => 'index', 'options' => 'mr', 'search' => $address)); try { $output = ltrim($this->_http->get($url)->getBody()); } catch (Horde_Http_Exception $e) { throw new Horde_Pgp_Exception($e); } if (strpos($output, '-----BEGIN PGP PUBLIC KEY BLOCK') !== false) { return Horde_Pgp_Element_PublicKey::create($output); } elseif (strpos($output, 'pub:') !== false) { $output = explode("\n", $output); $keyids = $keyuids = array(); $curid = null; foreach ($output as $line) { if (substr($line, 0, 4) == 'pub:') { $line = explode(':', $line); /* Ignore invalid lines and expired keys. */ if (count($line) != 7 || !empty($line[5]) && $line[5] <= time()) { continue; } $curid = $line[4]; $keyids[$curid] = $line[1]; } elseif (!is_null($curid) && substr($line, 0, 4) == 'uid:') { preg_match("/<([^>]+)>/", $line, $matches); $keyuids[$curid][] = $matches[1]; } } /* Remove keys without a matching UID. */ foreach ($keyuids as $id => $uids) { $match = false; foreach ($uids as $uid) { if ($uid == $address) { $match = true; break; } } if (!$match) { unset($keyids[$id]); } } /* Sort by timestamp to use the newest key. */ if (count($keyids)) { ksort($keyids); return $this->get(array_pop($keyids)); } } throw new Horde_Pgp_Exception(Horde_Pgp_Translation::t("Could not obtain public key from the keyserver.")); }