Skip to content

Instantly share code, notes, and snippets.

@Kevin-Robertson
Last active August 20, 2024 19:36
Show Gist options
  • Save Kevin-Robertson/9e0f8bfdbf4c1e694e6ff4197f0a4372 to your computer and use it in GitHub Desktop.
Save Kevin-Robertson/9e0f8bfdbf4c1e694e6ff4197f0a4372 to your computer and use it in GitHub Desktop.
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