Мне нужно проверить подпись, у меня есть пример кода, который я реализовал в nodeJS и работает как шарм.
const crypto = require('crypto');
app.post('/api/verify', (req, res) => {
const signature = req.headers['signature']
let rawBody = req.body;
rawBody = JSON.stringify(rawBody);
const result = verifySignature(signature, rawBody)
res.send(`Signature verification status: ${result}`); // Return True
});
const verifySignature = (signature, rawBody) => {
const publicKey = fs.readFileSync('public.pem', 'utf8');
const verifier = crypto.createVerify('RSA-SHA256')
verifier.update(rawBody)
return verifier.verify({ key: publicKey, padding: constants.RSA_PKCS1_PSS_PADDING }, signature, 'base64')
}
Теперь проблема в том, что я должен проверить это в PHP (LARAVEL), для этого я использую phpseclib.
use phpseclib\Crypt\RSA;
$signature = $request->header('signature');
$bodyContent = $request->getContent();
$result = $this->verify_signature($signature , $bodyContent); // Always False
protected function verify_signature($signature, $requestBody): bool
{
$rsa = new RSA();
$rsa->setSignatureMode(RSA::SIGNATURE_PSS);
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setHash("sha256");
$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
XXXXXXXXXXX
-----END PUBLIC KEY-----
EOD;
$rsa->loadKey($public_key);
$result = $rsa->verify($requestBody , base64_decode($signature));
if ($result) {
return true;
}
return false;
}
Может кто-нибудь, пожалуйста, дайте мне знать, что мне здесь не хватает!?






Обе стороны используют разные параметры PSS. Однако для успешной проверки должны применяться те же параметры PSS. Параметры по умолчанию, используемые на стороне NodeJS, можно найти в документации NodeJS:
RSA_PSS_SALTLEN_AUTO, которая автоматически определяет длину соли из структуры блока PSS. Насколько я знаю, phpseclib не поддерживает это, поэтому вам нужно узнать длину соли. Если подписание также выполнялось с помощью NodeJS и использовалась длина соли по умолчанию, применяется максимально возможная длина соли ( sign() использует RSA_PSS_SALTLEN_MAX_SIGN), а именно:signature length (bytes) - digest output length (bytes) - 2 = 256 - 32 - 2.В PHP-коде SHA1 используется по умолчанию для обоих дайджестов, т.е. хэш MGF1 должен быть указан явно. Длина соли по умолчанию равна 0, т.е. должна (вероятно) также быть задана явно. Значения по умолчанию см. в документации phpseclib, V2.
Пример: следующий код NodeJS выполнен успешно, т. е. подпись успешно проверена. Подпись также была сгенерирована с использованием NodeJS и значения по умолчанию (т. е. максимальной длины соли):
const crypto = require('crypto');
function verifySignature(signature, rawBody) {
const publicKey = publicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT
5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E
bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw
KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x
H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4
OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i
GwIDAQAB
-----END PUBLIC KEY-----`;
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(rawBody);
return verifier.verify({ key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }, signature, 'base64');
}
const signature = "LrQcFTFvgRxC/1aSnKn+lgHDmMNsv+F1E7/u6Y2KtbbzlUuO1ehls6F/sS+G9Q+oPuVVW/6xeMr++ygOJU5LlwwsliVxxs05OBZIvRrDwoNHqipakNN8SkZWSLdAuj1j9pv1bApwQjshFjOFPA11NgZGjdDvaB5Yayt4m3jewwR4Zxvtpqcd0MV1Ja22v3zfHQqca0Oahx4g6aLAy9WCLmVuFWZRauFKx0s+k+tPUs1ssTz/equl405T6PErQ1YbfApSqg4v0RAvHu7WWVG4s3lONU+jMUyqC4OHdf0mEgweNx9Kzy6gLA8nrrQGjxdomJmQuGxjX6BTlrRQjRecGw= = ";
const msg = "The quick brown fox jumps over the lazy dog";
const verified = verifySignature(signature, msg);
console.info(verified); // true
Аналог PHP с phpseclib (V2):
use phpseclib\Crypt\RSA;
$publicKey = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT
5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E
bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw
KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x
H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4
OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i
GwIDAQAB
-----END PUBLIC KEY-----';
$rsa = new RSA();
$rsa->loadKey($publicKey);
$rsa->setSignatureMode(RSA::SIGNATURE_PSS);
$rsa->setHash("sha256");
$rsa->setMGFHash("sha256"); // set MGF digest explicitly
$rsa->setSaltLength(256-32-2); // set salt length explicitly
$msg = "The quick brown fox jumps over the lazy dog";
$signature = "LrQcFTFvgRxC/1aSnKn+lgHDmMNsv+F1E7/u6Y2KtbbzlUuO1ehls6F/sS+G9Q+oPuVVW/6xeMr++ygOJU5LlwwsliVxxs05OBZIvRrDwoNHqipakNN8SkZWSLdAuj1j9pv1bApwQjshFjOFPA11NgZGjdDvaB5Yayt4m3jewwR4Zxvtpqcd0MV1Ja22v3zfHQqca0Oahx4g6aLAy9WCLmVuFWZRauFKx0s+k+tPUs1ssTz/equl405T6PErQ1YbfApSqg4v0RAvHu7WWVG4s3lONU+jMUyqC4OHdf0mEgweNx9Kzy6gLA8nrrQGjxdomJmQuGxjX6BTlrRQjRecGw= = ";
$result = $rsa->verify($msg , base64_decode($signature));
echo $result ? 'verified' : 'unverified'; // verified
который также успешно проверяет подпись.
Большое спасибо за ваше исчерпывающее объяснение, вы спасли мой день.
verify()в коде NodeJS по умолчанию используетRSA_PSS_SALTLEN_AUTOдля длины соли, которая автоматически определяет длину соли из структуры блока PSS. Насколько я знаю, phpseclib не поддерживает это, поэтому необходимо знать длину соли. Для этого требуется код для подписи или полный образец данных (нерабочая пара ключей, сообщение, подпись).