One-Way Hash Algorithm Overview
A one-way hash function generates a fixed-size output, known as a hash value or digest, from an input of any size. This hash serves as a unique "fingerprint" for the data. Comparing hash values allows verification of data integrity without comparing the original data directly. These functions are also called cryptographic hash functions or message digest functions.
The input is referred to as the message or pre-image. The output is the hash, digest, or fingerprint. The hash value length is constant (e.g., 256 bits for SHA-256) regardless of input size.
OpenSSL EVP Implementation
The OpenSSL EVP (Envelope) API provides a high-level interface to cryptographic functions, including hash algorithms. It abstracts algorithm details, allowing code to work with different algorithms through a consistent API. The openssl/evp.h header declares these functions. Initializing all algorithms requires calling OpenSSL_add_all_algorithms().
Core Data Structures
EVP_MD Structure
This structure defines a message digest algorithm. All hash algorithm implementations maintain a pointer to an EVP_MD structure.
typedef struct env_md_st {
int type;
int pkey_type;
int md_size;
unsigned long flags;
int (*init)(EVP_MD_CTX *ctx);
int (*update)(EVP_MD_CTX *ctx, const void *data, unsigned long count);
int (*final)(EVP_MD_CTX *ctx, unsigned char *md);
int (*copy)(EVP_MD_CTX *to, const EVP_MD_CTX *from);
int (*cleanup)(EVP_MD_CTX *ctx);
int (*sign)();
int (*verify)();
int required_pkey_type[5];
int block_size;
int ctx_size;
int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
} EVP_MD;
type: Algorithm NID (Numeric Identifier).md_size: Digest output length (e.g., 20 for SHA-1).init: Pointer to algorithm initialization function.update: Pointer to data processing function.final: Pointer to finalization function producing the digest.block_size: Internal block size in bytes.
EVP_MD_CTX Structure
This context structure holds state for a hash operation.
typedef struct env_md_ctx_st {
const EVP_MD *digest;
ENGINE *engine;
unsigned long flags;
void *md_data;
EVP_PKEY_CTX *pctx;
int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count);
} EVP_MD_CTX;
digest: Pointer to theEVP_MDstructure for the algorithm in use.md_data: Algorithm-specific context data.
Key Functions
// Retrieves an EVP_MD structure by algorithm name (e.g., "sha256").
const EVP_MD *EVP_get_digestbyname(const char *name);
// Performs a one-shot hash calculation.
int EVP_Digest(const void *data, size_t count,
unsigned char *md, unsigned int *size,
const EVP_MD *type, ENGINE *impl);
EVP_Digest hashes data of length count using algorithm type, storing the digest in md and its length in size.
Demonstration Program
A sample program demonstrates using the OpenSSL EVP API for hashing.
Development Environment
- OpenSSL 1.0.2l
- Visual Studio 2015
- Windows 10 Pro x64
Features
The program provides a graphical interface with the following capabilities:
- Algorithm Selection: MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512.
- Input/Output Format Support: String (text), Hexadecimal, Base64.
- Hash Calculation: Computes and displays the digest for given input.
The core hashing logic follows this pattern:
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
int compute_hash(const char* alg_name, const unsigned char* input, size_t in_len, unsigned char* digest, unsigned int* digest_len) {
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
const EVP_MD* md = EVP_get_digestbyname(alg_name);
int ret = 0;
if (mdctx == NULL || md == NULL) {
goto cleanup;
}
if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
goto cleanup;
}
if (EVP_DigestUpdate(mdctx, input, in_len) != 1) {
goto cleanup;
}
if (EVP_DigestFinal_ex(mdctx, digest, digest_len) != 1) {
goto cleanup;
}
ret = 1;
cleanup:
EVP_MD_CTX_free(mdctx);
return ret;
}