Encryption support
This commit is contained in:
parent
a56799955f
commit
7d776fd605
@ -113,6 +113,13 @@ class OpenPGP {
|
||||
class OpenPGP_S2K {
|
||||
public $type, $hash_algorithm, $salt, $count;
|
||||
|
||||
function __construct($salt='BADSALT', $hash_algorithm=10, $count=65536, $type=3) {
|
||||
$this->type = $type;
|
||||
$this->hash_algorithm = $hash_algorithm;
|
||||
$this->salt = $salt;
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
static function parse(&$input) {
|
||||
$s2k = new OpenPGP_S2k();
|
||||
switch($s2k->type = ord($input{0})) {
|
||||
@ -570,6 +577,13 @@ class OpenPGP_Packet {
|
||||
class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
|
||||
public $version, $keyid, $key_algorithm, $encrypted_data;
|
||||
|
||||
function __construct($key_algorithm='', $keyid='', $encrypted_data='', $version=3) {
|
||||
$this->version = $version;
|
||||
$this->keyid = substr($keyid, -16);
|
||||
$this->key_algorithm = $key_algorithm;
|
||||
$this->encrypted_data = $encrypted_data;
|
||||
}
|
||||
|
||||
function read() {
|
||||
switch($this->version = ord($this->read_byte())) {
|
||||
case 3:
|
||||
@ -1230,6 +1244,13 @@ class OpenPGP_SignaturePacket_EmbeddedSignaturePacket extends OpenPGP_SignatureP
|
||||
class OpenPGP_SymmetricSessionKeyPacket extends OpenPGP_Packet {
|
||||
public $version, $symmetric_algorithm, $s2k, $encrypted_data;
|
||||
|
||||
function __construct($s2k=NULL, $encrypted_data='', $symmetric_algorithm=9, $version=3) {
|
||||
$this->version = $version;
|
||||
$this->symmetric_algorithm = $symmetric_algorithm;
|
||||
$this->s2k = $s2k;
|
||||
$this->encrypted_data = $encrypted_data;
|
||||
}
|
||||
|
||||
function read() {
|
||||
$this->version = ord($this->read_byte());
|
||||
$this->symmetric_algorithm = ord($this->read_byte());
|
||||
@ -1775,6 +1796,10 @@ class OpenPGP_UserAttributePacket extends OpenPGP_Packet {
|
||||
class OpenPGP_IntegrityProtectedDataPacket extends OpenPGP_EncryptedDataPacket {
|
||||
public $version;
|
||||
|
||||
function __construct($data='', $version=1) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
function read() {
|
||||
$this->version = ord($this->read_byte());
|
||||
$this->data = $this->input;
|
||||
@ -1791,7 +1816,24 @@ class OpenPGP_IntegrityProtectedDataPacket extends OpenPGP_EncryptedDataPacket {
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-5.14
|
||||
*/
|
||||
class OpenPGP_ModificationDetectionCodePacket extends OpenPGP_Packet {
|
||||
// TODO
|
||||
function __construct($sha1='') {
|
||||
$this->data = $sha1;
|
||||
}
|
||||
|
||||
function read() {
|
||||
$this->data = $this->input;
|
||||
if(strlen($this->input) != 20) throw new Exception("Bad ModificationDetectionCodePacket");
|
||||
}
|
||||
|
||||
function header_and_body() {
|
||||
$body = $this->body(); // Get body first, we will need it's length
|
||||
if(strlen($body) != 20) throw new Exception("Bad ModificationDetectionCodePacket");
|
||||
return array('header' => "\xD3\x14", 'body' => $body);
|
||||
}
|
||||
|
||||
function body() {
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,10 +1,49 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__FILE__).'/openpgp.php';
|
||||
@include_once dirname(__FILE__).'/openpgp_crypt_rsa.php';
|
||||
require_once 'Crypt/AES.php';
|
||||
require_once 'Crypt/TripleDES.php';
|
||||
require_once 'Crypt/Random.php';
|
||||
|
||||
class OpenPGP_Crypt_AES_TripleDES {
|
||||
public static function encrypt($passphrases_and_keys, $message, $symmetric_algorithm=9) {
|
||||
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($symmetric_algorithm);
|
||||
$prefix = self::randomBytes($key_block_bytes);
|
||||
$prefix .= substr($prefix, -2);
|
||||
|
||||
$key = self::randomBytes($key_bytes);
|
||||
$cipher->setKey($key);
|
||||
|
||||
$to_encrypt = $prefix . $message->to_bytes();
|
||||
$mdc = new OpenPGP_ModificationDetectionCodePacket(hash('sha1', $to_encrypt . "\xD3\x14", 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() . crypt_random() . crypt_random());
|
||||
$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 static function decryptSymmetric($pass, $m) {
|
||||
$epacket = self::getEncryptedData($m);
|
||||
|
||||
@ -41,16 +80,13 @@ class OpenPGP_Crypt_AES_TripleDES {
|
||||
if($packet->s2k_useage == 254) {
|
||||
$chk = substr($material, -20);
|
||||
$material = substr($material, 0, -20);
|
||||
if($chk != hash('sha1', $material)) return NULL;
|
||||
if($chk != hash('sha1', $material, true)) return NULL;
|
||||
} else {
|
||||
$chk = unpack('n', substr($material, -2));
|
||||
$chk = reset($chk);
|
||||
$material = substr($material, 0, -2);
|
||||
|
||||
$mkChk = 0;
|
||||
for($i = 0; $i < strlen($material); $i++) {
|
||||
$mkChk = ($mkChk + ord($material{$i})) % 65536;
|
||||
}
|
||||
$mkChk = self::checksum($material);
|
||||
if($chk != $mkChk) return NULL;
|
||||
}
|
||||
|
||||
@ -139,4 +175,21 @@ class OpenPGP_Crypt_AES_TripleDES {
|
||||
}
|
||||
throw new Exception("Can only decrypt EncryptedDataPacket");
|
||||
}
|
||||
|
||||
public static function randomBytes($n) {
|
||||
$key = '';
|
||||
for($i = 0; $i < $n; $i++) {
|
||||
$key .= crypt_random();
|
||||
}
|
||||
$s2k = new OpenPGP_S2K(crypt_random() . crypt_random() . crypt_random());
|
||||
return $s2k->make_key($key, $n);
|
||||
}
|
||||
|
||||
public static function checksum($s) {
|
||||
$mkChk = 0;
|
||||
for($i = 0; $i < strlen($s); $i++) {
|
||||
$mkChk = ($mkChk + ord($s{$i})) % 65536;
|
||||
}
|
||||
return $mkChk;
|
||||
}
|
||||
}
|
||||
|
@ -15,5 +15,13 @@
|
||||
<testsuite name="KeyVerification">
|
||||
<file>tests/phpseclib_suite.php</file>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="Decryption">
|
||||
<file>tests/phpseclib_suite.php</file>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="Encryption">
|
||||
<file>tests/phpseclib_suite.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
@ -111,3 +111,21 @@ class Decryption extends PHPUnit_Framework_TestCase {
|
||||
$this->assertSame(!!$skey, true);
|
||||
}
|
||||
}
|
||||
|
||||
class Encryption extends PHPUnit_Framework_TestCase {
|
||||
public function testEncryptSymmetric() {
|
||||
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
|
||||
$encrypted = OpenPGP_Crypt_AES_TripleDES::encrypt('secret', new OpenPGP_Message(array($data)));
|
||||
$decrypted = OpenPGP_Crypt_AES_TripleDES::decryptSymmetric('secret', $encrypted);
|
||||
$this->assertEquals($decrypted[0]->data, 'This is text.');
|
||||
}
|
||||
|
||||
public function testEncryptAsymmetric() {
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
|
||||
$encrypted = OpenPGP_Crypt_AES_TripleDES::encrypt($key, new OpenPGP_Message(array($data)));
|
||||
$decryptor = new OpenPGP_Crypt_RSA($key);
|
||||
$decrypted = $decryptor->decrypt($encrypted);
|
||||
$this->assertEquals($decrypted[0]->data, 'This is text.');
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user