| 
<?phpdeclare(strict_types=1);
 namespace ParagonIE\Halite;
 
 use ParagonIE\Halite\Alerts as CryptoException;
 use ParagonIE\Halite\Contract;
 
 /**
 * Symmetric Key Crypography uses one secret key, while Asymmetric Key Cryptography
 * uses a secret key and public key pair
 */
 abstract class Key implements Contract\KeyInterface
 {
 // FLAGS:
 const SECRET_KEY       =   1;
 const PUBLIC_KEY       =   2;
 const ENCRYPTION       =   4;
 const SIGNATURE        =   8;
 const ASYMMETRIC       =  16;
 
 // ALIAS:
 const AUTHENTICATION   =   8;
 
 // SHORTCUTS:
 const CRYPTO_SECRETBOX =  5;
 const CRYPTO_AUTH      =  9;
 const CRYPTO_BOX       = 20;
 const CRYPTO_SIGN      = 24;
 
 private $is_public_key = false;
 private $is_signing_key = false;
 private $is_asymmetric_key = false;
 private $key_material = '';
 
 /**
 * Don't let this ever succeed
 *
 * @throws CryptoException\CannotCloneKey
 */
 public function __clone()
 {
 throw new CryptoException\CannotCloneKey;
 }
 
 /**
 * @param string $keyMaterial - The actual key data
 * @param bool $public - Is this a public key?
 * @param bool $signing - Is this a signing key?
 * @param bool $asymmetric - Is this being used in asymmetric cryptography?
 */
 public function __construct(
 string $keyMaterial = '',
 ...$args
 ) {
 // Workaround: Inherited classes have simpler constructors:
 $public = \count($args) >= 1 ? $args[0] : false;
 $signing = \count($args) >= 2 ? $args[1] : false;
 $asymmetric = \count($args) >= 3 ? $args[2] : false;
 
 // String concatenation used to undo a PHP 7 optimization that causes
 // the wrong memory to get overwritten by \Sodium\memzero:
 $this->key_material .= $keyMaterial;
 $this->is_public_key = $public;
 $this->is_signing_key = $signing;
 if ($public && !$asymmetric) {
 // This is implied.
 $asymmetric = true;
 }
 $this->is_asymmetric_key = $asymmetric;
 }
 
 /**
 * Hide this from var_dump(), etc.
 *
 * @return array
 */
 public function __debugInfo()
 {
 // We exclude $this->key_material
 return [
 'is_asymmetric_key' => $this->is_asymmetric_key,
 'is_public_key' => $this->is_public_key,
 'is_signing_key' => $this->is_signing_key
 ];
 }
 
 /**
 * Make sure you wipe the key from memory on destruction
 */
 public function __destruct()
 {
 if (!$this->is_public_key) {
 \Sodium\memzero($this->key_material);
 $this->key_material = null;
 }
 }
 
 /**
 * Don't allow this object to ever be serialized
 */
 public function __sleep()
 {
 throw new CryptoException\CannotSerializeKey;
 }
 
 /**
 * Get public keys
 *
 * @return string
 */
 public function __toString()
 {
 if ($this->is_public_key) {
 return $this->key_material;
 }
 return '';
 }
 /**
 * Get the actual key material
 *
 * @return string
 */
 public function get()
 {
 return ''.$this->key_material;
 }
 
 /**
 * Is this a part of a key pair?
 *
 * @return bool
 */
 public function isAsymmetricKey()
 {
 return $this->is_asymmetric_key;
 }
 
 /**
 * Is this a signing key?
 *
 * @return bool
 */
 public function isEncryptionKey()
 {
 return !$this->is_signing_key;
 }
 
 /**
 * Is this a public key?
 *
 * @return bool
 */
 public function isPublicKey()
 {
 return $this->is_public_key;
 }
 
 /**
 * Is this a secret key?
 *
 * @return bool
 */
 public function isSecretKey()
 {
 return !$this->is_public_key;
 }
 
 /**
 * Is this a signing key?
 *
 * @return bool
 */
 public function isSigningKey()
 {
 return $this->is_signing_key;
 }
 
 /**
 * Does this integer contain this flag?
 *
 * @param int $int
 * @param int $flag
 * @return bool
 */
 public static function hasFlag(int $int, int $flag): bool
 {
 return ($int & $flag) !== 0;
 }
 
 /**
 * Opposite of hasFlag()
 *
 * @param int $int
 * @param int $flag
 * @return bool
 */
 public static function doesNotHaveFlag(int $int, int $flag): bool
 {
 return ($int & $flag) === 0;
 }
 }
 
 |