A cryptographic hash turns any amount of data into a short, fixed size digest. The same input always produces the same digest, a different input (even one changed bit) produces a completely different one, and there is no practical way to find an input that produces a chosen digest. A message authentication code (MAC) adds a secret key to that idea, so the digest also proves the data was not altered by anyone who does not hold the key.
All functions on this page take and return TBytes and live in sgcCrypto_SHA2, sgcCrypto_Keccak, sgcCrypto_Blake2b, sgcCrypto_Blake2s, sgcCrypto_SipHash, sgcCrypto_HMAC, sgcCrypto_CMAC and sgcCrypto_Poly1305.
SHA-2
The hash family behind TLS certificates, code signing and most protocols in production today. Use SHA-256 unless something specific asks for a different size.
function sgcSHA1(const aData: TBytes): TBytes;
function sgcSHA224(const aData: TBytes): TBytes;
function sgcSHA256(const aData: TBytes): TBytes;
function sgcSHA384(const aData: TBytes): TBytes;
function sgcSHA512(const aData: TBytes): TBytes;
SHA-3, SHAKE, cSHAKE and KMAC
SHA-3 is built on a different construction (Keccak) than SHA-2, so a weakness in one family does not carry over to the other, which is why protocols that need long term assurance often specify both. SHAKE128 and SHAKE256 are extendable output functions: instead of a fixed digest size, you ask for as many bytes as you need, and a shorter output is always a prefix of a longer one from the same input. ML-KEM, ML-DSA and SLH-DSA (see Post-Quantum Cryptography) are all built on SHAKE internally. KMAC is the SHA-3 native message authentication code, built on cSHAKE.
function sgcSHA3_224(const aData: TBytes): TBytes;
function sgcSHA3_256(const aData: TBytes): TBytes;
function sgcSHA3_384(const aData: TBytes): TBytes;
function sgcSHA3_512(const aData: TBytes): TBytes;
function sgcSHAKE128(const aData: TBytes; aLen: Integer): TBytes;
function sgcSHAKE256(const aData: TBytes; aLen: Integer): TBytes;
function sgcKMAC128(const aKey, aData: TBytes; aLen: Integer; const aCustom: TBytes): TBytes;
function sgcKMAC256(const aKey, aData: TBytes; aLen: Integer; const aCustom: TBytes): TBytes;
BLAKE2b and BLAKE2s
BLAKE2 is faster than SHA-2 and SHA-3 in software while offering the same security margin, and it takes an optional key directly, without the HMAC construction. BLAKE2b targets 64-bit platforms with digests up to 512 bits; BLAKE2s targets 32-bit and embedded platforms with digests up to 256 bits. A shorter digest is not a truncation of the full one, the length is mixed into the hash itself, so a program cannot switch sizes and expect matching output.
function sgcBlake2b(const aData: TBytes; aDigestLen: Integer = 64): TBytes;
function sgcBlake2b_Keyed(const aKey, aData: TBytes; aDigestLen: Integer = 64): TBytes;
function sgcBlake2s(const aData: TBytes; aDigestLen: Integer = 32): TBytes;
function sgcBlake2s_Keyed(const aKey, aData: TBytes; aDigestLen: Integer = 32): TBytes;
SipHash
SipHash-2-4 is a fast, keyed hash designed for hash table lookups. Its job is to stop an attacker feeding your application chosen inputs that all land in the same bucket and turn an O(1) lookup into O(n), a denial of service technique known as hash flooding. It takes exactly 16 bytes of key and produces an 8 byte tag; it is not a general purpose MAC and should not be used to authenticate messages.
function sgcSipHash24(const aKey, aData: TBytes): TBytes;
HMAC
HMAC turns any of the hashes above into a message authentication code. It is the standard choice when the underlying hash does not accept a key directly (SHA-1, SHA-2).
function sgcHMAC_SHA1(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA256(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA384(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA512(const aKey, aData: TBytes): TBytes;
var
oTag: TBytes;
begin
oTag := sgcHMAC_SHA256(TBytes(oKey), TBytes(oMessage));
end;
AES-CMAC
CMAC builds a MAC out of a block cipher instead of a hash. Use it where a protocol specifies AES-CMAC by name (it is common in smart card and IoT specifications); otherwise HMAC-SHA256 is the more usual default.
function sgcAES_CMAC(const aKey, aData: TBytes): TBytes;
function sgcAES_CMAC_Verify(const aKey, aData, aTag: TBytes): Boolean;
Poly1305
Poly1305 is a one time authenticator: it must never be used twice with the same key. In practice it is not called directly, it is the authentication half of the ChaCha20-Poly1305 and XChaCha20-Poly1305 AEAD ciphers on the Symmetric Encryption page, which derive a fresh one time key for every message.
function sgcPoly1305(const aKey, aData: TBytes): TBytes;
function sgcPoly1305_Verify(const aKey, aData, aTag: TBytes): Boolean;
Comparing a MAC or a password hash
Never compare two tags or digests with a plain = when one of them came from an untrusted source. A byte by byte compare that returns as soon as it finds a mismatch takes measurably less time the earlier the mismatch occurs, which is enough of a signal for an attacker to forge a valid tag one byte at a time over many attempts. Use the constant time compare from sgcCrypto_Encoding instead, listed under Encoding & utilities on the Cryptography overview page.
function sgcConstantTimeEquals(const aLeft, aRight: TBytes): Boolean;
RIPEMD-160
A 160 bit digest from the European RIPE project, in sgcCrypto_Legacy but not legacy in the sense the section below means. It is not broken the way MD5 and SHA-1 are, but it is slower than SHA-256 and offers less security margin, so it belongs where a format names it specifically rather than as a default choice. Bitcoin and every chain descended from it use it for addresses, layered over SHA-256. HMAC-RIPEMD160 is RFC 2286.
function sgcRIPEMD160(const aData: TBytes): TBytes;
function sgcHMAC_RIPEMD160(const aKey, aData: TBytes): TBytes;
var
oHash160: TBytes;
begin
{ the Bitcoin address digest: RIPEMD-160 over SHA-256 }
oHash160 := sgcRIPEMD160(sgcSHA256(oPublicKey));
end;
Legacy hashes
sgcCrypto_Legacy provides MD4, MD5 and HMAC-MD5. All three are broken as security primitives: practical collisions have been published for both MD4 and MD5. They exist only for interoperating with older protocols and file formats that specify them by name (for example NTLM authentication). Do not choose them for anything new; use SHA-256 or BLAKE2b instead.
function sgcMD4(const aData: TBytes): TBytes;
function sgcMD5(const aData: TBytes): TBytes;
function sgcHMAC_MD5(const aKey, aData: TBytes): TBytes;