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); }
/** */ public function next() { $base64 = true; $class = $end = $end_armor = $ob_class = $start = null; $headers = array(); $stream = $this->_data; while (!($eof = $stream->eof())) { $pos = $stream->pos(); $val = rtrim($stream->getToChar("\n", !is_null($start))); if (is_null($end_armor) && strpos($val, '-----BEGIN PGP ') === 0 && substr($val, -5) === '-----') { $armor = substr($val, 15, strpos($val, '-', 15) - 15); if ($start) { $stream->seek($pos, false); break; } switch ($armor) { case 'MESSAGE': $class = 'Horde_Pgp_Element_Message'; break; case 'PUBLIC KEY BLOCK': $class = 'Horde_Pgp_Element_PublicKey'; break; case 'PRIVATE KEY BLOCK': $class = 'Horde_Pgp_Element_PrivateKey'; break; case 'SIGNATURE': $class = 'Horde_Pgp_Element_Signature'; break; case 'SIGNED MESSAGE': $armor = 'SIGNATURE'; $base64 = false; $class = 'Horde_Pgp_Element_SignedMessage'; break; default: /* Unknown: ignore. */ continue 2; } $end_armor = '-----END PGP ' . $armor . '-----'; } elseif (!is_null($end_armor)) { if (is_null($start)) { if (strlen($val)) { list($h, $v) = explode(':', $val, 2); $headers[trim($h)] = trim($v); } else { $start = $stream->pos(); } } elseif ($val === $end_armor) { $end = $pos; $ob_class = $class; break; } } } if ($eof && (is_null($this->_key) || is_null($start))) { $this->_current = $this->_key = null; return; } if (is_null($ob_class)) { $ob_class = 'Horde_Pgp_Element_Text'; } $pos = $stream->pos(); $data = $stream->getString($start, $end - 1); $stream->seek($pos, false); if ($base64) { /* Get checksum, if it exists. */ if ($pos = strrpos($data, "\n=")) { $checksum = base64_decode(substr($data, $pos + 2, 4)); $data = base64_decode(substr($data, 0, $pos)); Horde_Pgp_Backend_Openpgp::autoload(); $data_checksum = substr(pack('N', OpenPGP::crc24($data)), 1); if ($data_checksum !== $checksum) { // Checksum error! return $this->next(); } } else { $data = base64_decode($data); } } $this->_current = new $ob_class($data, $headers); $this->_key = is_null($this->_key) ? 0 : $this->_key + 1; }
function body() { $bytes = parent::body() . chr($this->s2k_useage); $secret_material = NULL; if ($this->s2k_useage == 255 || $this->s2k_useage == 254) { $bytes .= chr($this->symmetric_algorithm); $bytes .= $this->s2k->to_bytes(); } if ($this->s2k_useage > 0) { $bytes .= $this->encrypted_data; } else { $secret_material = ''; foreach (self::$secret_key_fields[$this->algorithm] as $f) { $f = $this->key[$f]; $secret_material .= pack('n', OpenPGP::bitlength($f)); $secret_material .= $f; } $bytes .= $secret_material; // 2-octet checksum $chk = 0; for ($i = 0; $i < strlen($secret_material); $i++) { $chk = ($chk + ord($secret_material[$i])) % 65536; } $bytes .= pack('n', $chk); } return $bytes; }
/** * @see http://tools.ietf.org/html/rfc4880#section-12.2 * @see http://tools.ietf.org/html/rfc4880#section-3.3 */ function fingerprint() { switch ($this->version) { case 2: case 3: return $this->fingerprint = md5($this->key['n'] . $this->key['e']); case 4: $head = array(chr(0x99), NULL, chr($this->version), pack('N', $this->timestamp), chr($this->algorithm)); $material = array(); foreach ($this->key as $data) { $material[] = pack('n', OpenPGP::bitlength($data)); $material[] = $data; } $material = implode('', $material); $head[1] = pack('n', 6 + strlen($material)); return $this->fingerprint = sha1(implode('', $head) . $material); } }
<?php // USAGE: php examples/deASCIIdeCrypt.php secretkey.asc password message.asc // This will fail if the algo on key or message is not 3DES or AES require_once dirname(__FILE__) . '/../lib/openpgp.php'; require_once dirname(__FILE__) . '/../lib/openpgp_crypt_rsa.php'; require_once dirname(__FILE__) . '/../lib/openpgp_crypt_symmetric.php'; $keyASCII = file_get_contents($argv[1]); $msgASCII = file_get_contents($argv[3]); $keyEncrypted = OpenPGP_Message::parse(OpenPGP::unarmor($keyASCII, 'PGP PRIVATE KEY BLOCK')); // Try each secret key packet foreach ($keyEncrypted as $p) { if (!$p instanceof OpenPGP_SecretKeyPacket) { continue; } $key = OpenPGP_Crypt_Symmetric::decryptSecretKey($argv[2], $p); $msg = OpenPGP_Message::parse(OpenPGP::unarmor($msgASCII, 'PGP MESSAGE')); $decryptor = new OpenPGP_Crypt_RSA($key); $decrypted = $decryptor->decrypt($msg); var_dump($decrypted); }
/** */ public function __toString() { $bytes = $this->message->to_bytes(); if (!strlen($this->_armor)) { return $bytes; } return OpenPGP::enarmor($bytes, 'PGP ' . $this->_armor, array_merge($this->headers, array('Version' => $this->armorVersion))); }
<?php require_once dirname(__FILE__) . '/../lib/openpgp.php'; require_once dirname(__FILE__) . '/../lib/openpgp_crypt_rsa.php'; /* Parse secret key from STDIN, the key must not be password protected */ $wkey = OpenPGP_Message::parse(file_get_contents('php://stdin')); $wkey = $wkey[0]; $string = "This\nis\na\ntest."; /* Create a new literal data packet */ $data = new OpenPGP_LiteralDataPacket($string, array('format' => 'u', 'filename' => 'stuff.txt')); $data->normalize(true); // Clearsign-style normalization of the LiteralDataPacket /* Create a signer from the key */ $sign = new OpenPGP_Crypt_RSA($wkey); /* The message is the signed data packet */ $m = $sign->sign($data); /* Generate clearsigned data */ $packets = $m->signatures()[0]; echo "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n"; // Output normalised data. You could convert line endings here // without breaking the signature, but do not add any // trailing whitespace to lines. echo preg_replace("/^-/", "- -", $packets[0]->data) . "\n"; echo OpenPGP::enarmor($packets[1][0]->to_bytes(), "PGP SIGNATURE");
/** * 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))); }
public function signDocument() { $document = new \StdClass(); foreach ($this->resourceData as $term => $value) { $document->{$term} = $this->normalizeData($value); } unset($document->digital_signature); unset($document->_id); unset($document->_rev); unset($document->doc_id); unset($document->publishing_node); unset($document->update_timestamp); unset($document->node_timestamp); unset($document->create_timestamp); $bencoder = new \LearningRegistry\Bencode\LearningRegistryBencodeEncoderTrial(); $document = (array) $document; $bencodedDocument = utf8_encode($bencoder->encode($document)); $hashedDocument = hash('SHA256', $bencodedDocument); global $loader; if (!isset($loader)) { $loader = $this->getLoader(); } spl_autoload_unregister(array($loader, 'loadClass')); require_once dirname(__FILE__) . '/../OpenPGP/openpgp.php'; require_once dirname(__FILE__) . '/../OpenPGP/openpgp_crypt_rsa.php'; require_once dirname(__FILE__) . '/../OpenPGP/openpgp_crypt_symmetric.php'; $keyASCII = $this->getKey(); $keyEncrypted = \OpenPGP_Message::parse(\OpenPGP::unarmor($keyASCII, 'PGP PRIVATE KEY BLOCK')); foreach ($keyEncrypted as $p) { if (!$p instanceof \OpenPGP_SecretKeyPacket) { continue; } $key = \OpenPGP_Crypt_Symmetric::decryptSecretKey($this->getPassPhrase(), $p); } $data = new \OpenPGP_LiteralDataPacket($hashedDocument, array('format' => 'u')); $sign = new \OpenPGP_Crypt_RSA($key); $m = $sign->sign($data); $packets = $m->signatures()[0]; $message = "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n"; $message .= $packets[0]->data . "\n"; $message .= "-----BEGIN PGP SIGNATURE-----\n\n"; $signed_data = str_replace("-----BEGIN -----", "", str_replace("-----END -----", "", \OpenPGP::enarmor($packets[1][0]->to_bytes(), ""))); $signature = str_split(trim($signed_data), 65); foreach ($signature as $line) { $message .= $line . "\n"; } $message .= "-----END PGP SIGNATURE-----\n"; $this->setSigFields(array('signature' => $message, 'key_owner' => $this->getKeyOwner(), 'key_location' => array($this->getPublicKeyPath()), 'signing_method' => "LR-PGP.1.0")); spl_autoload_register(array($loader, 'loadClass')); $this->document = $this->createDocument(); }