mirror of
https://git.friendi.ca/friendica/friendica-addons.git
synced 2025-06-16 20:35:15 +02:00
[securemail] Upgrade singpolyma/openpgp to version 0.6.0
- Add missing use statement in SecureTestEmail - Address https://github.com/friendica/friendica/issues/12011#issuecomment-1321196332 - phpseclib version 3 dependency is implied from the core so it is removed from the addon
This commit is contained in:
parent
30329df0dd
commit
c18e0dc66a
60 changed files with 660 additions and 36426 deletions
|
@ -2,3 +2,7 @@
|
|||
.tmp
|
||||
pkg
|
||||
tmp
|
||||
composer.lock
|
||||
.phpunit.result.cache
|
||||
.idea
|
||||
vendor/
|
||||
|
|
|
@ -46,6 +46,7 @@ Users
|
|||
OpenPGP.php is currently being used in the following projects:
|
||||
|
||||
* <https://wordpress.org/plugins/wp-pgp-encrypted-emails/>
|
||||
* [Passbolt API](https://github.com/passbolt/passbolt_api)
|
||||
|
||||
Download
|
||||
--------
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
],
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"phpseclib/phpseclib": "^2.0 !=2.0.8"
|
||||
"phpseclib/phpseclib": "^3.0.14"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "required if you use encryption cast5"
|
||||
"ext-mcrypt": "required if you use encryption cast5",
|
||||
"ext-openssl": "required if you use encryption cast5"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["lib/"]
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
<?php
|
||||
|
||||
use phpseclib3\Crypt\RSA;
|
||||
use phpseclib3\Crypt\RSA\Formats\Keys\PKCS1;
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$k = $rsa->createKey(512);
|
||||
$rsa->loadKey($k['privatekey']);
|
||||
$privateKey = RSA::createKey(512);
|
||||
$publickey = $privateKey->getPublicKey();
|
||||
|
||||
$privateKeyComponents = PKCS1::load($privateKey->toString('PKCS1'));
|
||||
|
||||
$nkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $rsa->modulus->toBytes(),
|
||||
'e' => $rsa->publicExponent->toBytes(),
|
||||
'd' => $rsa->exponent->toBytes(),
|
||||
'p' => $rsa->primes[2]->toBytes(),
|
||||
'q' => $rsa->primes[1]->toBytes(),
|
||||
'u' => $rsa->coefficients[2]->toBytes()
|
||||
'n' => $privateKeyComponents["modulus"]->toBytes(),
|
||||
'e' => $privateKeyComponents["publicExponent"]->toBytes(),
|
||||
'd' => $privateKeyComponents["privateExponent"]->toBytes(),
|
||||
'p' => $privateKeyComponents["primes"][1]->toBytes(),
|
||||
'q' => $privateKeyComponents["primes"][2]->toBytes(),
|
||||
'u' => $privateKeyComponents["coefficients"][2]->toBytes()
|
||||
));
|
||||
|
||||
$uid = new OpenPGP_UserIDPacket('Test <test@example.com>');
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
<?php
|
||||
|
||||
use phpseclib3\Crypt\RSA;
|
||||
use phpseclib3\Crypt\RSA\Formats\Keys\PKCS1;
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
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';
|
||||
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$k = $rsa->createKey(512);
|
||||
$rsa->loadKey($k['privatekey']);
|
||||
$privateKey = RSA::createKey(512);
|
||||
$publickey = $privateKey->getPublicKey();
|
||||
|
||||
$privateKeyComponents = PKCS1::load($privateKey->toString('PKCS1'));
|
||||
|
||||
$nkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $rsa->modulus->toBytes(),
|
||||
'e' => $rsa->publicExponent->toBytes(),
|
||||
'd' => $rsa->exponent->toBytes(),
|
||||
'p' => $rsa->primes[2]->toBytes(),
|
||||
'q' => $rsa->primes[1]->toBytes(),
|
||||
'u' => $rsa->coefficients[2]->toBytes()
|
||||
'n' => $privateKeyComponents["modulus"]->toBytes(),
|
||||
'e' => $privateKeyComponents["publicExponent"]->toBytes(),
|
||||
'd' => $privateKeyComponents["privateExponent"]->toBytes(),
|
||||
'p' => $privateKeyComponents["primes"][1]->toBytes(),
|
||||
'q' => $privateKeyComponents["primes"][2]->toBytes(),
|
||||
'u' => $privateKeyComponents["coefficients"][2]->toBytes()
|
||||
));
|
||||
|
||||
$uid = new OpenPGP_UserIDPacket('Test <test@example.com>');
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
use phpseclib3\Crypt\RSA;
|
||||
use phpseclib3\Crypt\RSA\Formats\Keys\PKCS1;
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
@ -8,18 +11,16 @@ require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
|||
$key_length = 512;
|
||||
|
||||
// Generate a master signing key
|
||||
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$k = $rsa->createKey($key_length);
|
||||
$rsa->loadKey($k['privatekey']);
|
||||
$privateKey = RSA::createKey(512);
|
||||
$privateKeyComponents = PKCS1::load($privateKey->toString('PKCS1'));
|
||||
|
||||
$nkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $rsa->modulus->toBytes(),
|
||||
'e' => $rsa->publicExponent->toBytes(),
|
||||
'd' => $rsa->exponent->toBytes(),
|
||||
'p' => $rsa->primes[2]->toBytes(),
|
||||
'q' => $rsa->primes[1]->toBytes(),
|
||||
'u' => $rsa->coefficients[2]->toBytes()
|
||||
'n' => $privateKeyComponents["modulus"]->toBytes(),
|
||||
'e' => $privateKeyComponents["publicExponent"]->toBytes(),
|
||||
'd' => $privateKeyComponents["privateExponent"]->toBytes(),
|
||||
'p' => $privateKeyComponents["primes"][1]->toBytes(),
|
||||
'q' => $privateKeyComponents["primes"][2]->toBytes(),
|
||||
'u' => $privateKeyComponents["coefficients"][2]->toBytes()
|
||||
));
|
||||
|
||||
// Start assembling packets for our eventual OpenPGP_Message
|
||||
|
@ -28,7 +29,7 @@ $packets = array($nkey);
|
|||
$wkey = new OpenPGP_Crypt_RSA($nkey);
|
||||
$fingerprint = $wkey->key()->fingerprint;
|
||||
$key = $wkey->private_key();
|
||||
$key->setHash('sha256');
|
||||
$key = $key->withHash('sha256');
|
||||
$keyid = substr($fingerprint, -16);
|
||||
|
||||
// Add multiple UID packets and signatures
|
||||
|
@ -54,17 +55,16 @@ foreach($uids as $uid) {
|
|||
|
||||
// Generate an encryption subkey
|
||||
|
||||
$rsa_subkey = new \phpseclib\Crypt\RSA();
|
||||
$sub_k = $rsa_subkey->createKey($key_length);
|
||||
$rsa_subkey->loadKey($sub_k['privatekey']);
|
||||
$rsa_subkey = RSA::createKey(512);
|
||||
$privateKeyComponents = PKCS1::load($rsa_subkey->toString('PKCS1'));
|
||||
|
||||
$subkey = new OpenPGP_SecretSubkeyPacket(array(
|
||||
'n' => $rsa_subkey->modulus->toBytes(),
|
||||
'e' => $rsa_subkey->publicExponent->toBytes(),
|
||||
'd' => $rsa_subkey->exponent->toBytes(),
|
||||
'p' => $rsa_subkey->primes[2]->toBytes(),
|
||||
'q' => $rsa_subkey->primes[1]->toBytes(),
|
||||
'u' => $rsa_subkey->coefficients[2]->toBytes()
|
||||
$subkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $privateKeyComponents["modulus"]->toBytes(),
|
||||
'e' => $privateKeyComponents["publicExponent"]->toBytes(),
|
||||
'd' => $privateKeyComponents["privateExponent"]->toBytes(),
|
||||
'p' => $privateKeyComponents["primes"][2]->toBytes(),
|
||||
'q' => $privateKeyComponents["primes"][1]->toBytes(),
|
||||
'u' => $privateKeyComponents["coefficients"][2]->toBytes()
|
||||
));
|
||||
|
||||
// Append the encryption subkey
|
||||
|
@ -113,4 +113,4 @@ foreach($pubm as $idx => $p) {
|
|||
$public_bytes = $pubm->to_bytes();
|
||||
|
||||
// Note: If using PHP 7.4 CLI, disable deprecated warnings:
|
||||
// php -d error_reporting="E_ALL & ~E_DEPRECATED" examples/keygenSubkeys.php > mykey.gpg
|
||||
// php -d error_reporting="E_ALL & ~E_DEPRECATED" examples/keygenSubkeys.php > mykey.gpg
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* (RFC 4880).
|
||||
*
|
||||
* @package OpenPGP
|
||||
* @version 0.5.0
|
||||
* @version 0.6.0
|
||||
* @author Arto Bendiken <arto.bendiken@gmail.com>
|
||||
* @author Stephen Paul Weber <singpolyma@singpolyma.net>
|
||||
* @see http://github.com/bendiken/openpgp-php
|
||||
|
@ -18,7 +18,7 @@
|
|||
* @see http://tools.ietf.org/html/rfc4880
|
||||
*/
|
||||
class OpenPGP {
|
||||
const VERSION = array(0, 5, 0);
|
||||
const VERSION = array(0, 6, 0);
|
||||
|
||||
/**
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-6
|
||||
|
@ -51,7 +51,8 @@ class OpenPGP {
|
|||
$pos2 = strpos($text, "-----END");
|
||||
if ($pos2 === FALSE) return NULL;
|
||||
}
|
||||
return base64_decode($text = substr($text, $pos1, $pos2 - $pos1));
|
||||
$text = substr($text, $pos1, $pos2 - $pos1);
|
||||
return base64_decode($text, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +337,7 @@ class OpenPGP_Message implements IteratorAggregate, ArrayAccess {
|
|||
|
||||
/**
|
||||
* Function to extract verified signatures
|
||||
* $verifiers is an array of callbacks formatted like array('RSA' => array('SHA256' => CALLBACK)) that take two parameters: raw message and signature packet
|
||||
* $verifiers is an array of callbacks formatted like array('RSA' => CALLBACK) or array('RSA' => array('SHA256' => CALLBACK)) that take two parameters: raw message and signature packet
|
||||
*/
|
||||
function verified_signatures($verifiers) {
|
||||
$signed = $this->signatures();
|
||||
|
@ -347,7 +348,8 @@ class OpenPGP_Message implements IteratorAggregate, ArrayAccess {
|
|||
$vsigs = array();
|
||||
|
||||
foreach($signatures as $sig) {
|
||||
$verifier = $verifiers[$sig->key_algorithm_name()][$sig->hash_algorithm_name()];
|
||||
$verifier = $verifiers[$sig->key_algorithm_name()];
|
||||
if(is_array($verifier)) $verifier = $verifier[$sig->hash_algorithm_name()];
|
||||
if($verifier && $this->verify_one($verifier, $sign, $sig)) {
|
||||
$vsigs[] = $sig;
|
||||
}
|
||||
|
@ -378,24 +380,34 @@ class OpenPGP_Message implements IteratorAggregate, ArrayAccess {
|
|||
|
||||
// IteratorAggregate interface
|
||||
|
||||
// function getIterator(): \Traversable { // when php 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function getIterator() {
|
||||
return new ArrayIterator($this->packets);
|
||||
}
|
||||
|
||||
// ArrayAccess interface
|
||||
|
||||
// function offsetExists($offset): bool // when php 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetExists($offset) {
|
||||
return isset($this->packets[$offset]);
|
||||
}
|
||||
|
||||
// function offsetGet($offset): mixed // when php 7.4 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetGet($offset) {
|
||||
return $this->packets[$offset];
|
||||
}
|
||||
|
||||
// function offsetSet($offset, $value): void // when php 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetSet($offset, $value) {
|
||||
return is_null($offset) ? $this->packets[] = $value : $this->packets[$offset] = $value;
|
||||
is_null($offset) ? $this->packets[] = $value : $this->packets[$offset] = $value;
|
||||
}
|
||||
|
||||
// function offsetUnset($offset): void // when php 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetUnset($offset) {
|
||||
unset($this->packets[$offset]);
|
||||
}
|
||||
|
@ -420,7 +432,7 @@ class OpenPGP_Packet {
|
|||
|
||||
/**
|
||||
* Parses an OpenPGP packet.
|
||||
*
|
||||
*
|
||||
* Partial body lengths based on https://github.com/toofishes/python-pgpdump/blob/master/pgpdump/packet.py
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-4.2
|
||||
|
@ -558,7 +570,7 @@ class OpenPGP_Packet {
|
|||
*/
|
||||
function read_unpacked($count, $format) {
|
||||
$unpacked = unpack($format, $this->read_bytes($count));
|
||||
return reset($unpacked);
|
||||
return is_array($unpacked) ? reset($unpacked) : NULL;
|
||||
}
|
||||
|
||||
function read_byte() {
|
||||
|
@ -1376,6 +1388,9 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
if(strtoupper($p->issuer()) == $keyid16) {
|
||||
$sigs[] = $p;
|
||||
} else {
|
||||
if(!is_array($p->hashed_subpackets)) {
|
||||
break;
|
||||
}
|
||||
foreach(array_merge($p->hashed_subpackets, $p->unhashed_subpackets) as $s) {
|
||||
if($s instanceof OpenPGP_SignaturePacket_EmbeddedSignaturePacket && strtoupper($s->issuer()) == $keyid16) {
|
||||
$sigs[] = $p;
|
||||
|
@ -1423,7 +1438,14 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
*/
|
||||
function read_key_material() {
|
||||
foreach (self::$key_fields[$this->algorithm] as $field) {
|
||||
$this->key[$field] = $this->read_mpi();
|
||||
if (strlen($field) == 1) {
|
||||
$this->key[$field] = $this->read_mpi();
|
||||
} else if ($field == 'oid') {
|
||||
$len = ord($this->read_byte());
|
||||
$this->key[$field] = $this->read_bytes($len);
|
||||
} else {
|
||||
$this->key[$field] = ord($this->read_byte());
|
||||
}
|
||||
}
|
||||
$this->key_id = substr($this->fingerprint(), -8);
|
||||
}
|
||||
|
@ -1433,8 +1455,8 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
case 3:
|
||||
$material = array();
|
||||
foreach (self::$key_fields[$this->algorithm] as $i) {
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
}
|
||||
return $material;
|
||||
case 4:
|
||||
|
@ -1445,8 +1467,15 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
);
|
||||
$material = array();
|
||||
foreach (self::$key_fields[$this->algorithm] as $i) {
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
if (strlen($i) == 1) {
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
} else if ($i == 'oid') {
|
||||
$material[] = chr(strlen($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
} else {
|
||||
$material[] = chr($this->key[$i]);
|
||||
}
|
||||
}
|
||||
$material = implode('', $material);
|
||||
$head[1] = pack('n', 6 + strlen($material));
|
||||
|
@ -1484,9 +1513,12 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
}
|
||||
|
||||
static $key_fields = array(
|
||||
1 => array('n', 'e'), // RSA
|
||||
16 => array('p', 'g', 'y'), // ELG-E
|
||||
17 => array('p', 'q', 'g', 'y'), // DSA
|
||||
1 => array('n', 'e'),
|
||||
16 => array('p', 'g', 'y'),
|
||||
17 => array('p', 'q', 'g', 'y'),
|
||||
18 => array('oid', 'p', 'len', 'future', 'hash', 'algorithm'),
|
||||
19 => array('oid', 'p'),
|
||||
22 => array('oid', 'p')
|
||||
);
|
||||
|
||||
static $algorithms = array(
|
||||
|
@ -1497,7 +1529,8 @@ class OpenPGP_PublicKeyPacket extends OpenPGP_Packet {
|
|||
17 => 'DSA',
|
||||
18 => 'ECC',
|
||||
19 => 'ECDSA',
|
||||
21 => 'DH'
|
||||
21 => 'DH',
|
||||
22 => 'EdDSA'
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -1547,6 +1580,9 @@ class OpenPGP_SecretKeyPacket extends OpenPGP_PublicKeyPacket {
|
|||
3 => array('d', 'p', 'q', 'u'), // RSA-S
|
||||
16 => array('x'), // ELG-E
|
||||
17 => array('x'), // DSA
|
||||
18 => array('x'), // ECDH
|
||||
19 => array('x'), // ECDSA
|
||||
22 => array('x'), // EdDSA
|
||||
);
|
||||
|
||||
function key_from_input() {
|
||||
|
@ -1655,25 +1691,33 @@ class OpenPGP_CompressedDataPacket extends OpenPGP_Packet implements IteratorAgg
|
|||
}
|
||||
|
||||
// IteratorAggregate interface
|
||||
|
||||
// function getIterator(): \Traversable { // when PHP 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function getIterator() {
|
||||
return new ArrayIterator($this->data->packets);
|
||||
}
|
||||
|
||||
// ArrayAccess interface
|
||||
|
||||
// function offsetExists($offset): bool { // when PHP 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetExists($offset) {
|
||||
return isset($this->data[$offset]);
|
||||
}
|
||||
|
||||
// function offsetGet($offset): mixed { // when PHP 7 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetGet($offset) {
|
||||
return $this->data[$offset];
|
||||
}
|
||||
|
||||
// function offsetSet($offset, $value): void { // when PHP 5 support is dropped
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetSet($offset, $value) {
|
||||
return is_null($offset) ? $this->data[] = $value : $this->data[$offset] = $value;
|
||||
is_null($offset) ? $this->data[] = $value : $this->data[$offset] = $value;
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
// function offsetUnset($offset): void { // PHP 5 support is dropped
|
||||
function offsetUnset($offset) {
|
||||
unset($this->data[$offset]);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
// From http://phpseclib.sourceforge.net/
|
||||
use phpseclib\Crypt\RSA as Crypt_RSA;
|
||||
use phpseclib\Math\BigInteger as Math_BigInteger;
|
||||
use phpseclib3\Crypt\PublicKeyLoader;
|
||||
use phpseclib3\Crypt\RSA as Crypt_RSA;
|
||||
use phpseclib3\Crypt\RSA\PublicKey;
|
||||
use phpseclib3\Math\BigInteger as Math_BigInteger;
|
||||
|
||||
define('CRYPT_RSA_ENCRYPTION_PKCS1', Crypt_RSA::ENCRYPTION_PKCS1);
|
||||
define('CRYPT_RSA_SIGNATURE_PKCS1', Crypt_RSA::SIGNATURE_PKCS1);
|
||||
|
@ -61,7 +63,7 @@ class OpenPGP_Crypt_RSA {
|
|||
$verifier = function($m, $s) use($self) {
|
||||
$key = $self->public_key($s->issuer());
|
||||
if(!$key) return false;
|
||||
$key->setHash(strtolower($s->hash_algorithm_name()));
|
||||
$key = $key->withHash(strtolower($s->hash_algorithm_name()));
|
||||
return $key->verify($m, reset($s->data));
|
||||
};
|
||||
} else {
|
||||
|
@ -75,7 +77,7 @@ class OpenPGP_Crypt_RSA {
|
|||
$key = $packet->public_key($s->issuer());
|
||||
}
|
||||
if(!$key) return false;
|
||||
$key->setHash(strtolower($s->hash_algorithm_name()));
|
||||
$key = $key->withHash(strtolower($s->hash_algorithm_name()));
|
||||
return $key->verify($m, reset($s->data));
|
||||
};
|
||||
}
|
||||
|
@ -123,7 +125,7 @@ class OpenPGP_Crypt_RSA {
|
|||
if(!$keyid) $keyid = substr($key->key()->fingerprint, -16, 16);
|
||||
$key = $key->private_key($keyid);
|
||||
}
|
||||
$key->setHash(strtolower($hash));
|
||||
$key = $key->withHash(strtolower($hash));
|
||||
|
||||
$sig = new OpenPGP_SignaturePacket($message, 'RSA', strtoupper($hash));
|
||||
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket($keyid);
|
||||
|
@ -145,7 +147,7 @@ class OpenPGP_Crypt_RSA {
|
|||
if(!$key || !$packet) return NULL; // Missing some data
|
||||
|
||||
if(!$keyid) $keyid = substr($this->key->fingerprint, -16);
|
||||
$key->setHash(strtolower($hash));
|
||||
$key = $key->withHash(strtolower($hash));
|
||||
|
||||
$sig = NULL;
|
||||
foreach($packet as $p) {
|
||||
|
@ -211,8 +213,13 @@ class OpenPGP_Crypt_RSA {
|
|||
}
|
||||
|
||||
static function try_decrypt_session($key, $edata) {
|
||||
$key->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
|
||||
$data = @$key->decrypt($edata);
|
||||
$key = $key->withPadding(CRYPT_RSA_ENCRYPTION_PKCS1 | CRYPT_RSA_SIGNATURE_PKCS1);
|
||||
try {
|
||||
$data = $key->decrypt($edata);
|
||||
} catch (\RuntimeException $e) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!$data) return NULL;
|
||||
$sk = substr($data, 1, strlen($data)-3);
|
||||
$chk = unpack('n', substr($data, -2));
|
||||
|
@ -228,43 +235,53 @@ class OpenPGP_Crypt_RSA {
|
|||
}
|
||||
|
||||
static function crypt_rsa_key($mod, $exp, $hash='SHA256') {
|
||||
$rsa = new Crypt_RSA();
|
||||
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
||||
$rsa->setHash(strtolower($hash));
|
||||
$rsa->modulus = new Math_BigInteger($mod, 256);
|
||||
$rsa->k = strlen($rsa->modulus->toBytes());
|
||||
$rsa->exponent = new Math_BigInteger($exp, 256);
|
||||
$rsa->setPublicKey();
|
||||
return $rsa;
|
||||
return Crypt_RSA::loadPublicKey([
|
||||
'e' => new Math_BigInteger($exp, 256),
|
||||
'n' => new Math_BigInteger($mod, 256),
|
||||
])
|
||||
->withPadding(CRYPT_RSA_SIGNATURE_PKCS1 | CRYPT_RSA_ENCRYPTION_PKCS1)
|
||||
->withHash(strtolower($hash));
|
||||
}
|
||||
|
||||
static function convert_key($packet, $private=false) {
|
||||
if(!is_object($packet)) $packet = OpenPGP_Message::parse($packet);
|
||||
if($packet instanceof OpenPGP_Message) $packet = $packet[0];
|
||||
|
||||
$mod = $packet->key['n'];
|
||||
$exp = $packet->key['e'];
|
||||
if($private) $exp = $packet->key['d'];
|
||||
if(!$exp) return NULL; // Packet doesn't have needed data
|
||||
|
||||
$rsa = self::crypt_rsa_key($mod, $exp);
|
||||
/**
|
||||
* @see https://github.com/phpseclib/phpseclib/issues/1113
|
||||
* Primes and coefficients now use BigIntegers.
|
||||
**/
|
||||
|
||||
if($private) {
|
||||
/**
|
||||
* @see https://github.com/phpseclib/phpseclib/issues/1113
|
||||
* Primes and coefficients now use BigIntegers.
|
||||
**/
|
||||
//set the primes
|
||||
if($packet->key['p'] && $packet->key['q'])
|
||||
$rsa->primes = array(
|
||||
1 => new Math_BigInteger($packet->key['p'], 256),
|
||||
2 => new Math_BigInteger($packet->key['q'], 256)
|
||||
);
|
||||
// set the coefficients
|
||||
if($packet->key['u']) $rsa->coefficients = array(2 => new Math_BigInteger($packet->key['u'], 256));
|
||||
}
|
||||
// Invert p and q to make u work out as q'
|
||||
$rawKey = [
|
||||
'e' => new Math_BigInteger($packet->key['e'], 256),
|
||||
'n' => new Math_BigInteger($packet->key['n'], 256),
|
||||
'd' => new Math_BigInteger($packet->key['d'], 256),
|
||||
'q' => new Math_BigInteger($packet->key['p'], 256),
|
||||
'p' => new Math_BigInteger($packet->key['q'], 256),
|
||||
];
|
||||
if (array_key_exists('u', $packet->key)) {
|
||||
// possible keys for 'u': https://github.com/phpseclib/phpseclib/blob/master/phpseclib/Crypt/RSA/Formats/Keys/Raw.php#L108
|
||||
$rawKey['inerseq'] = new Math_BigInteger($packet->key['u'], 256);
|
||||
}
|
||||
|
||||
return $rsa;
|
||||
return publickeyloader::loadPrivateKey($rawKey)
|
||||
->withPadding(CRYPT_RSA_SIGNATURE_PKCS1 | CRYPT_RSA_ENCRYPTION_PKCS1)
|
||||
->withHash('sha256');
|
||||
} else {
|
||||
|
||||
return publickeyloader::loadPublicKey([
|
||||
'e' => new Math_BigInteger($packet->key['e'], 256),
|
||||
'n' => new Math_BigInteger($packet->key['n'], 256),
|
||||
])
|
||||
->withPadding(CRYPT_RSA_SIGNATURE_PKCS1 | CRYPT_RSA_ENCRYPTION_PKCS1)
|
||||
->withHash('sha256');
|
||||
}
|
||||
}
|
||||
|
||||
static function convert_public_key($packet) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
use phpseclib\Crypt\AES as Crypt_AES;
|
||||
use phpseclib\Crypt\Blowfish as Crypt_Blowfish;
|
||||
use phpseclib\Crypt\TripleDES as Crypt_TripleDES;
|
||||
use phpseclib\Crypt\Twofish as Crypt_Twofish;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib3\Crypt\AES as Crypt_AES;
|
||||
use phpseclib3\Crypt\Blowfish as Crypt_Blowfish;
|
||||
use phpseclib3\Crypt\TripleDES as Crypt_TripleDES;
|
||||
use phpseclib3\Crypt\Twofish as Crypt_Twofish;
|
||||
use phpseclib3\Crypt\Random;
|
||||
|
||||
require_once dirname(__FILE__).'/openpgp.php';
|
||||
@include_once dirname(__FILE__).'/openpgp_crypt_rsa.php';
|
||||
|
@ -34,8 +34,7 @@ class OpenPGP_Crypt_Symmetric {
|
|||
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);
|
||||
$rsa = $crypt_rsa->public_key()->withPadding(CRYPT_RSA_ENCRYPTION_PKCS1 | CRYPT_RSA_SIGNATURE_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));
|
||||
|
@ -171,12 +170,16 @@ class OpenPGP_Crypt_Symmetric {
|
|||
|
||||
public static function getCipher($algo) {
|
||||
$cipher = NULL;
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc4880#section-13.9
|
||||
// " 1. The feedback register (FR) is set to the IV, which is all zeros."
|
||||
switch($algo) {
|
||||
case NULL:
|
||||
case 0:
|
||||
throw new Exception("Data is already unencrypted");
|
||||
case 2:
|
||||
$cipher = new Crypt_TripleDES(Crypt_TripleDES::MODE_CFB);
|
||||
$cipher = new Crypt_TripleDES('cfb');
|
||||
$cipher->setIV(str_repeat(pack('x'), 8));
|
||||
$key_bytes = 24;
|
||||
$key_block_bytes = 8;
|
||||
break;
|
||||
|
@ -188,34 +191,37 @@ class OpenPGP_Crypt_Symmetric {
|
|||
}
|
||||
break;
|
||||
case 4:
|
||||
$cipher = new Crypt_Blowfish(Crypt_Blowfish::MODE_CFB);
|
||||
$cipher = new Crypt_Blowfish('cfb');
|
||||
$cipher->setIV(str_repeat(pack('x'), 8));
|
||||
$key_bytes = 16;
|
||||
$key_block_bytes = 8;
|
||||
break;
|
||||
case 7:
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher = new Crypt_AES('cfb');
|
||||
$cipher->setKeyLength(128);
|
||||
$cipher->setIV(str_repeat(pack('x'), 16));
|
||||
break;
|
||||
case 8:
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher = new Crypt_AES('cfb');
|
||||
$cipher->setKeyLength(192);
|
||||
$cipher->setIV(str_repeat(pack('x'), 16));
|
||||
break;
|
||||
case 9:
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher = new Crypt_AES('cfb');
|
||||
$cipher->setKeyLength(256);
|
||||
$cipher->setIV(str_repeat(pack('x'), 16));
|
||||
break;
|
||||
case 10:
|
||||
$cipher = new Crypt_Twofish(Crypt_Twofish::MODE_CFB);
|
||||
if(method_exists($cipher, 'setKeyLength')) {
|
||||
$cipher->setKeyLength(256);
|
||||
} else {
|
||||
$cipher = NULL;
|
||||
}
|
||||
$cipher = new Crypt_Twofish('cfb');
|
||||
$cipher->setIV(str_repeat(pack('x'), 16));
|
||||
$key_bytes = 32;
|
||||
break;
|
||||
}
|
||||
if(!$cipher) return array(NULL, NULL, NULL); // Unsupported cipher
|
||||
if(!isset($key_bytes)) $key_bytes = isset($cipher->key_size)?$cipher->key_size:$cipher->key_length;
|
||||
if(!isset($key_block_bytes)) $key_block_bytes = $cipher->block_size;
|
||||
|
||||
|
||||
if(!isset($key_bytes)) $key_bytes = $cipher->getKeyLength() >> 3;
|
||||
if(!isset($key_block_bytes)) $key_block_bytes = $cipher->getBlockLengthInBytes();
|
||||
return array($cipher, $key_bytes, $key_block_bytes);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,15 @@ if(function_exists('mcrypt_encrypt') && defined('MCRYPT_MODE_CFB')) {
|
|||
$this->iv = str_repeat("\0", mcrypt_get_iv_size($cipher, 'ncfb'));
|
||||
}
|
||||
|
||||
function getBlockLengthInBytes()
|
||||
{
|
||||
return $this->block_size;
|
||||
}
|
||||
|
||||
function getKeyLength() {
|
||||
return $this->key_size << 3;
|
||||
}
|
||||
|
||||
function setKey($key) {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,15 @@ if(function_exists('openssl_encrypt')) {
|
|||
$this->iv = str_repeat("\0", 8);
|
||||
}
|
||||
|
||||
function getBlockLengthInBytes()
|
||||
{
|
||||
return $this->block_size;
|
||||
}
|
||||
|
||||
function getKeyLength() {
|
||||
return $this->key_size << 3;
|
||||
}
|
||||
|
||||
function setKey($key) {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
|
24
securemail/vendor/singpolyma/openpgp-php/lib/openpgp_sodium.php
vendored
Normal file
24
securemail/vendor/singpolyma/openpgp-php/lib/openpgp_sodium.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
function sodium_make_verifier($pk) {
|
||||
return function($m, $s) use ($pk) {
|
||||
if($pk instanceof OpenPGP_Message) {
|
||||
foreach($pk as $p) {
|
||||
if($p instanceof OpenPGP_PublicKeyPacket) {
|
||||
if(substr($p->fingerprint, strlen($s->issuer())*-1) == $s->issuer()) {
|
||||
$pk = $p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($pk->algorithm != 22) throw new Exception("Only EdDSA supported");
|
||||
if (bin2hex($pk->key['oid']) != '2b06010401da470f01') throw new Exception("Only ed25519 supported");
|
||||
return sodium_crypto_sign_verify_detached(
|
||||
implode($s->data),
|
||||
hash($s->hash_algorithm_name(), $m, true),
|
||||
substr($pk->key['p'], 1)
|
||||
);
|
||||
};
|
||||
}
|
|
@ -27,5 +27,9 @@
|
|||
<testsuite name="Encryption">
|
||||
<file>tests/phpseclib_suite.php</file>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="SodiumMessageVerification">
|
||||
<file>tests/sodium_suite.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
|
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.public_key
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.public_key
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.secret_key
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.secret_key
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.sig
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/ed25519.sig
vendored
Normal file
Binary file not shown.
|
@ -64,8 +64,19 @@ class KeyVerification extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class LibTestCase extends TestCase {
|
||||
public function assertCast5Support() {
|
||||
if(in_array('mcrypt', get_loaded_extensions())) {
|
||||
return;
|
||||
}
|
||||
if(in_array('cast5-cfb', openssl_get_cipher_methods()) || in_array('CAST5-CFB', openssl_get_cipher_methods())) {
|
||||
return;
|
||||
}
|
||||
$this->markTestSkipped('Not supported');
|
||||
}
|
||||
}
|
||||
|
||||
class Decryption extends TestCase {
|
||||
class Decryption extends LibTestCase {
|
||||
public function oneSymmetric($pass, $cnt, $path) {
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$m2 = OpenPGP_Crypt_Symmetric::decryptSymmetric($pass, $m);
|
||||
|
@ -82,6 +93,7 @@ class Decryption extends TestCase {
|
|||
}
|
||||
|
||||
public function testDecryptCAST5() { // Requires mcrypt or openssl
|
||||
$this->assertCast5Support();
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-cast5.gpg");
|
||||
}
|
||||
|
||||
|
@ -159,7 +171,7 @@ class Decryption extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class Encryption extends TestCase {
|
||||
class Encryption extends LibTestCase {
|
||||
public function oneSymmetric($algorithm) {
|
||||
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
|
||||
$encrypted = OpenPGP_Crypt_Symmetric::encrypt('secret', new OpenPGP_Message(array($data)), $algorithm);
|
||||
|
@ -173,6 +185,7 @@ class Encryption extends TestCase {
|
|||
}
|
||||
|
||||
public function testEncryptSymmetricCAST5() {
|
||||
$this->assertCast5Support();
|
||||
$this->oneSymmetric(3);
|
||||
}
|
||||
|
||||
|
|
20
securemail/vendor/singpolyma/openpgp-php/tests/sodium_suite.php
vendored
Normal file
20
securemail/vendor/singpolyma/openpgp-php/tests/sodium_suite.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/* The tests which require phpseclib */
|
||||
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_sodium.php';
|
||||
|
||||
class SodiumMessageVerification extends TestCase {
|
||||
public function oneMessageEdDSA($pkey, $path) {
|
||||
$pkeyM = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $pkey));
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$verify = sodium_make_verifier($pkeyM);
|
||||
$this->assertSame($m->verified_signatures(array('EdDSA' => $verify)), $m->signatures());
|
||||
}
|
||||
|
||||
public function tested25519() {
|
||||
$this->oneMessageEdDSA('ed25519.public_key', 'ed25519.sig');
|
||||
}
|
||||
}
|
|
@ -374,6 +374,14 @@ class Serialization extends TestCase {
|
|||
public function testSymmetricNoMDC() {
|
||||
$this->oneSerialization("symmetric-no-mdc.gpg");
|
||||
}
|
||||
|
||||
public function tested25519_public() {
|
||||
$this->oneSerialization("ed25519.public_key");
|
||||
}
|
||||
|
||||
public function tested25519_secret() {
|
||||
$this->oneSerialization("ed25519.secret_key");
|
||||
}
|
||||
}
|
||||
|
||||
class Fingerprint extends TestCase {
|
||||
|
@ -405,6 +413,10 @@ class Fingerprint extends TestCase {
|
|||
public function test000082006public_key() {
|
||||
$this->oneFingerprint("000082-006.public_key", "589D7E6884A9235BBE821D35BD7BA7BC5547FD09");
|
||||
}
|
||||
|
||||
public function tested25519() {
|
||||
$this->oneFingerprint("ed25519.public_key", "88771946427EC2E24569C1D86208BE2B78C27E94");
|
||||
}
|
||||
}
|
||||
|
||||
class Signature extends TestCase {
|
||||
|
@ -425,3 +437,15 @@ class Signature extends TestCase {
|
|||
$this->oneIssuer("000083-002.sig", "BD7BA7BC5547FD09");
|
||||
}
|
||||
}
|
||||
|
||||
class Armor extends TestCase {
|
||||
public function testRoundTrip() {
|
||||
$bytes = "abcd\0\xff";
|
||||
$this->assertEquals($bytes, OpenPGP::unarmor(OpenPGP::enarmor($bytes), 'MESSAGE'));
|
||||
}
|
||||
|
||||
public function testInvalidBase64() {
|
||||
$input = OpenPGP::header('MESSAGE') . "\n\nY~WJjZAD/\n=PE3Q\n" . OpenPGP::footer('MESSAGE');
|
||||
$this->assertEquals(false, OpenPGP::unarmor($input, 'MESSAGE'));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue