Как использовать хэширование SHA1 в программировании на языке C
Я пытаюсь написать программу на C, которая доказывает, что SHA1 почти не содержит конфликтов, но я не могу понять, как на самом деле создать хеш для моих входных значений. Мне просто нужно создать хэш и сохранить шестнадцатеричное значение в массиве. После некоторых поисков Google я нашел документацию OpenSSL, в которой мне было предложено использовать это:
#include <openssl/sha.h>
unsigned char *SHA1(const unsigned char *d, unsigned long n,
unsigned char *md);
int SHA1_Init(SHA_CTX *c);
int SHA1_Update(SHA_CTX *c, const void *data,
unsigned long len);
int SHA1_Final(unsigned char *md, SHA_CTX *c);
Я считаю, что я должен использовать либо unsigned char * SHA1, либо SHA1_Init, но я не уверен, какие аргументы будут, если x - мой вход, который будет хэширован. Кто-нибудь, пожалуйста, очистите это для меня? Спасибо.
Ответы
Ответ 1
Если у вас есть все ваши данные одновременно, просто используйте функцию SHA1
:
// The data to be hashed
char data[] = "Hello, world!";
size_t length = sizeof(data);
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(data, length, hash);
// hash now contains the 20-byte SHA-1 hash
Если, с другой стороны, вы получаете только свои данные за один раз и хотите вычислить хеш при получении этих данных, а затем использовать другие функции:
// Error checking omitted for expository purposes
// Object to hold the current state of the hash
SHA_CTX ctx;
SHA1_Init(&ctx);
// Hash each piece of data as it comes in:
SHA1_Update(&ctx, "Hello, ", 7);
...
SHA1_Update(&ctx, "world!", 6);
// etc.
...
// When you're done with the data, finalize it:
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Final(hash, &ctx);
Ответ 2
Это два разных способа достижения одного и того же.
В частности, вы или используете SHA_Init
, а затем SHA_Update
столько раз, сколько необходимо для передачи ваших данных, а затем SHA_Final
, чтобы получить дайджест, или вы SHA1
.
Причиной двух режимов является то, что при хэшировании больших файлов обычным является чтение файла в кусках, поскольку альтернатива будет использовать много памяти. Следовательно, отслеживание SHA_CTX
- контекста SHA - по мере того, как вы идете, вы можете обойти это. Алгоритм внутри также подходит для этой модели, то есть данные передаются в блоке за раз.
Метод SHA
должен быть достаточно простым. Другой работает следующим образом:
unsigned char md[SHA_DIGEST_LENGTH];
SHA_CTX context;
int SHA1_Init(&context);
for ( i = 0; i < numblocks; i++ )
{
int SHA1_Update(&context, pointer_to_data, data_length);
}
int SHA1_Final(md, &context);
В конечном итоге md
будет содержать двоичный дайджест, а не шестнадцатеричное представление - это не строка и не должен использоваться как один.
Ответ 3
Первая функция (SHA1()
) - это более высокоуровневая, она, вероятно, та, которую вы хотите. Документ довольно понятен в использовании - d
- это вход, n
- его размер, а md
- это место, где размещен результат (вы его назначаете).
Что касается других 3 функций - это более низкий уровень, и я уверен, что они внутренне используются первым. Они лучше подходят для больших входов, которые необходимо обрабатывать поэтапно.
Ответ 4
Я считаю, что должен использовать либо unsigned char *SHA1
, либо SHA1_Init
...
Для более поздних версий библиотеки OpenSSL, например 1.0.2 и 1.1.0, проект рекомендует использовать интерфейс EVP. Пример использования EVP Message Digests с SHA256 доступен в вики OpenSSL:
#define handleErrors abort
EVP_MD_CTX *ctx;
if((ctx = EVP_MD_CTX_create()) == NULL)
handleErrors();
if(1 != EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))
handleErrors();
unsigned char message[] = "abcd .... wxyz";
unsinged int message_len = sizeof(message);
if(1 != EVP_DigestUpdate(ctx, message, message_len))
handleErrors();
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_len = sizeof(digest);
if(1 != EVP_DigestFinal_ex(ctx, digest, &digest_len))
handleErrors();
EVP_MD_CTX_destroy(ctx);