Цифровая подпись сообщения и объединение его с байтами сообщения.
Вам нужно знать, где заканчивается один, а другой начинается, но точно. Некоторые API просто берут ключ и сообщение и выдают выходные данные байтов, а затем вместо отдельного шага verify (data) -> boolean они берут одну группу байтов и либо возвращают проверенное сообщение, либо терпят неудачу.
Так что да, вы можете отправить
encrypt(
concat(
sign(message, signerPrivateKey), message),
encryptionKey)
Чтобы получить проверенное сообщение, получатель должен заблаговременно получить два ключа: открытый ключ подписывающего лица и ключ дешифрования, который совпадает с ключом encryptionKey для симметричного шифрования и который должен быть защищенным секретом.
Если вы хотите использовать асимметричное шифрование, поэтому вам нужно только обмениваться открытыми ключами, а ваше сообщение не всегда короче ключа, обычно вы генерируете одноразовый симметричный ключ и шифруете только асимметрично, поскольку асимметричные алгоритмы обычно дороже, чем симметричные.
oneTimeUseSymmetricCryptoKey := generateKey()
concat(
encryptAssymetric(
oneTimeUseSymmetricCryptoKey,
encrypterPrivateKey),
encryptSymmetric(
concat(sign(message, signerPrivateKey), message),
oneTimeUseSymmetricCryptoKey))
Ничто из этого не предотвращает атаку пересылки сообщений, описанную в ссылке выше. Для этого вам необходимо аутентифицировать отправителя, например, выбрав открытый ключ для проверки подписи И ключ для расшифровки на основе адреса отправителя, полученного независимо от обмена зашифрованными байтами.