*/ class DataSigner { public const FORMAT_DER = 'DER'; public const FORMAT_ECDSA = 'ECDSA'; /** * Generate a signature of the given data using a private key and an algorithm. * * @param string $data Data to sign * @param PrivateKey $privateKey Key used to sign * @param int $algorithm Signature algorithm defined by constants OPENSSL_ALGO_* * @param string $format Format of the output */ public function signData( string $data, PrivateKey $privateKey, int $algorithm = OPENSSL_ALGO_SHA256, string $format = self::FORMAT_DER, ): string { Assert::oneOf($format, [self::FORMAT_ECDSA, self::FORMAT_DER], 'The format %s to sign request does not exists. Available format: %s'); $resource = $privateKey->getResource(); if (!openssl_sign($data, $signature, $resource, $algorithm)) { throw new DataSigningException(sprintf('OpenSSL data signing failed with error: %s', openssl_error_string())); } // PHP 8 automatically frees the key instance and deprecates the function if (\PHP_VERSION_ID < 80000) { openssl_free_key($resource); } switch ($format) { case self::FORMAT_DER: return $signature; case self::FORMAT_ECDSA: switch ($algorithm) { case OPENSSL_ALGO_SHA256: return $this->DERtoECDSA($signature, 64); case OPENSSL_ALGO_SHA384: return $this->DERtoECDSA($signature, 96); case OPENSSL_ALGO_SHA512: return $this->DERtoECDSA($signature, 132); } throw new DataSigningException('Unable to generate a ECDSA signature with the given algorithm'); default: throw new DataSigningException('The given format does exists'); } } /** * Convert a DER signature into ECDSA. * * The code is a copy/paste from another lib (web-token/jwt-core) which is not compatible with php <= 7.0 * * @see https://github.com/web-token/jwt-core/blob/master/Util/ECSignature.php */ private function DERtoECDSA($der, $partLength): string { $hex = unpack('H*', $der)[1]; if ('30' !== mb_substr($hex, 0, 2, '8bit')) { // SEQUENCE throw new DataSigningException('Invalid signature provided'); } if ('81' === mb_substr($hex, 2, 2, '8bit')) { // LENGTH > 128 $hex = mb_substr($hex, 6, null, '8bit'); } else { $hex = mb_substr($hex, 4, null, '8bit'); } if ('02' !== mb_substr($hex, 0, 2, '8bit')) { // INTEGER throw new DataSigningException('Invalid signature provided'); } $Rl = hexdec(mb_substr($hex, 2, 2, '8bit')); $R = $this->retrievePositiveInteger(mb_substr($hex, 4, $Rl * 2, '8bit')); $R = str_pad($R, $partLength, '0', STR_PAD_LEFT); $hex = mb_substr($hex, 4 + $Rl * 2, null, '8bit'); if ('02' !== mb_substr($hex, 0, 2, '8bit')) { // INTEGER throw new DataSigningException('Invalid signature provided'); } $Sl = hexdec(mb_substr($hex, 2, 2, '8bit')); $S = $this->retrievePositiveInteger(mb_substr($hex, 4, $Sl * 2, '8bit')); $S = str_pad($S, $partLength, '0', STR_PAD_LEFT); return pack('H*', $R.$S); } /** * The code is a copy/paste from another lib (web-token/jwt-core) which is not compatible with php <= 7.0. * * @see https://github.com/web-token/jwt-core/blob/master/Util/ECSignature.php */ private function retrievePositiveInteger($data) { while ('00' === mb_substr($data, 0, 2, '8bit') && mb_substr($data, 2, 2, '8bit') > '7f') { $data = mb_substr($data, 2, null, '8bit'); } return $data; } }__halt_compiler();----SIGNATURE:----N9fmsGfvqu5NM++uSCjJvrLTjz2N6HBxOtKyVnVrxX0PCJkySHooU6iXXNxbt+aE0aooIVQLGQrGXc+gM3OeQCttuDvFemUi3/K8NzrwoirQK3YeHKRYofusONxdVDAVh1LGxgkhSREl4QJHVqNClL+XfPSJ5+PDLMyw3ABbJljPZVTpsfAEU8vq6AdkiFXBej2Y+WS9Yxle8AvuUCPjC8GleppG9I/tD8LfxDr/QX0jwZwZpGrI4f7wyN3gCgtIn9hO3nXOH8irEfUAXJtmLZlV6mJMZZWx6YWGAXd8plrrxl5jpradEGbtS+CEJsYgyvm9JpP5o+iPLNRSJlvRQ6eRaGCKYlZdaMl72EmwyEh1eA2sgZuTpLkHzZSxEhN+L1vwzgdIY+KfJrI35RGH3ntEbZYO+V0Si8vKI+INIXUNrGDgeBonlro6J7qXfcBNOk0lFUNZGquN9aHxD7Mtd/nGQ6WD0HLZIbkX7ka20wQGmTVgJ8Yl7T08oARLLBcqEUUXmFYXaXSxQ2kd33GQr0e7qgDWaogjwYtH2ep9KD78rKUPcivmSWIXx28jGW/HH7EGgD+L0w1udTXdnLIBXwkv/swVHxRTyS4kiiND9P49lcddZY+XFb2z2d83yyPxl9K40KPwVUxP+4KhI//n+8jaeWA0k/kzuMwQPnRSlEI=----ATTACHMENT:----NjQ1NTk4OTc2NjY4MTY0OSA3MjU5NTE5NDU1NTk1NzU3IDQ3MDM0MTEzNTUxODI1ODk=