/** * 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); }
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."); }
/** * @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()); }
/** * 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; }
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);
/** * @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)); }
<?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');
/** * 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']]; }
/** * 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); }
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); }
/** * Perform decryption * * @param $text * @return mixed */ public static function decrypt($text) { $key = KeyFactory::loadEncryptionKey(config('laracrypt.path')); return Crypto::decrypt($text, $key); }
/** * 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; }
/** * SecureJwt constructor. * * @param string $keyFile */ public function __construct($keyFile = '') { $this->key = KeyFactory::loadEncryptionKey($keyFile); }
<?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); }