paragonie / paseto

Platform-Agnostic Security Tokens
https://paseto.io
Other
3.23k stars 108 forks source link

Cannot read pem created with encodePem #163

Closed frederikbosch closed 1 year ago

frederikbosch commented 1 year ago
file_put_contents(__DIR__ . '/key.pem', AsymmetricSecretKey::generate(new Version4())->encodePem());
SecretKey::importPem(file_get_contents(__DIR__ . '/key.pem'));

The above throws a RuntimeException("Invalid data.") because $asnObject->getNumberofChildren() returns 3. Am I wrong to think that the above should work?

frederikbosch commented 1 year ago

Actually, I really believe we should rewrite encoding and decoding of PEM and base64 encoded representations of the keys. The AsymmetricSecretKey and AsymmetricPublicKey contain too many if (hash_equals($protocol::header(), Version4::HEADER)) { kinds of statements. You are simply lost keeping track of all the conditions.

In my opinion the KeyInterface should be extended.

<?php
declare(strict_types=1);
namespace ParagonIE\Paseto;

/**
 * Interface KeyInterface
 * @package ParagonIE\Paseto
 */
interface KeyInterface
{
    /**
     * The intended version for this protocol. Currently only meaningful
     * in asymmetric cryptography.
     *
     * @return ProtocolInterface
     */
    public function getProtocol(): ProtocolInterface;

    /**
     * Returns the raw key as a string.
     *
     * @return string
     */
    public function raw(): string;

    /**
     * Return a base64url-encoded representation of this key.
     *
     * @return string
     */
    public function encode(): string;

    /**
     * Initialize a key from a base64url-encoded string.
     *
     * @return string
     */
    public static function fromEncodedString(string $encoded): self;

    /**
     * Return a PEM-encoded key.
     *
     * @return string
     */
    public function encodePem(): string;

    /**
     * Initialize a key from a PEM-encoded key.
     *
     * @return string
     */
    public static function importPem(string $encoded): self;

    /**
     * This hides the internal state from var_dump(), etc. if it returns
     * an empty array.
     *
     * @return array
     */
    public function __debugInfo();
}

This way encoding and decoding of specific versions are kept together.

frederikbosch commented 1 year ago

For the record, I am willing to create a PR, if agreed on the interface update.

frederikbosch commented 1 year ago

The suggested interface did not work out, as the interface is also used in symmetric keys. I choose another solution, to be found in PR #168.

frederikbosch commented 1 year ago

I tried to read the Version 4 private key with EasyECC, but EasyECC is not for Ed25519. PR #169 provides a method to import a pem generated with ->encodePem().