/** * {@inheritdoc} */ public function decryptContent($data, $cek, $iv, $aad, $encoded_protected_header, $tag) { $calculated_aad = $encoded_protected_header; if (null !== $aad) { $calculated_aad .= '.' . $aad; } if (version_compare(PHP_VERSION, '7.1.0') >= 0) { return openssl_decrypt($data, $this->getMode($cek), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad); } elseif (class_exists('\\Crypto\\Cipher')) { $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize()); $cipher->setTag($tag); $cipher->setAAD($calculated_aad); $plaintext = $cipher->decrypt($data, $cek, $iv); return $plaintext; } return GCM::decrypt($cek, $iv, $data, $calculated_aad, $tag); }
/** * {@inheritdoc} */ public function unwrapKey(JWKInterface $key, $encrypted_cek, array $header) { $this->checkKey($key); $this->checkAdditionalParameters($header); $kek = Base64Url::decode($key->get('k')); $tag = Base64Url::decode($header['tag']); $iv = Base64Url::decode($header['iv']); if (version_compare(PHP_VERSION, '7.1.0') >= 0) { return openssl_decrypt($encrypted_cek, $this->getMode($kek), $kek, OPENSSL_RAW_DATA, $iv, $tag, null); } elseif (class_exists('\\Crypto\\Cipher')) { $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize()); $cipher->setTag($tag); $cipher->setAAD(null); $cek = $cipher->decrypt($encrypted_cek, $kek, $iv); return $cek; } return AESGCM::decrypt($kek, $iv, $encrypted_cek, null, $tag); }
/** * @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); }
public static function decrypt($encData, $password, $IV, $AAD) { /* * https://tools.ietf.org/html/rfc5116#section-5.1 * * An authentication tag with a length of 16 octets (128 * bits) is used. The AEAD_AES_128_GCM ciphertext is formed by * appending the authentication tag provided as an output to the GCM * encryption operation to the ciphertext that is output by that * operation. * * ciphertext is exactly 16 octets longer than its * corresponding plaintext. */ if (strlen($encData) < self::TAG_LEN) { return false; } // Get the tag appended to cipher text $tag = substr($encData, strlen($encData) - self::TAG_LEN, self::TAG_LEN); // Resize the cipher text $encData = substr($encData, 0, strlen($encData) - self::TAG_LEN); if (self::useOpenSSL()) { $method = self::getMethod($password); $data = openssl_decrypt($encData, $method, $password, OPENSSL_RAW_DATA, $IV, $tag, $AAD); } else { if (self::useSO()) { try { $cipher = \Crypto\Cipher::aes(\Crypto\Cipher::MODE_GCM, self::bitLen($password)); $cipher->setTag($tag); $cipher->setAAD($AAD); $data = $cipher->decrypt($encData, $password, $IV); } catch (\Exception $e) { return false; } } else { try { $data = AESGCM::decrypt($password, $IV, $encData, $AAD, $tag); } catch (\Exception $e) { //echo $e->getMessage(); return false; } } } return $data; }