Преобразование функции хеширования подписи Nodejs или Java в PHP

Я пытаюсь создать подпись PKI, используя закрытый ключ в PHP.

Это следующие правила для создания подписи

  1. Используйте алгоритм SHA-2 для генерации хэша базовой строки подписи.

  2. Подпишите хэшированное значение, используя закрытый ключ приложения.

  3. Base64-кодирует значение подписи. ПРИМЕЧАНИЕ. Кодировка Base64 не должна включать CRLF (возврат каретки/перевод строки) через каждые 72 символа, что является частью строгой кодировки Base64. Вместо этого вся строка в кодировке Base64 должна быть без разрывов строк.

  4. Установите строку в качестве значения параметра подписи.

Пример кода Nodejs:

var signature = crypto.createSign('RSA-SHA256')
                      .update(baseString)
                      .sign(signWith, 'base64');

Java-код

String baseString = "Constructed base string";
Signature sig = Signature.getInstance("RSA-SHA256");
sig.initSign(privateKey); // Get private key from keystone
sig.update(baseString.getBytes());
byte[] signedData = sig.sign();
String finalStr = Base64.getEncoder().encodeToString(signedData);

Я пытаюсь преобразовать этот код в PHP, моя базовая строка верна.

// $data = "BaseString";
// $private_key_pem = openssl_pkey_get_private("file://".$path."privateKey.pem",'passphrase');
$hash = hash('sha256', $data);
$result = openssl_sign($hash, $signature, $private_key_pem,'RSA-SHA256');
$signature = base64_encode($signature);
            

Это верно? Если да, ответ API — недействительная подпись PKI.


person Dnyanesh    schedule 01.07.2020    source источник


Ответы (1)


Я устанавливаю две программы на Java и PHP для сравнения вывода (signature = finalStr) и проверки подписи. Чтобы получить сопоставимый результат, я жестко запрограммировал ключи RSA в обеих программах, поэтому код выглядит немного странно.

Чтобы получить более короткие строки ключей, я сгенерировал 512-битные ключи RSA, которые не являются безопасными — используйте ключи не менее 2048 бит в рабочей среде.

Как видите, обе программы генерируют одну и ту же подпись:

finalStr: NEHC7o+mW34qoTNOwXRQIRfs80s/YhudzX0K4AGlFTeyyJcRhit9f03iw58Ww1Eo3zfkSrrz3411TZheVLHFnQ==

и обе программы могут проверить подпись как true.

Это код Java:

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class MainSo {
    public static void main(String[] args) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, InvalidKeySpecException {
        System.out.println("https://stackoverflow.com/questions/62674669/converting-nodejs-or-java-signature-hashing-function-to-php");

        // keys are sample rsa 512 keys
        String privateKey1 = "-----BEGIN PRIVATE KEY-----\n" +
                "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqg8Hlhxm7LfqASjF\n" +
                "KMce91anr2ViG/K8GQmk0HPMiw3Lh6DrGDGmsw2jUczwQTyv07qDwWwf+vaEiTdk\n" +
                "jd1JxQIDAQABAkAOGbTtU2mNUyqJ8hF28hu1MnAw8N0TqCrEgLIzvoZFOTqvxPqc\n" +
                "VaCuUs4Fm/J5x8gWLycsRmbBMeecIzvjzXY5AiEAtoZ4WSplvJbEHjiKhW+dRICc\n" +
                "tSTcGaTf0v4vdfQTiGsCIQDug9wLUZDiSttbz2QlA3QthFX+UIu8fE/A/lGEjXnC\n" +
                "jwIgcejRyrPO8jcVBdc7e7MAbvPk2Je8VLS0irTfYbmFRykCIQDCFsbu5vbxTlzm\n" +
                "fwNNI1xc1b1sb3rmbHox4EHRjZaxfQIgEr2r53jmSRlyQfueo4nLZJhTGXdaJN8Z\n" +
                "yoWwFsFqsiA=\n" +
                "-----END PRIVATE KEY-----";
        String publicKey1 = "-----BEGIN PUBLIC KEY-----\n" +
                "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoPB5YcZuy36gEoxSjHHvdWp69lYhvy\n" +
                "vBkJpNBzzIsNy4eg6xgxprMNo1HM8EE8r9O6g8FsH/r2hIk3ZI3dScUCAwEAAQ==\n" +
                "-----END PUBLIC KEY-----";
        // rsa key generation
        // Remove markers and new line characters in private key
        String realPrivateKey = privateKey1.replaceAll("-----END PRIVATE KEY-----", "")
                .replaceAll("-----BEGIN PRIVATE KEY-----", "")
                .replaceAll("\n", "");
        byte[] priKey = Base64.getDecoder().decode(realPrivateKey);
        PKCS8EncodedKeySpec specPri = new PKCS8EncodedKeySpec(priKey);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = kf.generatePrivate(specPri);
        // Remove markers and new line characters in public key
        String realPublicKey = publicKey1.replaceAll("-----END PUBLIC KEY-----", "")
                .replaceAll("-----BEGIN PUBLIC KEY-----", "")
                .replaceAll("\n", "");
        byte[] pubKey = Base64.getDecoder().decode(realPublicKey);
        X509EncodedKeySpec specPub = new X509EncodedKeySpec(pubKey);
        PublicKey publicKey = kf.generatePublic(specPub);

        String baseString = "Constructed base string";

        //Signature sig = Signature.getInstance("RSA-SHA256");
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(privateKey); // Get private key from keystone
        sig.update(baseString.getBytes());
        byte[] signedData = sig.sign();
        String finalStr = Base64.getEncoder().encodeToString(signedData);
        System.out.println("finalStr: " + finalStr);

        // verify signature
        byte[] signedDataVerify = Base64.getDecoder().decode(finalStr);
        Signature sigVerify = Signature.getInstance("SHA256withRSA");
        sigVerify.initVerify(publicKey);
        sigVerify.update(baseString.getBytes());
        boolean verified = sigVerify.verify(signedDataVerify);
        System.out.println("signature verified: " + verified);
    }
}

и вот PHP-код:

<?php
// https://stackoverflow.com/questions/62674669/converting-nodejs-or-java-signature-hashing-function-to-php
$data = 'Constructed base string';

// sample 512 rsa keys
$privateKey1 = "-----BEGIN PRIVATE KEY-----\n" .
        "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqg8Hlhxm7LfqASjF\n" .
        "KMce91anr2ViG/K8GQmk0HPMiw3Lh6DrGDGmsw2jUczwQTyv07qDwWwf+vaEiTdk\n" .
        "jd1JxQIDAQABAkAOGbTtU2mNUyqJ8hF28hu1MnAw8N0TqCrEgLIzvoZFOTqvxPqc\n" .
        "VaCuUs4Fm/J5x8gWLycsRmbBMeecIzvjzXY5AiEAtoZ4WSplvJbEHjiKhW+dRICc\n" .
        "tSTcGaTf0v4vdfQTiGsCIQDug9wLUZDiSttbz2QlA3QthFX+UIu8fE/A/lGEjXnC\n" .
        "jwIgcejRyrPO8jcVBdc7e7MAbvPk2Je8VLS0irTfYbmFRykCIQDCFsbu5vbxTlzm\n" .
        "fwNNI1xc1b1sb3rmbHox4EHRjZaxfQIgEr2r53jmSRlyQfueo4nLZJhTGXdaJN8Z\n" .
        "yoWwFsFqsiA=\n" .
        "-----END PRIVATE KEY-----\n";

$publicKey1 = "-----BEGIN PUBLIC KEY-----\n" .
        "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoPB5YcZuy36gEoxSjHHvdWp69lYhvy\n" .
        "vBkJpNBzzIsNy4eg6xgxprMNo1HM8EE8r9O6g8FsH/r2hIk3ZI3dScUCAwEAAQ==\n" .
        "-----END PUBLIC KEY-----\n";

$privateKey = openssl_pkey_get_private ($privateKey1);
$publicKey = openssl_pkey_get_public($publicKey1);

// create the signature
openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256);
echo 'finalStr (Base64):' . PHP_EOL . base64_encode($signature) . PHP_EOL;

// verify signature
$result = openssl_verify($data, $signature, $publicKey, "sha256WithRSAEncryption");
echo 'verified (0=false, 1=true): ' . $result;
?>
person Michael Fehr    schedule 08.07.2020