Example #1
0
 /**
  * Hash then encrypt a password
  *
  * @param HiddenString $password    The user's password
  * @param EncryptionKey $secretKey  The master key for all passwords
  * @param string $level             The security level for this password
  * @return string                   An encrypted hash to store
  */
 public static function hash(HiddenString $password, EncryptionKey $secretKey, string $level = KeyFactory::INTERACTIVE) : string
 {
     $kdfLimits = KeyFactory::getSecurityLevels($level);
     // First, let's calculate the hash
     $hashed = \Sodium\crypto_pwhash_str($password->getString(), $kdfLimits[0], $kdfLimits[1]);
     // Now let's encrypt the result
     return Crypto::encrypt(new HiddenString($hashed), $secretKey);
 }
Example #2
0
 public function testSign()
 {
     $keypair = KeyFactory::generateSignatureKeyPair();
     $secretkey = $keypair->getSecretKey();
     $publickey = $keypair->getPublicKey();
     $signature = File::sign(__DIR__ . '/tmp/paragon_avatar.png', $secretkey);
     $this->assertTrue(!empty($signature));
     $this->assertTrue(File::verify(__DIR__ . '/tmp/paragon_avatar.png', $publickey, $signature));
 }
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function handle()
 {
     $enc_key = KeyFactory::generateEncryptionKey();
     try {
         KeyFactory::save($enc_key, config('laracrypt.path'));
     } catch (\Throwable $t) {
         $this->error($t);
     }
     return $this->info("Your LaraCrypt encryption key has been generated.");
 }
Example #4
0
 /**
  * @covers \ParagonIE\Halite\Asymmetric\EncryptionSecretKey::derivePublicKey()
  * @covers \ParagonIE\Halite\Asymmetric\SignatureSecretKey::derivePublicKey()
  */
 public function testPublicDerivation()
 {
     $enc_kp = KeyFactory::generateEncryptionKeyPair();
     $enc_secret = $enc_kp->getSecretKey();
     $enc_public = $enc_kp->getPublicKey();
     $this->assertEquals($enc_secret->derivePublicKey()->getRawKeyMaterial(), $enc_public->getRawKeyMaterial());
     $sign_kp = KeyFactory::generateSignatureKeyPair();
     $sign_secret = $sign_kp->getSecretKey();
     $sign_public = $sign_kp->getPublicKey();
     $this->assertEquals($sign_secret->derivePublicKey()->getRawKeyMaterial(), $sign_public->getRawKeyMaterial());
 }
Example #5
0
 /**
  * Seal a (file handle)
  *
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionPublicKey $publickey
  * @return int
  */
 protected static function sealData(ReadOnlyFile $input, MutableFile $output, EncryptionPublicKey $publickey) : int
 {
     // Generate a new keypair for this encryption
     $eph_kp = KeyFactory::generateEncryptionKeyPair();
     $eph_secret = $eph_kp->getSecretKey();
     $eph_public = $eph_kp->getPublicKey();
     unset($eph_kp);
     // Calculate the shared secret key
     $key = AsymmetricCrypto::getSharedSecret($eph_secret, $publickey, true);
     // Destroy the secre tkey after we have the shared secret
     unset($eph_secret);
     $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'seal');
     // Generate a nonce as per crypto_box_seal
     $nonce = \Sodium\crypto_generichash($eph_public->getRawKeyMaterial() . $publickey->getRawKeyMaterial(), '', \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Generate a random HKDF salt
     $hkdfsalt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     // Split the keys
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     $output->writeBytes(Halite::HALITE_VERSION_FILE, Halite::VERSION_TAG_LEN);
     $output->writeBytes($eph_public->getRawKeyMaterial(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
     $output->writeBytes($hkdfsalt, $config->HKDF_SALT_LEN);
     if ($config->USE_BLAKE2B) {
         $mac = \Sodium\crypto_generichash_init($authKey);
         \Sodium\crypto_generichash_update($mac, Halite::HALITE_VERSION_FILE);
         \Sodium\crypto_generichash_update($mac, $eph_public->getRawKeyMaterial());
         \Sodium\crypto_generichash_update($mac, $hkdfsalt);
     } else {
         $mac = \hash_init('sha256', HASH_HMAC, $authKey);
         // We no longer need $authKey after we set up the hash context
         unset($authKey);
         \hash_update($mac, Halite::HALITE_VERSION_FILE);
         \hash_update($mac, $eph_public->getRawKeyMaterial());
         \hash_update($mac, $hkdfsalt);
     }
     \Sodium\memzero($authKey);
     unset($eph_public);
     return self::streamEncrypt($input, $output, new EncryptionKey($encKey), $nonce, $mac, $config);
 }
 public function it_can_create_new_auth_records($authenticationMapper, User $user5, AuthenticationRecordInterface $newAuth)
 {
     $newAuth->getSessionKey()->willReturn(KeyFactory::generateEncryptionKey()->getRawKeyMaterial());
     $newAuth->getUsername()->willReturn('email');
     $newAuth->getUserId()->willReturn(5);
     $user5->getId()->willReturn(5);
     $authenticationMapper->save(Argument::type(AuthenticationRecordInterface::class))->shouldBeCalled();
     $authenticationMapper->create(Argument::type('integer'), Argument::type('string'), Argument::type('string'), Argument::type('string'))->willReturn($newAuth);
     $this->create($user5, 'userC', 'beestring')->shouldBeAnInstanceOf(AuthenticationRecordInterface::class);
 }
 /**
  * Resalt a user's authentication table salt
  *
  * @param AuthenticationRecordInterface $auth
  *
  * @return AuthenticationRecordInterface
  */
 private function resetAuthenticationKey(AuthenticationRecordInterface $auth) : AuthenticationRecordInterface
 {
     $key = KeyFactory::generateEncryptionKey();
     $auth->setSessionKey($key->getRawKeyMaterial());
     $this->authenticationProvider->update($auth);
     return $auth;
 }
Example #8
0
                    KeyFactory::save($keys[$index], $path);
                    break;
                case 'EncryptionSecretKey':
                    $kp = KeyFactory::generateEncryptionKeyPair();
                    $keys[$index] = $kp->getSecretKey();
                    KeyFactory::save($keys[$index], $path);
                    break;
                case 'SignatureSecretKey':
                    $kp = KeyFactory::generateSignatureKeyPair();
                    $keys[$index] = $kp->getSecretKey();
                    KeyFactory::save($keys[$index], $path);
                    break;
                case 'EncryptionKeyPair':
                    $keys[$index] = KeyFactory::generateEncryptionKeyPair();
                    KeyFactory::save($keys[$index], $path);
                    break;
                case 'SignatureKeyPair':
                    $keys[$index] = KeyFactory::generateSignatureKeyPair();
                    KeyFactory::save($keys[$index], $path);
                    break;
                default:
                    throw new \Error(\trk('errors.crypto.unknown_key_type', $keyConfig['type']));
            }
        }
    }
    // Now that we have a bunch of Keys stored in $keys, let's load them into
    // our singleton.
    $state->keyring = $keys;
};
$key_management_closure();
unset($key_management_closure);
Example #9
0
 /**
  * @covers Asymmetric::sign()
  * @covers Asymmetric::verify()
  */
 public function testSignFail()
 {
     $alice = KeyFactory::generateSignatureKeyPair();
     $message = 'test message';
     $signature = Asymmetric::sign($message, $alice->getSecretKey(), true);
     $this->assertFalse(Asymmetric::verify('wrongmessage', $alice->getPublicKey(), $signature, true));
     $_signature = $signature;
     // Let's flip one bit, randomly:
     $r = \Sodium\randombytes_uniform(\mb_strlen($signature, '8bit'));
     $_signature[$r] = \chr(\ord($_signature[$r]) ^ 1 << \Sodium\randombytes_uniform(8));
     $this->assertFalse(Asymmetric::verify($message, $alice->getPublicKey(), $_signature, true));
 }
Example #10
0
<?php

/**
 * Created by PhpStorm.
 * User: Glenn
 * Date: 2016-05-27
 * Time: 11:22 AM
 */
include "/../vendor/autoload.php";
use ParagonIE\Halite\KeyFactory;
// Generate a new random encryption key:
$encryptionKey = KeyFactory::generateEncryptionKey();
// Saving a key to a file:
KeyFactory::save($encryptionKey, './sec/encryption.key');
Example #11
0
 /**
  * Sign the new key with our current master key
  *
  * @param string $supplier
  * @param string $messageToSign
  * @return string[]
  * @throws \Exception
  */
 protected function signNewKeyWithMasterKey(string $supplier, string $messageToSign) : array
 {
     $master_keys = [];
     foreach ($this->config['suppliers'][$supplier]['signing_keys'] as $key) {
         if ($key['type'] === 'master' && !empty($key['salt'])) {
             $master_keys[] = $key;
         }
     }
     // This shouldn't happen, but just in case:
     if (empty($master_keys)) {
         throw new \Exception('You cannot generate another key unless you already have a master key with the salt loaded locally.');
     }
     // Select the correct master key.
     if (\count($master_keys) === 1) {
         $signingKey = $master_keys[0];
     } else {
         echo 'Select which master key to use:';
         do {
             foreach ($master_keys as $index => $key) {
                 $pk = Base64UrlSafe::encode(\Sodium\hex2bin($key['public_key']));
                 echo $index + 1, "\t", $pk, "\n";
             }
             $keyIndex = $this->prompt('Enter a number: ');
             if (empty($keyIndex)) {
                 // Okay, let's cancel.
                 throw new \Exception('Aborted.');
             }
             if ($keyIndex < 1 || $keyIndex > \count($master_keys)) {
                 $keyIndex = 0;
                 echo 'Please enter a number between 1 and ', \count($master_keys), ".\n";
             }
         } while ($keyIndex < 1);
         $signingKey = $master_keys[--$keyIndex];
     }
     $signature = '';
     $masterSalt = \Sodium\hex2bin($signingKey['salt']);
     do {
         $password = $this->silentPrompt('Enter the password for your master key: ');
         if (empty($password)) {
             // Okay, let's cancel.
             throw new \Exception('Aborted.');
         }
         $masterKeyPair = KeyFactory::deriveSignatureKeyPair($password, $masterSalt, false, KeyFactory::SENSITIVE);
         // We must verify the public key matches:
         $masterPublicKey = $masterKeyPair->getPublicKey();
         if (\hash_equals($masterPublicKey->getRawKeyMaterial(), \Sodium\hex2bin($signingKey['public_key']))) {
             $masterSecretKey = $masterKeyPair->getSecretKey();
             // Setting $signature exits the loop
             $signature = Asymmetric::sign($messageToSign, $masterSecretKey);
         } else {
             echo 'Incorrect master key passphrase!', "\n";
         }
     } while (!$signature);
     // We are returning two strings:
     return [$signature, $signingKey['public_key']];
 }
Example #12
0
 /**
  * Seal a (file handle)
  * 
  * @param ReadOnlyFile $input
  * @param MutableFile $output
  * @param EncryptionPublicKey $publickey
  */
 public static function sealStream(ReadOnlyFile $input, MutableFile $output, KeyInterface $publickey)
 {
     if (!$publickey instanceof EncryptionPublicKey) {
         throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 3: Expected an instance of EncryptionPublicKey');
     }
     // Generate a new keypair for this encryption
     $eph_kp = KeyFactory::generateEncryptionKeyPair();
     $eph_secret = $eph_kp->getSecretKey();
     $eph_public = $eph_kp->getPublicKey();
     unset($eph_kp);
     // Calculate the shared secret key
     $key = AsymmetricCrypto::getSharedSecret($eph_secret, $publickey, true);
     // Destroy the secre tkey after we have the shared secret
     unset($eph_secret);
     $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'seal');
     // Generate a nonce as per crypto_box_seal
     $nonce = \Sodium\crypto_generichash($eph_public->get() . $publickey->get(), null, \Sodium\CRYPTO_STREAM_NONCEBYTES);
     // Generate a random HKDF salt
     $hkdfsalt = \Sodium\randombytes_buf($config->HKDF_SALT_LEN);
     // Split the keys
     list($encKey, $authKey) = self::splitKeys($key, $hkdfsalt, $config);
     // We no longer need the original key after we split it
     unset($key);
     $mac = \hash_init('sha256', HASH_HMAC, $authKey);
     // We no longer need to retain this after we've set up the hash context
     unset($authKey);
     $output->writeBytes(Halite::HALITE_VERSION_FILE, Halite::VERSION_TAG_LEN);
     $output->writeBytes($eph_public->get(), \Sodium\CRYPTO_BOX_PUBLICKEYBYTES);
     $output->writeBytes($hkdfsalt, $config->HKDF_SALT_LEN);
     \hash_update($mac, Halite::HALITE_VERSION_FILE);
     \hash_update($mac, $eph_public->get());
     \hash_update($mac, $hkdfsalt);
     unset($eph_public);
     return self::streamEncrypt($input, $output, new EncryptionKey($encKey), $nonce, $mac, $config);
 }
Example #13
0
 public function testLegacySignKeyStorage()
 {
     $sign_keypair = KeyFactory::deriveSignatureKeyPair('apple', "\t\n\v\f\r" . "", true);
     $sign_secret = $sign_keypair->getSecretKey();
     $sign_public = $sign_keypair->getPublicKey();
     $file_secret = \tempnam(__DIR__ . '/tmp', 'key');
     $file_public = \tempnam(__DIR__ . '/tmp', 'key');
     $this->assertTrue(KeyFactory::save($sign_secret, $file_secret) !== false);
     $this->assertTrue(KeyFactory::save($sign_public, $file_public) !== false);
     $load_public = KeyFactory::loadSignaturePublicKey($file_public);
     $this->assertTrue($load_public instanceof SignaturePublicKey);
     $this->assertTrue(\hash_equals($sign_public->getRawKeyMaterial(), $load_public->getRawKeyMaterial()));
     \unlink($file_secret);
     \unlink($file_public);
 }
Example #14
0
 /**
  * Perform decryption
  *
  * @param $text
  * @return mixed
  */
 public static function decrypt($text)
 {
     $key = KeyFactory::loadEncryptionKey(config('laracrypt.path'));
     return Crypto::decrypt($text, $key);
 }
Example #15
0
 /**
  * We are revoking a key.
  *
  * @param array $args
  * @throws \Exception
  * @return mixed
  */
 protected function handleKeyRevoke(array $args)
 {
     if (count($this->config['suppliers']) === 1) {
         $supplier = \count($args) > 0 ? $args[0] : \array_keys($this->config['suppliers'])[0];
     } else {
         $supplier = \count($args) > 0 ? $args[0] : $this->prompt("Please enter the name of the supplier: ");
     }
     if (!\array_key_exists($supplier, $this->config['suppliers'])) {
         echo 'Please authenticate before attempting to revoke keys.', "\n";
         echo 'Run this command: ', $this->c['yellow'], 'barge login', $this->c[''], "\n";
         exit(255);
     }
     $masterKeys = [];
     $keyList = [];
     foreach ($this->config['suppliers'][$supplier]['signing_keys'] as $key) {
         if ($key['type'] === 'master') {
             if (!empty($key['salt'])) {
                 $masterKeys[] = $key;
             } else {
                 $keyList[] = $key;
             }
         } else {
             $keyList[] = $key;
         }
     }
     if (empty($masterKeys)) {
         echo 'No usable master keys found. Make sure the salt is loaded locally.', "\n";
         exit(255);
     }
     if (empty($keyList)) {
         // If and only if you have nothing more to revoke, allow revoking the master key:
         $keyList = $masterKeys;
     }
     if (\count($masterKeys) === 1) {
         $masterKey = $masterKeys[0];
     } else {
         $masterKey = $this->selectKeyFromList('Select your master key: ', $masterKeys);
         // Add other master keys to the list
         foreach ($masterKeys as $key) {
             if ($key['public_key'] !== $masterKey['public_key']) {
                 $keyList[] = $key;
             }
         }
     }
     if (\count($keyList) === 1) {
         $revokingKey = $keyList[0];
     } else {
         $revokingKey = $this->selectKeyFromList('Select which key to revoke: ', $keyList);
     }
     $confirm_revoke = null;
     while ($confirm_revoke === null) {
         $choice = $this->prompt('Are you sure you wish to revoke this key? (y/N): ');
         switch ($choice) {
             case 'YES':
             case 'yes':
             case 'Y':
             case 'y':
                 $confirm_revoke = true;
                 break;
             case 'N':
             case 'NO':
             case 'n':
             case 'no':
             case '':
                 // Just pressing enter means "don't store it"!
                 $confirm_revoke = false;
                 break;
             default:
                 echo "\n", $this->c['yellow'], 'Invalid response. Please enter yes or no.', $this->c[''], "\n";
         }
     }
     // This is what get signed by our master key:
     $message = ['action' => 'REVOKE', 'date_revoked' => \date('Y-m-d\\TH:i:s'), 'public_key' => $revokingKey['public_key'], 'supplier' => $supplier];
     $messageToSign = \json_encode($message);
     $iter = false;
     do {
         if ($iter) {
             echo 'Incorrect password.', "\n";
         }
         $password = $this->silentPrompt('Enter the password for your master key: ');
         if (empty($password)) {
             // Okay, let's cancel.
             throw new \Exception('Aborted.');
         }
         $masterKeyPair = KeyFactory::deriveSignatureKeyPair($password, \Sodium\hex2bin($masterKey['salt']), false, KeyFactory::SENSITIVE);
         \Sodium\memzero($password);
         $masterPublicKeyString = \Sodium\bin2hex($masterKeyPair->getPublicKey()->getRawKeyMaterial());
         $iter = true;
     } while (!\hash_equals($masterKey['public_key'], $masterPublicKeyString));
     $signature = Asymmetric::sign($messageToSign, $masterKeyPair->getSecretKey());
     $response = $this->sendRevocation($supplier, $message, $signature, $masterPublicKeyString);
     if ($response['status'] === 'OK') {
         foreach ($this->config['suppliers'][$supplier]['signing_keys'] as $i => $key) {
             if ($key['public_key'] === $message['public_key']) {
                 unset($this->config['suppliers'][$supplier]['signing_keys'][$i]);
             }
         }
     }
     return $response;
 }
Example #16
0
 /**
  * SecureJwt constructor.
  *
  * @param string $keyFile
  */
 public function __construct($keyFile = '')
 {
     $this->key = KeyFactory::loadEncryptionKey($keyFile);
 }
Example #17
0
<?php

declare (strict_types=1);
use ParagonIE\Halite\HiddenString;
use ParagonIE\Halite\Password;
use ParagonIE\Halite\KeyFactory;
// First, manage the keys
if (!\file_exists('01-secret-key.txt')) {
    $secretKey = KeyFactory::generateEncryptionKey();
    KeyFactory::save($secretKey, '01-secret-key.txt');
} else {
    $secretKey = KeyFactory::loadEncryptionKey('01-secret-key.txt');
}
$password = new HiddenString('correct horse battery staple');
$hash = Password::hash($password, $secretKey);
if (Password::verify($password, $hash, $secretKey)) {
    echo 'Access granted', "\n";
} else {
    echo 'Access DENIED!', "\n";
    exit(255);
}