Коды проверки подлинности сообщений, хэши и подписи
В этой статье обсуждается выявление несанкционированных изменений сообщений с помощью кодов проверки подлинности сообщения (MAC), хэшей и подписей в приложениях универсальной платформы Windows (UWP).
Коды проверки подлинности сообщения (MAC)
С помощью шифрования можно помешать злоумышленнику прочитать сообщение, но нельзя защитить сообщение от изменений. Цена фальсификации сообщения может оказаться очень большой, даже если текст изменен на бессмыслицу. С помощью кода проверки подлинности сообщения (MAC) можно выявить несанкционированное изменение передаваемой информации. Например, рассмотрим следующий сценарий.
- Владимир и Юлия владеют общим секретным ключом и договорились об использовании определенной функции, выдающей код проверки подлинности сообщения.
- Владимир создает сообщение и вместе с секретным ключом передает его функции, которая выдает код проверки подлинности сообщения.
- Боб отправляет сообщение [незашифровано] и значение MAC-адреса Алисе по сети.
- Полученное сообщение вместе с секретным ключом Юлия передает функции, которая выдает код проверки подлинности сообщения. Этот код Юлия сравнивает с кодом, полученным от Владимира. Если они совпадают, это означает, что сообщение не подвергалось изменениям в процессе передачи.
При этом у Инны, которая перехватывает сообщение Владимира Юлии, не получится подделать это сообщение. У Инны нет доступа к секретному ключу, и она, соответственно, не сможет генерировать код проверки подлинности сообщения, при помощи которого поддельное сообщение для Юлии выглядело бы подлинным.
Использование кода проверки подлинности сообщения позволяет убедиться только в том, что исходное сообщение не было изменено, а использование общего секретного ключа — убедиться, что хэш сообщения подписан человеком, имеющим доступ к этому закрытому ключу.
Для перечисления доступных алгоритмов получения кода проверки подлинности сообщения и генерации симметричного ключа можно использовать MacAlgorithmProvider. Для выполнения шифрования и генерации кода проверки подлинности сообщения можно использовать статические методы класса CryptographicEngine.
Цифровые подписи являются эквивалентом открытого ключа для кодов проверки подлинности сообщений (MAC) с закрытым ключом. Для проверки неизменности передаваемого сообщения коды проверки подлинности сообщений используют закрытые ключи, в то время как цифровые подписи — закрытый и открытый ключи в паре.
В этом примере кода показано, как использовать класс MacAlgorithmProvider, чтобы создать хэш-код проверки подлинности сообщения (HMAC).
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
namespace SampleMacAlgorithmProvider
{
sealed partial class MacAlgProviderApp : Application
{
public MacAlgProviderApp()
{
// Initialize the application.
this.InitializeComponent();
// Initialize the hashing process.
String strMsg = "This is a message to be authenticated";
String strAlgName = MacAlgorithmNames.HmacSha384;
IBuffer buffMsg;
CryptographicKey hmacKey;
IBuffer buffHMAC;
// Create a hashed message authentication code (HMAC)
this.CreateHMAC(
strMsg,
strAlgName,
out buffMsg,
out hmacKey,
out buffHMAC);
// Verify the HMAC.
this.VerifyHMAC(
buffMsg,
hmacKey,
buffHMAC);
}
void CreateHMAC(
String strMsg,
String strAlgName,
out IBuffer buffMsg,
out CryptographicKey hmacKey,
out IBuffer buffHMAC)
{
// Create a MacAlgorithmProvider object for the specified algorithm.
MacAlgorithmProvider objMacProv = MacAlgorithmProvider.OpenAlgorithm(strAlgName);
// Demonstrate how to retrieve the name of the algorithm used.
String strNameUsed = objMacProv.AlgorithmName;
// Create a buffer that contains the message to be signed.
BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);
// Create a key to be signed with the message.
IBuffer buffKeyMaterial = CryptographicBuffer.GenerateRandom(objMacProv.MacLength);
hmacKey = objMacProv.CreateKey(buffKeyMaterial);
// Sign the key and message together.
buffHMAC = CryptographicEngine.Sign(hmacKey, buffMsg);
// Verify that the HMAC length is correct for the selected algorithm
if (buffHMAC.Length != objMacProv.MacLength)
{
throw new Exception("Error computing digest");
}
}
public void VerifyHMAC(
IBuffer buffMsg,
CryptographicKey hmacKey,
IBuffer buffHMAC)
{
// The input key must be securely shared between the sender of the HMAC and
// the recipient. The recipient uses the CryptographicEngine.VerifySignature()
// method as follows to verify that the message has not been altered in transit.
Boolean IsAuthenticated = CryptographicEngine.VerifySignature(hmacKey, buffMsg, buffHMAC);
if (!IsAuthenticated)
{
throw new Exception("The message cannot be verified.");
}
}
}
}
хэш-коды;
Криптографическая хэш-функция преобразовывает блок данных произвольной длины в двоичную строку фиксированной длины. Хэш-функции обычно используются при подписывании данных. В большинстве случаев операции подписывания с помощью открытого ключа требуют много вычислительных ресурсов. Вот почему целесообразно подписывать (шифровать) не само исходное сообщение, а его хэш. Рассмотрим типичный, хотя и упрощенный сценарий такой процедуры.
- Владимир и Юлия владеют общим секретным ключом и договорились об использовании определенной функции, выдающей код проверки подлинности сообщения.
- Владимир создает сообщение и вместе с секретным ключом передает его функции, которая выдает код проверки подлинности сообщения.
- Боб отправляет сообщение [незашифровано] и значение MAC-адреса Алисе по сети.
- Полученное сообщение вместе с секретным ключом Юлия передает функции, которая выдает код проверки подлинности сообщения. Этот код Юлия сравнивает с кодом, полученным от Владимира. Если они совпадают, это означает, что сообщение не подвергалось изменениям в процессе передачи.
Заметьте: Юлия послала незашифрованное сообщение. Только хэш был зашифрован. Эта процедура позволяет убедиться только в том, что исходное сообщение не было изменено. А использование открытого ключа Юлии показывает, что хэш сообщения был подписан кем-то, имеющим доступ к ее закрытому ключу, предположительно самой Юлией.
Можно использовать класс HashAlgorithmProvider для перечисления доступных алгоритмов хэширования и создания значения CryptographicHash.
Цифровые подписи являются эквивалентом открытого ключа для кодов проверки подлинности сообщений (MAC) с закрытым ключом. Разница между ними в том, что MAC-коды используют закрытые ключи, для того чтобы получатель мог проверить, не было ли сообщение изменено при передаче, а в цифровых подписях для этого используются пары из открытого и закрытого ключей.
Объект CryptographicHash можно использовать для повторного хэширования различных данных без необходимости заново создавать объект для каждого случая применения. Метод Append добавляет новые данные для хэширования в буфер. Метод GetValueAndReset хэширует данные и сбрасывает параметры объекта для следующего использования. Процедура показана в следующем примере.
public void SampleReusableHash()
{
// Create a string that contains the name of the hashing algorithm to use.
String strAlgName = HashAlgorithmNames.Sha512;
// Create a HashAlgorithmProvider object.
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a CryptographicHash object. This object can be reused to continually
// hash new messages.
CryptographicHash objHash = objAlgProv.CreateHash();
// Hash message 1.
String strMsg1 = "This is message 1.";
IBuffer buffMsg1 = CryptographicBuffer.ConvertStringToBinary(strMsg1, BinaryStringEncoding.Utf16BE);
objHash.Append(buffMsg1);
IBuffer buffHash1 = objHash.GetValueAndReset();
// Hash message 2.
String strMsg2 = "This is message 2.";
IBuffer buffMsg2 = CryptographicBuffer.ConvertStringToBinary(strMsg2, BinaryStringEncoding.Utf16BE);
objHash.Append(buffMsg2);
IBuffer buffHash2 = objHash.GetValueAndReset();
// Hash message 3.
String strMsg3 = "This is message 3.";
IBuffer buffMsg3 = CryptographicBuffer.ConvertStringToBinary(strMsg3, BinaryStringEncoding.Utf16BE);
objHash.Append(buffMsg3);
IBuffer buffHash3 = objHash.GetValueAndReset();
// Convert the hashes to string values (for display);
String strHash1 = CryptographicBuffer.EncodeToBase64String(buffHash1);
String strHash2 = CryptographicBuffer.EncodeToBase64String(buffHash2);
String strHash3 = CryptographicBuffer.EncodeToBase64String(buffHash3);
}
Цифровые подписи
Цифровые подписи являются эквивалентом открытого ключа для кодов проверки подлинности сообщений (MAC) с закрытым ключом. Разница между ними в том, что MAC-коды используют закрытые ключи, для того чтобы получатель мог проверить, не было ли сообщение изменено при передаче, а в цифровых подписях для этого используются пары из открытого и закрытого ключей.
Однако в большинстве случаев операции подписывания с помощью открытого ключа требуют много вычислительных ресурсов. Вот почему целесообразно подписывать (шифровать) не само исходное сообщение, а его хэш. Отправитель создает хэш сообщения, подписывает его и посылает подпись вместе с сообщением (в незашифрованном виде). Получатель вычисляет хэш-код сообщения, расшифровывает подпись и сравнивает полученный результат со значением хэша. Если они совпадают, получатель может быть уверен, что сообщение действительно было послано отправителем и не было изменено в процессе передачи.
Подписывание сообщений дает возможность убедиться только в том, что исходное сообщение не было изменено. А использование открытого ключа отправителя показывает, что хэш сообщения был подписан кем-то, имеющим доступ к закрытому ключу.
Для перечисления доступных алгоритмов подписи, а также для формирования или импорта пары ключей можно использовать объект AsymmetricKeyAlgorithmProvider. Для подписывания сообщения или проверки подписи можно использовать статические методы класса CryptographicHash.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по