Created
February 19, 2025 00:17
-
-
Save rotarydrone/bbed1d69e0af76ae143a149deee062a0 to your computer and use it in GitHub Desktop.
Generate Kerberos Keys from Password
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Original: https://snovvcrash.rocks/2021/05/21/calculating-kerberos-keys.html | |
Kerberos Key Calculator - Generates Kerberos encryption keys for machine and user accounts. | |
Uses multiple encryption types including RC4-HMAC-NT, AES128-HMAC, and AES256-HMAC. | |
""" | |
import argparse | |
from binascii import unhexlify, hexlify | |
from typing import Dict, Union | |
from impacket.krb5 import constants | |
from impacket.krb5.crypto import Key, string_to_key | |
from Cryptodome.Hash import MD4 | |
CIPHER_TYPES: Dict[str, int] = { | |
'rc4_hmac_nt': int(constants.EncryptionTypes.rc4_hmac.value), | |
'aes128_hmac': int(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value), | |
'aes256_hmac': int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value) | |
} | |
def generate_kerberos_keys(password: bytes, salt: bytes) -> Dict[str, str]: | |
""" | |
Generate Kerberos encryption keys for all supported cipher types. | |
Args: | |
password: Raw password bytes | |
salt: Salt value for key generation | |
Returns: | |
Dictionary mapping cipher names to their hexadecimal key values | |
""" | |
keys = {} | |
for name, cipher in CIPHER_TYPES.items(): | |
if cipher == 23: # RC4-HMAC-NT | |
md4 = MD4.new() | |
md4.update(password) | |
key = Key(cipher, md4.digest()) | |
else: # AES types | |
fixed_password = password.decode('utf-16-le', 'replace').encode('utf-8', 'replace') | |
key = string_to_key(cipher, fixed_password, salt) | |
keys[name] = hexlify(key.contents).decode('utf-8') | |
return keys | |
def process_machine_account(domain: str, hostname: str, hex_password: str) -> Dict[str, Union[str, Dict[str, str]]]: | |
""" | |
Generate Kerberos keys for a machine account. | |
Args: | |
domain: Domain name | |
hostname: Machine hostname | |
hex_password: Machine password in hexadecimal format | |
Returns: | |
Dictionary containing account info and generated keys | |
""" | |
salt = f'{domain.upper()}host{hostname.lower()}.{domain.lower()}'.encode('utf-8') | |
raw_password = unhexlify(hex_password) | |
return { | |
'account': f'{domain.upper()}\\{hostname.upper()}$', | |
'salt': salt.decode('utf-8'), | |
'keys': generate_kerberos_keys(raw_password, salt) | |
} | |
def process_user_account(domain: str, username: str, password: str) -> Dict[str, Union[str, Dict[str, str]]]: | |
""" | |
Generate Kerberos keys for a user account. | |
Args: | |
domain: Domain name | |
username: Username | |
password: Clear-text password | |
Returns: | |
Dictionary containing account info and generated keys | |
""" | |
salt = f'{domain.upper()}{username}'.encode('utf-8') | |
raw_password = password.encode('utf-16-le') | |
return { | |
'account': f'{domain.upper()}\\{username}', | |
'salt': salt.decode('utf-8'), | |
'keys': generate_kerberos_keys(raw_password, salt) | |
} | |
def print_results(results: Dict[str, Union[str, Dict[str, str]]]) -> None: | |
""" | |
Print the account information and generated keys in a formatted manner. | |
Args: | |
results: Dictionary containing account info and keys | |
""" | |
print(results['account']) | |
print(f" * Salt: {results['salt']}") | |
for cipher_name, key in results['keys'].items(): | |
print(f" * {cipher_name}: {key}") | |
def main() -> None: | |
"""Main function to handle command line arguments and process accounts.""" | |
parser = argparse.ArgumentParser( | |
description='Generate Kerberos encryption keys for machine or user accounts' | |
) | |
parser.add_argument('-d', '--domain', required=True, | |
help='Domain name') | |
subparsers = parser.add_subparsers(dest='account_type', required=True, | |
help='Account type') | |
# Machine account parser | |
machine_parser = subparsers.add_parser('machine', | |
help='Generate keys for machine account') | |
machine_parser.add_argument('-n', '--hostname', required=True, | |
help='Machine hostname') | |
machine_parser.add_argument('-p', '--hex-password', required=True, | |
help='Machine password in hexadecimal format') | |
# User account parser | |
user_parser = subparsers.add_parser('user', | |
help='Generate keys for user account') | |
user_parser.add_argument('-u', '--username', required=True, | |
help='Username') | |
user_parser.add_argument('-p', '--password', required=True, | |
help='User password') | |
args = parser.parse_args() | |
try: | |
if args.account_type == 'machine': | |
results = process_machine_account( | |
args.domain, | |
args.hostname, | |
args.hex_password | |
) | |
else: # user account | |
results = process_user_account( | |
args.domain, | |
args.username, | |
args.password | |
) | |
print_results(results) | |
except Exception as e: | |
parser.error(f"Error processing account: {str(e)}") | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment