Generate Kerberos AES keys from a known password
function Get-KerberosAESKey | |
{ | |
<# | |
.SYNOPSIS | |
Generate Kerberos AES 128/256 keys from a known username/hostname, password, and kerberos realm. The | |
results have been verified against the test values in RFC3962, MS-KILE, and my own test lab. | |
https://tools.ietf.org/html/rfc3962 | |
https://msdn.microsoft.com/library/cc233855.aspx | |
Author: Kevin Robertson (@kevin_robertson) | |
License: BSD 3-Clause | |
.PARAMETER Password | |
[String] Valid password. | |
.PARAMETER Salt | |
[String] Concatenated string containing the realm and username/hostname. | |
AD username format = uppercase realm + case sensitive username (e.g., TEST.LOCALusername, TEST.LOCALAdministrator) | |
AD hostname format = uppercase realm + the word host + lowercase hostname without the trailing '$' + . + lowercase | |
realm (e.g., TEST.LOCALhostwks1.test.local) | |
.PARAMETER Iteration | |
[Integer] Default = 4096: Int value representing how many iterations of PBKDF2 will be performed. AD uses the | |
default of 4096. | |
.PARAMETER OutputType | |
[String] Default = AES: (AES,AES128,AES256,AES128ByteArray,AES256ByteArray) AES, AES128, and AES256 will output strings. | |
AES128Byte and AES256Byte will output byte arrays. | |
.EXAMPLE | |
Verify results against first RFC3962 sample test vectors in section B. | |
Get-KerberosAESKey -Password password -Salt ATHENA.MIT.EDUraeburn -Iteration 1 | |
.EXAMPLE | |
Generate keys for a valid AD user. | |
Get-KerberosAESKey -Salt TEST.LOCALuser | |
.LINK | |
https://gist.github.com/kevin-robertson/ | |
#> | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$false)][String]$Password, | |
[parameter(Mandatory=$true)][String]$Salt, | |
[parameter(Mandatory=$false)][ValidateSet("AES","AES128","AES256","AES128ByteArray","AES256ByteArray")][String]$OutputType = "AES", | |
[parameter(Mandatory=$false)][Int]$Iteration=4096 | |
) | |
if(!$Password) | |
{ | |
$secure_password = Read-Host -Prompt "Enter password" -AsSecureString | |
$password_memory = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure_password) | |
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($password_memory) | |
} | |
[Byte[]]$password_bytes = [System.Text.Encoding]::UTF8.GetBytes($Password) | |
[Byte[]]$salt_bytes = [System.Text.Encoding]::UTF8.GetBytes($Salt) | |
$AES256_constant = 0x6B,0x65,0x72,0x62,0x65,0x72,0x6F,0x73,0x7B,0x9B,0x5B,0x2B,0x93,0x13,0x2B,0x93,0x5C,0x9B,0xDC,0xDA,0xD9,0x5C,0x98,0x99,0xC4,0xCA,0xE4,0xDE,0xE6,0xD6,0xCA,0xE4 | |
$AES128_constant = 0x6B,0x65,0x72,0x62,0x65,0x72,0x6F,0x73,0x7B,0x9B,0x5B,0x2B,0x93,0x13,0x2B,0x93 | |
$IV = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
$PBKDF2 = New-Object Security.Cryptography.Rfc2898DeriveBytes($password_bytes,$salt_bytes,$iteration) | |
$PBKDF2_AES256_key = $PBKDF2.GetBytes(32) | |
$PBKDF2_AES128_key = $PBKDF2_AES256_key[0..15] | |
$PBKDF2_AES256_key_string = ([System.BitConverter]::ToString($PBKDF2_AES256_key)) -replace "-","" | |
$PBKDF2_AES128_key_string = ([System.BitConverter]::ToString($PBKDF2_AES128_key)) -replace "-","" | |
Write-Verbose "PBKDF2 AES128 Key: $PBKDF2_AES128_key_string" | |
Write-Verbose "PBKDF2 AES256 Key: $PBKDF2_AES256_key_string" | |
$AES = New-Object "System.Security.Cryptography.AesManaged" | |
$AES.Mode = [System.Security.Cryptography.CipherMode]::CBC | |
$AES.Padding = [System.Security.Cryptography.PaddingMode]::None | |
$AES.IV = $IV | |
# AES 256 | |
$AES.KeySize = 256 | |
$AES.Key = $PBKDF2_AES256_key | |
$AES_encryptor = $AES.CreateEncryptor() | |
$AES256_key_part_1 = $AES_encryptor.TransformFinalBlock($AES256_constant,0,$AES256_constant.Length) | |
$AES256_key_part_2 = $AES_encryptor.TransformFinalBlock($AES256_key_part_1,0,$AES256_key_part_1.Length) | |
$AES256_key = $AES256_key_part_1[0..15] + $AES256_key_part_2[0..15] | |
$AES256_key_string = ([System.BitConverter]::ToString($AES256_key)) -replace "-","" | |
# AES 128 | |
$AES.KeySize = 128 | |
$AES.Key = $PBKDF2_AES128_key | |
$AES_encryptor = $AES.CreateEncryptor() | |
$AES128_key = $AES_encryptor.TransformFinalBlock($AES128_constant,0,$AES128_constant.Length) | |
$AES128_key_string = ([System.BitConverter]::ToString($AES128_key)) -replace "-","" | |
switch($OutputType) | |
{ | |
'AES' | |
{ | |
Write-Output "AES128 Key: $AES128_key_string" | |
Write-Output "AES256 Key: $AES256_key_string" | |
} | |
'AES128' | |
{ | |
Write-Output "$AES128_key_string" | |
} | |
'AES256' | |
{ | |
Write-Output "$AES256_key_string" | |
} | |
'AES128ByteArray' | |
{ | |
Write-Output $AES128_key | |
} | |
'AES256ByteArray' | |
{ | |
Write-Output $AES256_key | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment