Skip to content

Instantly share code, notes, and snippets.

@leechristensen
Last active October 16, 2025 23:26
Show Gist options
  • Save leechristensen/40acb67ff5b788d6b78d81443b66b444 to your computer and use it in GitHub Desktop.
Save leechristensen/40acb67ff5b788d6b78d81443b66b444 to your computer and use it in GitHub Desktop.
Python function that calculates the key name hash used in CNG private key file names.
# CNG local system private keys are stored in the following location in this format:
# C:\ProgramData\Microsoft\Crypto\SystemKeys\<hash>_<machineGuid>
#
# <hash> is caclulated with the function below. The key name is specified when calling NCryptOpenKey
# <machineGuid> is the Window's machine's GUID found in HKLM\SOFTWARE\Microsoft\Cryptography ! MachineGuid
#
# References:
# - https://learn.microsoft.com/en-us/windows/win32/seccng/key-storage-and-retrieval#key-directories-and-files
# - https://learn.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptopenkey
def get_cng_private_key_hash(key_name: str) -> str:
"""
Simplified version that returns the hash or raises an exception.
Args:
key_name: Source string to hash
Returns:
MD5 hash formatted as 32 hex characters
Raises:
ValueError: If input is invalid
"""
if not key_name:
raise ValueError("Input string cannot be empty")
# Convert to lowercase
lower_str = key_name.lower()
# Encode as UTF-16 LE, INCLUDING the null terminator
wide_bytes = (lower_str + '\0').encode('utf-16-le')
# Compute MD5 hash
import hashlib
md5_hash = hashlib.md5(wide_bytes).digest()
# Convert to 4 32-bit integers and format
hash_ints = []
for i in range(4):
chunk = md5_hash[i*4:(i+1)*4]
value = int.from_bytes(chunk, byteorder='little', signed=False)
hash_ints.append(value)
return ''.join(f'{val:08x}' for val in hash_ints)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment