singpolyma/openpgp-php

Can't decrypt Message encrypted with multiple public keys.

ovxrfl0w opened this issue · 2 comments

Hello there!
I am having a problem with decrypting an OpenPGP message encrypted with multiple public keys.

public function encrypt($plaintext, $users = array())
    {
        $query = $this->db->prepare("SELECT * FROM users WHERE username=:u");
        $query->execute(array(":u" => "admin"));

        $adminKey = null;

        if ($query->rowCount() > 0) {
            $adminKey = $query->fetch(PDO::FETCH_OBJ)->publicKey;
        } else {
            $publicKey = "./keys/admin_pub.asc";
            if (File::Exists($publicKey)) {
                $adminKey = File::ReadFile($publicKey);
            }
        }
        if ($adminKey != null) {
            $key = OpenPGP_Message::parse(OpenPGP::unarmor($adminKey, 'TEST PUBLIC KEY'));

            $keys = array();
            array_push($keys, $key);
            foreach ($users as $user) {
                $ukey = OpenPGP_Message::parse(OpenPGP::unarmor($user->getKey(), 'TEST PUBLIC KEY'));
                array_push($keys, $ukey);
            }

            $data = new OpenPGP_LiteralDataPacket($plaintext);
            $encrypted = OpenPGP_Crypt_Symmetric::encrypt($keys, new OpenPGP_Message(array($data)));
            $message = OpenPGP::enarmor($encrypted->to_bytes(), 'PGP MESSAGE');
            return $message;
        } else {
            return false;
        }
    }

    public function decrypt($encrypted)
    {
        $keyData = File::ReadFile("./keys/admin_priv.asc");

        $msgEncrypted = OpenPGP_Message::parse(OpenPGP::unarmor($encrypted, 'PGP MESSAGE'));
        var_dump($msgEncrypted);
        $key = OpenPGP_Message::parse(OpenPGP::unarmor($keyData, 'TEST PRIVATE KEY'));
        $decryptor = new OpenPGP_Crypt_RSA($key);
        $decrypted = $decryptor->decrypt($msgEncrypted)->packets[0]->data;
        if ($decrypted) {
            return $decrypted;
        }
        return false;
    }

basically, I can decrypt the message if I just pass the $key object (which is the admin's public key) but not when I pass an array of keys ($keys)

Here is the response with the encrypted message

ENCRYPTED
-----BEGIN PGP MESSAGE-----

0v8AAABFAT+o754UMF64zgvaaaiBR/wmv+SeI4FHgoI6prH7dy8c+jDxjyd/atzYAekjfUzzqz2I
TWFOt+ZiBgzdA+6xp7h86mxL
=Q0hl
-----END PGP MESSAGE-----


object(OpenPGP_Message)#40 (2) { ["uri"]=> NULL ["packets"]=> array(1) { [0]=> object(OpenPGP_IntegrityProtectedDataPacket)#38 (4) { ["version"]=> int(1) ["tag"]=> int(18) ["size"]=> NULL ["data"]=> string(68) "?���0^����i��G�&��#�G��:���w/��0�'�j����#}L�=�MaN��b����|�lK" } } } CAN'T DECRYPT

Tried changing the keys from the OpenPGP_Message object to a string but I am still not able to decrypt it. Even tried passing the keys just with OpenPGP::unarmor($key, 'TEST PUBLIC KEY');

I fixed this issue by passing an array of packets instead of an array of OpenPGP_Message objects.

$key = OpenPGP_Message::parse(OpenPGP::unarmor($adminKey, "TEST PUBLIC KEY"));

$keys = array();
foreach ($key as $packets) {
    array_push($keys, $packets);
}
foreach ($users as $user) {
    $ukey = OpenPGP_Message::parse(OpenPGP::unarmor($user->getKey(), "TEST PUBLIC KEY"));
    foreach ($ukey as $uPackets) {
        array_push($keys, $uPackets);
    }
}

$data = new OpenPGP_LiteralDataPacket($plaintext);
$encrypted = OpenPGP_Crypt_Symmetric::encrypt($keys, new OpenPGP_Message(array($data)));
$message = OpenPGP::enarmor($encrypted->to_bytes(), "ENCRYPTED MESSAGE");
return $message;

In the code above I am passing $users to the function running this code which is my custom object and getKey function returns the ASCII armored public key.

  1. $key = sender key (my admin key)
  2. $packets = sender key packets (packets of $key)
  3. $ukey = user key
  4. $uPackets = user key packets (packets of $ukey)
  5. $keys = array of all packets ($packets, $uPackets...)

Huge thanks to @singpolyma for helping me fix this issue.