public static function encrypt($passphrases_and_keys, $message, $symmetric_algorithm = 9) { list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($symmetric_algorithm); if (!$cipher) { throw new Exception("Unsupported cipher"); } $prefix = crypt_random_string($key_block_bytes); $prefix .= substr($prefix, -2); $key = crypt_random_string($key_bytes); $cipher->setKey($key); $to_encrypt = $prefix . $message->to_bytes(); $mdc = new OpenPGP_ModificationDetectionCodePacket(hash('sha1', $to_encrypt . "Ó", true)); $to_encrypt .= $mdc->to_bytes(); $encrypted = array(new OpenPGP_IntegrityProtectedDataPacket($cipher->encrypt($to_encrypt))); if (!is_array($passphrases_and_keys) && !$passphrases_and_keys instanceof IteratorAggregate) { $passphrases_and_keys = (array) $passphrases_and_keys; } foreach ($passphrases_and_keys as $pass) { if ($pass instanceof OpenPGP_PublicKeyPacket) { if (!in_array($pass->algorithm, array(1, 2, 3))) { throw new Exception("Only RSA keys are supported."); } $crypt_rsa = new OpenPGP_Crypt_RSA($pass); $rsa = $crypt_rsa->public_key(); $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); $esk = $rsa->encrypt(chr($symmetric_algorithm) . $key . pack('n', self::checksum($key))); $esk = pack('n', OpenPGP::bitlength($esk)) . $esk; array_unshift($encrypted, new OpenPGP_AsymmetricSessionKeyPacket($pass->algorithm, $pass->fingerprint(), $esk)); } else { if (is_string($pass)) { $s2k = new OpenPGP_S2K(crypt_random_string(10)); $cipher->setKey($s2k->make_key($pass, $key_bytes)); $esk = $cipher->encrypt(chr($symmetric_algorithm) . $key); array_unshift($encrypted, new OpenPGP_SymmetricSessionKeyPacket($s2k, $esk, $symmetric_algorithm)); } } } return new OpenPGP_Message($encrypted); }
/** * Encrypt data. * * @param mixed $key The list of public keys used to encrypt or a list * of passphrases. * @param mixed $data The data to be PGP encrypted. * @param array $opts Additional options: * - cipher: (integer) Cipher algorithm. * - compress: (integer) Compression algorithm. * * @param Horde_Pgp_Element_Message Encrypted message. */ protected function _encrypt($key, $data, $opts) { $msg = $this->_compressMessageOb($this->_getMessageOb($data), $opts['compress']); /* Following code adapted from OpenPGP_Crypt_Symmetric::encrypt(). */ list($cipher, $key_bytes, $block_bytes) = OpenPGP_Crypt_Symmetric::getCipher($opts['cipher']); $prefix = crypt_random_string($block_bytes); $prefix .= substr($prefix, -2); $to_encrypt = $prefix . $msg->to_bytes(); $mdc = new OpenPGP_ModificationDetectionCodePacket(hash('sha1', $to_encrypt . "Ó", true)); /* This is the symmetric encryption session key. */ $ckey = crypt_random_string($key_bytes); $cipher->setKey($ckey); /* This is the symmetrically encrypted version of plaintext. */ $encrypted = array(new OpenPGP_IntegrityProtectedDataPacket($cipher->encrypt($to_encrypt . $mdc->to_bytes()))); /* Now we need to encrypt the symmetric session key into the various * session key encrypted entities. */ foreach ($key as $k) { /* Symmetric encryption. */ if (is_string($k)) { $s2k = new OpenPGP_S2K(crypt_random_string(8, 2)); // SHA-1 $cipher->setKey($s2k->make_key($k, $key_bytes)); $encrypted[] = new OpenPGP_SymmetricSessionKeyPacket($s2k, $cipher->encrypt(chr($opts['cipher']) . $ckey), $opts['cipher']); continue; } /* Public key encryption. */ switch ($k->algorithm) { case 1: case 2: case 3: $rsa = new OpenPGP_Crypt_RSA($k); $pk = $rsa->public_key(); $pk->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); break; case 16: $pk = new Horde_Pgp_Crypt_Elgamal($k); break; } $pk_encrypt = $pk->encrypt(chr($opts['cipher']) . $ckey . pack('n', OpenPGP_Crypt_Symmetric::checksum($ckey))); $esk = array(); foreach (is_array($pk_encrypt) ? $pk_encrypt : array($pk_encrypt) as $val) { $esk[] = pack('n', OpenPGP::bitlength($val)) . $val; } $encrypted[] = new OpenPGP_AsymmetricSessionKeyPacket($k->algorithm, $k->fingerprint(), implode('', $esk)); } return new Horde_Pgp_Element_Message(new OpenPGP_Message(array_reverse($encrypted))); }