public function testMultiPartyKeyGeneration() { $adapter = EccFactory::getAdapter(); $generator = EccFactory::getNistCurves($adapter)->generator256(); $messages = new MessageFactory($adapter); $alice = $generator->createPrivateKey(); $bob = $generator->createPrivateKey(); $carol = $generator->createPrivateKey(); // Alice computes g^a and sends it to Bob. $bobX = $alice->createExchange($messages, $bob->getPublicKey()); // Bob computes (g^a)^b = g^{ab} and sends it to Carol. $carolX = $carol->createExchange($messages, $bobX->createMultiPartyKey()); // Carol computes (g^{ab})^c = g^{abc} and uses it as her secret. $carolSharedKey = $carolX->calculateSharedKey(); // Bob computes g^b and sends it to Carol. $carolX = $carol->createExchange($messages, $bob->getPublicKey()); // Carol computes (g^b)^c = g^{bc} and sends it to Alice. $aliceX = $alice->createExchange($messages, $carolX->createMultiPartyKey()); // Alice computes (g^{bc})^a = g^{bca} = g^{abc} and uses it as her secret. $aliceSharedKey = $aliceX->calculateSharedKey(); // Carol computes g^c and sends it to Alice. $aliceX = $carol->createExchange($messages, $alice->getPublicKey()); // Alice computes (g^c)^a = g^{ca} and sends it to Bob. $bobX = $bob->createExchange($messages, $aliceX->createMultiPartyKey()); // Bob computes (g^{ca})^b = g^{cab} = g^{abc} and uses it as his secret. $bobSharedKey = $bobX->calculateSharedKey(); $this->assertTrue($bobSharedKey == $aliceSharedKey); $this->assertTrue($aliceSharedKey == $carolSharedKey); $this->assertTrue($carolSharedKey == $bobSharedKey); }
/** * @return Binary */ public function generateKey() { $generator = EccFactory::getNistCurves()->generator256(); $key = $generator->createPrivateKey(); $serializer = new DerPrivateKeySerializer(); $serialized = $serializer->serialize($key); return new Binary($serialized); }
/** * * @dataProvider getAdapters */ public function testSecp256r1EquivalenceToNistP192(MathAdapterInterface $adapter) { $secpFactory = EccFactory::getSecgCurves($adapter); $nistFactory = EccFactory::getNistCurves($adapter); $signer = new Signer($adapter); $secret = $adapter->hexDec('DC51D3866A15BACDE33D96F992FCA99DA7E6EF0934E7097559C27F1614C88A7F'); $secpKey = $secpFactory->generator256r1()->getPrivateKeyFrom($secret); $nistKey = $nistFactory->generator256()->getPrivateKeyFrom($secret); $randomK = RandomGeneratorFactory::getRandomGenerator()->generate($secpKey->getPoint()->getOrder()); $message = RandomGeneratorFactory::getRandomGenerator()->generate($secpKey->getPoint()->getOrder()); $sigSecp = $signer->sign($secpKey, $message, $randomK); $sigNist = $signer->sign($nistKey, $message, $randomK); $this->assertEquals($sigNist->getR(), $sigSecp->getR()); $this->assertEquals($sigNist->getS(), $sigSecp->getS()); }
public static function generate_vapid_options() { if (USE_VAPID) { if (!get_option('webpush_vapid_key')) { $generator = EccFactory::getNistCurves()->generator256(); $privKeySerializer = new PemPrivateKeySerializer(new DerPrivateKeySerializer()); update_option('webpush_vapid_key', $privKeySerializer->serialize($generator->createPrivateKey())); } if (!get_option('webpush_vapid_subject')) { update_option('webpush_vapid_subject', 'mailto:' . get_option('admin_email')); } if (!get_option('webpush_vapid_audience')) { $parsedURL = parse_url(home_url('/', 'https')); update_option('webpush_vapid_audience', $parsedURL['scheme'] . '://' . $parsedURL['host'] . (isset($parsedURL['port']) ? ':' . $parsedURL['port'] : '')); } } }
/** * @param string $payload With padding * @param string $userPublicKey Base 64 encoded (MIME or URL-safe) * @param string $userAuthToken Base 64 encoded (MIME or URL-safe) * @param bool $nativeEncryption Use OpenSSL (>PHP7.1) * * @return array */ public static function encrypt($payload, $userPublicKey, $userAuthToken, $nativeEncryption) { $userPublicKey = Base64Url::decode($userPublicKey); $userAuthToken = Base64Url::decode($userAuthToken); // initialize utilities $math = EccFactory::getAdapter(); $pointSerializer = new UncompressedPointSerializer($math); $generator = EccFactory::getNistCurves()->generator256(); $curve = EccFactory::getNistCurves()->curve256(); // get local key pair $localPrivateKeyObject = $generator->createPrivateKey(); $localPublicKeyObject = $localPrivateKeyObject->getPublicKey(); $localPublicKey = hex2bin($pointSerializer->serialize($localPublicKeyObject->getPoint())); // get user public key object $pointUserPublicKey = $pointSerializer->unserialize($curve, bin2hex($userPublicKey)); $userPublicKeyObject = $generator->getPublicKeyFrom($pointUserPublicKey->getX(), $pointUserPublicKey->getY(), $generator->getOrder()); // get shared secret from user public key and local private key $sharedSecret = hex2bin($math->decHex(gmp_strval($userPublicKeyObject->getPoint()->mul($localPrivateKeyObject->getSecret())->getX()))); // generate salt $salt = openssl_random_pseudo_bytes(16); // section 4.3 $ikm = !empty($userAuthToken) ? self::hkdf($userAuthToken, $sharedSecret, 'Content-Encoding: auth' . chr(0), 32) : $sharedSecret; // section 4.2 $context = self::createContext($userPublicKey, $localPublicKey); // derive the Content Encryption Key $contentEncryptionKeyInfo = self::createInfo('aesgcm', $context); $contentEncryptionKey = self::hkdf($salt, $ikm, $contentEncryptionKeyInfo, 16); // section 3.3, derive the nonce $nonceInfo = self::createInfo('nonce', $context); $nonce = self::hkdf($salt, $ikm, $nonceInfo, 12); // encrypt // "The additional data passed to each invocation of AEAD_AES_128_GCM is a zero-length octet sequence." if (!$nativeEncryption) { list($encryptedText, $tag) = \AESGCM\AESGCM::encrypt($contentEncryptionKey, $nonce, $payload, ''); } else { $encryptedText = openssl_encrypt($payload, 'aes-128-gcm', $contentEncryptionKey, OPENSSL_RAW_DATA, $nonce, $tag); // base 64 encoded } // return values in url safe base64 return array('localPublicKey' => Base64Url::encode($localPublicKey), 'salt' => Base64Url::encode($salt), 'cipherText' => $encryptedText . $tag); }
/** * @param JWKInterface $key * * @throws \InvalidArgumentException * * @return \Mdanter\Ecc\Primitives\GeneratorPoint */ private function getGenerator(JWKInterface $key) { $crv = $key->get('crv'); switch ($crv) { case 'P-256': return EccFactory::getNistCurves()->generator256(); case 'P-384': return EccFactory::getNistCurves()->generator384(); case 'P-521': return EccFactory::getNistCurves()->generator521(); default: throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)); } }
/** * @return \Mdanter\Ecc\Primitives\GeneratorPoint */ protected function getGenerator() { return EccFactory::getNistCurves()->generator521(); }
<?php // ------------------------------------------ // Step 0 - Create the application keys // ------------------------------------------ // include composer autoloader require '../vendor/autoload.php'; use Mdanter\Ecc\EccFactory; $generator = EccFactory::getNistCurves()->generator256(); $private = $generator->createPrivateKey(); $public = $private->getPublicKey(); $adaptor = EccFactory::getAdapter(); $public_point = $public->getPoint(); // hexlify the integers $private_hex = $adaptor->decHex($private->getSecret()); $public_hex = $adaptor->decHex($public_point->getX()) . $adaptor->decHex($public_point->getY()); // keys! $keys = ['public' => $public_hex, 'private' => $private_hex]; var_dump($keys); // Once we have EC Keys, we continue on step1.php file and fill in the data in config.php
/** * This method creates VAPID keys in case you would not be able to have a Linux bash. * DO NOT create keys at each initialization! Save those keys and reuse them. * * @return array */ public static function createVapidKeys() { $privateKeyObject = EccFactory::getNistCurves()->generator256()->createPrivateKey(); return self::getUncompressedKeys($privateKeyObject); }
/** * @param JWKInterface $key * * @throws \Exception * * @return \Mdanter\Ecc\Primitives\GeneratorPoint */ private function getGenerator(JWKInterface $key) { $crv = $key->getValue('crv'); switch ($crv) { case 'P-256': return EccFactory::getNistCurves()->generator256(); case 'P-384': return EccFactory::getNistCurves()->generator384(); case 'P-521': return EccFactory::getNistCurves()->generator521(); default: throw new \Exception("Curve {$crv} is not supported"); } }
/** * @dataProvider getAdaptersWithRand * @testdox Test Diffie-Hellman key exchange and message encryption/decryption */ public function testDiffieHellman(MathAdapterInterface $math, RandomNumberGeneratorInterface $rng) { $generator = EccFactory::getNistCurves($math)->generator192($rng); $messages = new MessageFactory($math); $alicePrivKey = $generator->createPrivateKey(); $bobPrivKey = $generator->createPrivateKey(); $alice = $alicePrivKey->createExchange($messages, $bobPrivKey->getPublicKey()); $bob = $bobPrivKey->createExchange($messages, $alicePrivKey->getPublicKey()); $this->assertEquals($alice->calculateSharedKey(), $bob->calculateSharedKey()); // Test encrypt/decrypt by both parties $unencrypted = $messages->plaintext('This is some text', 'sha256'); $encrypted = $alice->encrypt($unencrypted); $this->assertEquals($unencrypted, $bob->decrypt($encrypted)); $encrypted = $bob->encrypt($unencrypted); $this->assertEquals($unencrypted, $alice->decrypt($encrypted)); }
/** * after_request * Hook for PHP Requests * * @param \Requests_Response $return * * @throws */ public function after_request(\Requests_Response &$return) { $headers = $return->headers; $url = $return->url; $data = $return->body; $signature = $headers['x-signature']; if ($this->debug) { echo "\n\nResponse Data:\n"; var_dump($return); } // Check if signature header exists, if not the request failed if (!isset($headers['x-signature']) or $headers['x-signature'] == '') { throw new \Exception('Request Failed'); } // build up the data to be signed $request_data = $this->service_name . "\n" . $headers['date'] . "\n" . $url . "\n"; if (!empty($data)) { $request_data .= trim($data); } // try and validate the signature // ------------------------------------ $generator = EccFactory::getNistCurves()->generator256(); $order_len = strlen($this->math_adapter->decHex($generator->getOrder())); $x = $this->math_adapter->hexDec(substr($this->public_key, 0, $order_len)); $y = $this->math_adapter->hexDec(substr($this->public_key, $order_len)); $point = new Point($this->math_adapter, EccFactory::getNistCurves()->curve256(), $x, $y, $generator->getOrder()); $public_key = new PublicKey($this->math_adapter, $generator, $point); $r = $this->math_adapter->hexDec(substr($signature, 0, $order_len)); $s = $this->math_adapter->hexDec(substr($signature, $order_len)); $signature = new Signature($r, $s); $signer = EccFactory::getSigner(); $check_hash = $this->math_adapter->hexDec(hash("sha256", $request_data)); $result = $signer->verify($public_key, $signature, $check_hash); // ------------------------------------ //$result = \ECDSA::validate($request_data, $signature, $this->public_key); // if signature validation failed, throw exception if ($result !== TRUE) { throw new \Exception('Signature Does Not Validate!'); } }