PHP натрия: используйте те же ключи для натрия_crypto_sign и натрия_crypto_box_seal - PullRequest
0 голосов
/ 14 января 2020

Привет, коллеги-программисты!

Я хочу реализовать шифрование натрия в своем веб-сервисе.

Сообщения не должны декодироваться отправителем, только получателем. Однако я хочу, чтобы отправитель прошел аутентификацию.

В соответствии с неофициальной документацией от paragon ie .com я должен использовать sodium_crypto_sign() в сочетании с sodium_crypto_box_seal().

Есть ли способ использовать одну пару ключей как для sodium_crypto_box_seal(), так и для sodium_crypto_sign()?

Я уже сделал реализацию только для sodium_crypto_box_seal() без подписи. Это работало просто отлично.

Это класс, который генерирует пару ключей.

class SodiumCryptoBoxKeyPairGenerator implements KeyPairGeneratorInterface
{
    private KeyPairFactoryInterface $keyPairFactory;

    public function __construct( KeyPairFactoryInterface $keyPairFactory )
    {
        $this->keyPairFactory = $keyPairFactory;
    }

    public function generate(): KeyPairInterface
    {
        $keyPair = sodium_crypto_box_keypair();

        return $this->keyPairFactory->createFromSecretAndPublicKey(
            sodium_bin2base64(
                sodium_crypto_box_secretkey( $keyPair ),
                SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
            ),
            sodium_bin2base64(
                sodium_crypto_box_publickey( $keyPair ),
                SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
            )
        );
    }
}

Я отредактировал класс Encryptor, включив в него подпись и проверку.

class SodiumCryptoBoxSealEncryptor implements KeyPairEncryptorInterface
{
    public function encrypt( string $unEncryptedString, string $receiverPublicKey, KeyPairInterface $localKeyPair ): string
    {
        $signedString = sodium_crypto_sign(
            $unEncryptedString,
            sodium_base642bin( $localKeyPair->getSecretKey(), SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING )
        );
        $encryptedString = sodium_crypto_box_seal(
            $signedString,
            sodium_base642bin( $receiverPublicKey, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING )
        );

        return sodium_bin2base64( $encryptedString, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
    }

    public function decrypt( string $encryptedString, string $senderPublicKey, KeyPairInterface $localKeyPair ): string
    {
        $localKeyPair = sodium_crypto_box_keypair_from_secretkey_and_publickey(
            sodium_base642bin( $localKeyPair->getSecretKey(), SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING ),
            sodium_base642bin( $localKeyPair->getPublicKey(), SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING )
        );
        $decryptedString = sodium_crypto_box_seal_open(
            sodium_base642bin( $encryptedString, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING ),
            $localKeyPair
        );
        $verifiedDecryptedString = sodium_crypto_sign_open(
            $decryptedString,
            sodium_base642bin( $senderPublicKey, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING )
        );

        return $verifiedDecryptedString;
    }
}

Я создал тест

echo 'Please write a message: ';
$message = fgets(STDIN);
echo 'Plain: ' . $message;

$keyPair = $this->keyPairProvider->getKeyPair();

$encryptedMessage = $this->encryptor->encrypt(
    $message,
    $keyPair->getPublicKey(),
    $keyPair
);
echo 'Encrypted: ' . $encryptedMessage;

$decryptedMessage = $this->encryptor->decrypt(
    $encryptedMessage,
    $keyPair->getPublicKey(),
    $keyPair
);
echo 'Decrypted: ' . $decryptedMessage; 

При выполнении теста я получаю следующий результат:

Пожалуйста, напишите сообщение: test

Обычный: test

PHP Неустранимая ошибка: Uncaught SodiumException: размер секретного ключа должен составлять SODIUM_CRYPTO_SIGN_SECRETKEYBYTES байт в **** / Encryptor / SodiumCryptoBoxSealEncryptor. php: 14

из какого я должен понимать, сгенерировано для sodim_crypto_sign(), что означает, что мне придется генерировать две пары ключей для каждого хоста или клиента. Это было бы очень неудобно.

...