Привет, коллеги-программисты!
Я хочу реализовать шифрование натрия в своем веб-сервисе.
Сообщения не должны декодироваться отправителем, только получателем. Однако я хочу, чтобы отправитель прошел аутентификацию.
В соответствии с неофициальной документацией от 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()
, что означает, что мне придется генерировать две пары ключей для каждого хоста или клиента. Это было бы очень неудобно.