0

I found this answer and it helped me half the way: How do you use the PHP OpenPGP library?

First of all, due to dependencies I really failed to set it up properly by just downloading it. But as I have Symfony running and installed with composer, I finally got pgp installed (but not working) in Symfony by running composer require singpolyma/openpgp-php which installed it and the dependencies into the vendor folder.

I can use pgp in a standalone php-file if I requires as follows, but this does not work in the controller (even if I add the requires it does not fail more or less than without)

require("../vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php");
require("../vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php");
require("../vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php");
require("../vendor/singpolyma/openpgp-php/lib/openpgp_crypt_rsa.php");

In the AbstractController of Symfony it does not work that way. I crushed my Brain which "use" command I should use and I just have no more ideas.

from composer.json the name is

"name": "singpolyma/openpgp-php",

but a minus is not a valid name in a namespace.

I usually get the error

Attempted to load class "OpenPGP_SecretKeyPacket" from namespace "App\Controller". Did you forget a "use" statement for another namespace?

<?php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;

class PageApiController extends AbstractController
{
    /**
    @Route("/ApiTest", methods={"GET"})
    */
    public function ApiTest(EntityManagerInterface $entityManager)
    {
        $rsa = new \phpseclib\Crypt\RSA(); // HERE comes the ERROR
        $k = $rsa->createKey(512);
        $rsa->loadKey($k['privatekey']);

        $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()
        ));

        $uid = new OpenPGP_UserIDPacket('Test <test@example.com>');

        $wkey = new OpenPGP_Crypt_RSA($nkey);
        $m = $wkey->sign_key_userid(array($nkey, $uid));

        // Serialize private key
        $Data = $m->to_bytes();

        return $this->json(['Test' => $Data]);
    }
}

I must admit I am not used to namespaces in php and I know I do not really understand what is going on in symfony yet. I am very grateful for any hint to namespaces in Symfony.

Stephan Vierkant
  • 9,674
  • 8
  • 61
  • 97
René W.
  • 150
  • 1
  • 9
  • I'm guessing that the library does not use namespaces? You could confirm be taking a look at the source code. The fix could be as simple as using a leading backslash to specify the global namespace: new \OpenPGP_UserIDPacket If nothing else, at least you will get a different error message. – Cerad Jan 11 '21 at 21:35
  • it doesn't use namespaces... – René W. Jan 12 '21 at 21:13

1 Answers1

2

There are actually two libraries involved here. The phpseclib is namespaced so things like the RSA class can be used with a simple new RSA(). However, the OpenPGP stuff is not namespaced and does not seem to support classic autoloading. Personally I would look for another more up to date library however you can use composer.json files capability to load the necessary include files. At which point you can create the secret key packet class cleanly. Which is as far as I went with testing.

# create a new project
symfony new --full pgp
cd pgp
composer require singpolyma/openpgp-php

# Edit composer.json
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "files": [
            "vendor/singpolyma/openpgp-php/lib/openpgp.php",
            "vendor/singpolyma/openpgp-php/lib/openpgp_crypt_rsa.php"
        ]
    },
# refresh autoload.php
composer dump-autoload

# Add a test command
namespace App\Command;

use phpseclib\Crypt\RSA;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class PgpCommand extends Command
{
    protected static $defaultName = 'pgp:test';

    protected function execute(InputInterface $input, OutputInterface $output)
    {

        $rsa = new RSA();
        $k = $rsa->createKey(512);
        $rsa->loadKey($k['privatekey']);

        // Note the leading back slash
        $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()
        ));
        return Command::SUCCESS;
    }
}

# and test
bin/console pgp:test
Cerad
  • 48,157
  • 8
  • 90
  • 92
  • you are genious.... i edited the autoload-part, run the composer command and added \ to all uses of Non-Namespace Classes like \OpenPGP_Crypt_RSA i might look what commands in symfony exactly are - it might be better to add the functionalty by a own command class instead of directly in the controller, right? ($data was scrambled binary data so it run into an error there challenge taken. – René W. Jan 12 '21 at 21:22
  • Sometimes it is easier to test code by running a console command instead of refreshing a browser. If I was actually going to use PGP for something I would create some sort of PGP service class and wrap up all the low level functionality. Such a service could then be injected and used from a controller or a command or by anything else that needs it. – Cerad Jan 12 '21 at 21:50