<?php 
declare(strict_types=1); 
namespace ParagonIE\Halite; 
 
use ParagonIE\Halite\{ 
    Alerts as CryptoException, 
    Asymmetric\EncryptionPublicKey, 
    Asymmetric\EncryptionSecretKey 
}; 
 
/** 
 * Describes a pair of secret and public keys 
 */ 
final class EncryptionKeyPair extends KeyPair 
{ 
    /** 
     * 
     * Pass it a secret key, it will automatically generate a public key 
     * 
     * @param ...Key $keys 
     */ 
    public function __construct(Key ...$keys) 
    { 
        switch (\count($keys)) { 
            /** 
             * If we received two keys, it must be an asymmetric secret key and 
             * an asymmetric public key, in either order. 
             */ 
            case 2: 
                if (!$keys[0]->isAsymmetricKey() || !$keys[1]->isAsymmetricKey()) { 
                    throw new CryptoException\InvalidKey( 
                        'Only keys intended for asymmetric cryptography can be used in a KeyPair object' 
                    ); 
                } 
                if ($keys[0]->isPublicKey()) { 
                    if ($keys[1]->isPublicKey()) { 
                        throw new CryptoException\InvalidKey( 
                            'Both keys cannot be public keys' 
                        ); 
                    } 
                    $this->setupKeyPair( 
                        $keys[1] instanceof EncryptionSecretKey 
                            ? $keys[1] 
                            : new EncryptionSecretKey($keys[1]->get()) 
                    ); 
                } elseif ($keys[1]->isPublicKey()) { 
                    $this->setupKeyPair( 
                        $keys[0] instanceof EncryptionSecretKey 
                            ? $keys[0] 
                            : new EncryptionSecretKey($keys[0]->get()) 
                    ); 
                } else { 
                    throw new CryptoException\InvalidKey( 
                        'Both keys cannot be secret keys' 
                    ); 
                } 
                break; 
            /** 
             * If we only received one key, it must be an asymmetric secret key! 
             */ 
            case 1: 
                if (!$keys[0]->isAsymmetricKey()) { 
                    throw new CryptoException\InvalidKey( 
                        'Only keys intended for asymmetric cryptography can be used in a KeyPair object' 
                    ); 
                } 
                if ($keys[0]->isPublicKey()) { 
                    // Ever heard of the Elliptic Curve Discrete Logarithm Problem? 
                    throw new CryptoException\InvalidKey( 
                        'We cannot generate a valid keypair given only a public key; we can given only a secret key, however.' 
                    ); 
                } 
                $this->setupKeyPair( 
                    $keys[0] instanceof EncryptionSecretKey 
                        ? $keys[0] 
                        : new EncryptionSecretKey($keys[0]->get()) 
                ); 
                break; 
            default: 
                throw new \InvalidArgumentException( 
                    'Halite\\EncryptionKeyPair expects 1 or 2 keys' 
                ); 
        } 
    } 
 
    /** 
     * Set up our key pair 
     * 
     * @param EncryptionSecretKey $secret 
     */ 
    protected function setupKeyPair(EncryptionSecretKey $secret) 
    { 
        $this->secret_key = $secret; 
        $this->public_key = $this->secret_key->derivePublicKey(); 
    } 
} 
 
 |