2016-12-10 5 views
2

Я пытаюсь реализовать цифровые подписи SHA256-RSA, и я смущен терминологией и реализацией на C#.Цифровые подписи: шифрование хеша и подписание хэша?

AFAIK, «подписание файла» - это генерация хэша файла, а затем шифрование этого хэша. Я также слышал фразу «подписание хэша». Это одно и то же? Или это хеширование хэша, а затем шифрование хэша?

Вот код в вопросе:

public void SignatureTest(byte[] data, X509Certificate2 cert) 
{ 
    var sha256 = new SHA256CryptoServiceProvider(); 
    var rsa = (RSACryptoServiceProvider)cert.PrivateKey; 

    var hashOfData = sha256.ComputeHash(data); 

    var encryptedHash = rsa.Encrypt(hashOfData, false); 
    var encryptedHashOAEP = rsa.Encrypt(hashOfData, true);    
    var signedHash = rsa.SignHash(hashOfData, "SHA256"); 

    //Shouldn't one of these be true? 
    var false1 = CompareAsBase64Str(encryptedHash, signedHash); 
    var false2 = CompareAsBase64Str(encryptedHashOAEP, signedHash); 

    //This is the one that actually matches 
    var true1 = CompareAsBase64Str(signedHash, rsa.SignData(data, sha256)); 
} 

public bool CompareAsBase64Str(byte[] b1, byte[] b2) 
{ 
    return (Convert.ToBase64String(b1) == Convert.ToBase64String(b2)); 
} 

Вот что говорит MSDN на RSACryptoServiceProvider:

SignHash() Вычисляет подпись для указанного значения хэш с помощью шифрования с закрытым ключом.

Шифрование() Шифрует данные с алгоритмом RSA.

Должен ли сигнал SignHash (hash) и encrypt (hash) быть таким же?

ответ

2

The answer given by zaitsman - хорошее объяснение тем, связанных с вашими вопросами, и я думаю, что это должен быть принятый ответ, но только для того, чтобы помочь связать вернемся к вашему конкретному вопросу о том, почему шифрование хеша не дает вам такого же результата, как подпись хэша (rsa.SignHash(hashOfData, "SHA256") в вашем коде):

Подписание хэш не только шифрует хэш-данные - он также шифрует имя (или некоторый идентификатор) алгоритма хеширования, используемого для генерации хэша вместе с ним. Без этого получатель не будет знать, какой алгоритм использовать при вычислении собственного хэша (отправляемого сообщения) для сравнения с тем, который они только что расшифровали, чтобы проверить подлинность сообщения (что, конечно, является весь смысл).

Когда вы зашифровали хэш самостоятельно (с rsa.Encrypt(hashOfData, false) и rsa.Encrypt(hashOfData, true)), вы только зашифрованные данные хэш и не сочетание хэш данных и идентификатор алгоритма ("SHA256" в коде).Другими словами, вы зашифровали разные данные, так что вы получили разные (зашифрованные) результаты.

Причина возвращаемое значение этого SignHash вызова делает матч значение, возвращаемое rsa.SignData(data, sha256) является то, что последний метод делает то же самое, за исключением того, что делает хэширования и хэш-подписи в качестве одной операции, так что вы не имеете для вычисления хэша в качестве отдельного шага, если он вам не нужен для каких-либо целей, кроме его подписания.

От RSACryptoServiceProvider.SignData Method на MSDN:

Вычисляет значение хэш-функции указанных данных и подписывает его.


Также смотрите: Why does SignHash need to know what hash algorithm was used?

+0

Спасибо! В дополнение к вашей информации об идентификаторе, я нашел ответ [Pavel Ognev] (http://stackoverflow.com/a/12140124/6258530) в связанной вами теме. Надеюсь, я смогу создать правильное заполнение для своих данных, чтобы зашифрованные данные (через 'rsa.Encrypt()') соответствовали сигнатуре (через 'rsa.SignData()') –

1

Вам нужно разделить проблемы, это поможет вам понять терминологию.

Любая произвольная капля данных может быть hash ed и/или encrypt ed в любой комбинации. Hash означает: использовать криптографический алгоритм для генерации необратимого значения (то есть, просто зная алгоритм и хэш, что вы неспособны восстановить исходные данные) и согласованным (то есть с учетом тех же данных и алгоритма, значение хэш выпускается всегда одинаково).

Encrypt означает: использовать криптографический алгоритм для шифрования данных (всего или в блоках) с заданным ключом (ключ может быть симметричным или асимметричным).

Sign средства: Hash данные и Encrypt хэш с заданным ключом. Затем, учитывая пару (для асимметричного) или тот же (для симметричного) ключа, потребитель может подтвердить, что:

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

+0

Спасибо! Я был более смущен термином «подписание хеша», как указано [здесь] (http://crypto.stackexchange.com/questions/6335/is-signing-a-hash-instead-of-the-full- данные считаются безопасными), [здесь] (https://www.globalsign.com/ru/blog/hsm-digital-signature-faq/) и в других местах. Исправьте меня, если я ошибаюсь: так что «знак» глагола - это другой процесс в «подписании файла» и «подписание хэша». Чтобы подписать файл, нужно создать хэш этого файла, а затем зашифровать этот хеш с дополнительными данными, идентифицирующими хеш. Подписать хэш - это просто зашифровать хеш с дополнительными идентифицирующими данными? –

+0

@ nr-91 'Sign' - это точно такой же процесс, независимо от того, что вы подписываете. когда вы передаете действительно большие куски данных (думаю: 10 с ГБ), процесс подписания всего файла может занять много времени, так как обычно данные в сигнатуре каким-то образом окутаны. Тем не менее, вы можете вычислить хэш во время потоковой передачи блоков данных клиенту, а затем подписать только это для проверки подлинности. Таким образом, данные поступают неподписанными и незашифрованными, но клиент может сам генерировать хеш (при получении), а затем проверять это на сообщение «подписанный хеш». – zaitsman

+0

Итак, 'Sign (hash)' - это тот же процесс, что и 'Sign (data)'? 'Sign (объект obj) { var hash = CalculateHash (obj); var hashAndPadding = hash + CreatePadding(); знак возврата (hashAndPadding); } ' Это бесконечная рекурсия. –

Смежные вопросы