From dd437e494d0c7940ed69f864d959c30553e113b3 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Sun, 6 Apr 2025 18:27:16 -0400 Subject: [PATCH 1/7] Create encode6.ps1 Ported from Python to PowerShell --- powershell/encode6.ps1 | 134 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 powershell/encode6.ps1 diff --git a/powershell/encode6.ps1 b/powershell/encode6.ps1 new file mode 100644 index 0000000..c3f0938 --- /dev/null +++ b/powershell/encode6.ps1 @@ -0,0 +1,134 @@ +# Based on https://github.com/CiscoDevNet/Type-6-Password-Encode/blob/main/encode6.py +# Which was: "Copyright (c) 2018 Cisco Systems. All rights reserved." + +$TYPE6_SALT_LEN = 8 +$TYPE6_MAC_LEN = 4 +$NO_PAD = [Security.Cryptography.PaddingMode]::None + +function base41_decode($three_symbols) { + if($three_symbols.Length -ne 3) { throw "Three Symbols Length Must Be 3!" } + $INT_CAP_A = [int]'A'[0] # Int Value of Character (A) + $x = [int]$three_symbols[0] - $INT_CAP_A + $y = [int]$three_symbols[1] - $INT_CAP_A + $z = [int]$three_symbols[2] - $INT_CAP_A + [uint16]$num16 = ($x * 41 * 41) + ($y * 41) + $z # 16 bit Integer + [Byte[]]$two_bytes = [System.BitConverter]::GetBytes($num16) + if ([BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + return $two_bytes # [Byte[]] +} + +function base41_encode([Byte[]]$two_bytes) { + if($two_bytes.Length -ne 2) { throw "Two Bytes Length Must Be 2!"} + $b41_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_``abcdefghi" + if([System.BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + $number = [BitConverter]::ToUInt16($two_bytes,0) + $z = -1 # Below equivalent of z = number % 41 + $number = [Math]::DivRem($number,41,[ref]$z) # number //= 41 + $y = -1 # Below equivalent of y = number % 41 + $x = [Math]::DivRem($number,41,[ref]$y) # number //= 41 + return $b41_chars[$x] + $b41_chars[$y] + $b41_chars[$z] # [String] +} + +function b41_decode($encoded_string) { + if($encoded_string.Length % 3 -ne 0) { throw "Encoded String Length Must Be Divisible by 3!" } + $decoded_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($i=0; $i -lt $encoded_string.Length; $i += 3) { + $chunk = $encoded_string[$i..($i + 3-1)] + $decoded_bytes += base41_decode -three_symbols $chunk + } + # Adjust Last Index to Remove Padding + $last_index = $decoded_bytes.Length -1 - $(if ($decoded_bytes[-1] -eq 0) { 1 } else { 2 }) + return $decoded_bytes[0..$last_index] # [Byte[]] +} + +function b41_encode([Byte[]]$binary) { + $encoded_str = "" + for ($i=0; $i -lt $binary.Length; $i += 2) { + $val = $binary[$i..($i+2-1)] + if ($val.Length -eq 2) { + $encoded_str += base41_encode -two_bytes $val + } + } + $pad = if ($binary.Length % 2 -ne 0) { $binary[-1], [Byte]0 } else { [Byte[]](0,1) } + $encoded_str += base41_encode -two_bytes $pad + return $encoded_str +} + +function password_mac_verify($encrypted_keystring, $master_key <# str #>) { + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $mac = $a[($a.Length-$TYPE6_MAC_LEN)..($a.Length-1)] + + $calculated_mac = password_mac_generate -encrypted_key_bytes $encrypted_pw -master_key $master_key -salt $salt + if (-not [Linq.Enumerable]::SequenceEqual([Byte[]]$calculated_mac, [Byte[]]$mac)) { + throw "Password Validation failed" + } +} + +function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str #>, [Byte[]]$salt) { + $password = [Text.Encoding]::UTF8.GetBytes($master_key) + $password_md5_digest = [Security.Cryptography.MD5]::Create().ComputeHash($password) + $aes = [Security.Cryptography.AES]::Create() + $aes.KeySize = 128 + $aes.Key = $password_md5_digest + $auth_key = $aes.EncryptEcb($salt + [Byte[]](0,0,0,0,0,0,0,0),$NO_PAD) + $hmaccer = [Security.Cryptography.HMACSHA1]::new() + $hmaccer.Key = $auth_key + $hash_bytes = $hmaccer.ComputeHash($encrypted_key_bytes) + return $hash_bytes[0..($TYPE6_MAC_LEN-1)] # Truncate to TYPE6_MAC_LEN +} + +function transform_bytes($in_bytes, $salt_bytes, $key_str) { + $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $aes = [Security.Cryptography.AES]::Create() + $aes.KeySize = 128 + $aes.Key = [Security.Cryptography.MD5]::Create().ComputeHash($key_bytes) + $aes.Key = $aes.EncryptEcb($salt_bytes + [Byte[]](0,0,0,0,0,0,0,1), $NO_PAD) + $out_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($x=0; $x -lt $in_bytes.Length; ++$x) { + $x_mod_16 = -1 # get by reference below + $x_div_16 = [Math]::DivRem($x,16,[ref]$x_mod_16) + if ($x_mod_16 -eq 0) { # New Key for every block size + $block_key = [Byte[]]::new(16) # Sixteen Zero Bytes (128 bits) + $block_key[3] = $x_div_16 # x // 16 + $block_key = $aes.EncryptEcb($block_key,$NO_PAD) + } + $x_byte = $in_bytes[$x] + $out_bytes += $x_byte -bxor $block_key[$x_mod_16] + } + return $out_bytes +} + +function encrypt_type_6_password([string]$cleartext_pw, [string]$master_key) { + $salt = [Byte[]]::new($TYPE6_SALT_LEN) + [Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($salt) + $clear_bytes = [Text.Encoding]::UTF8.GetBytes($cleartext_pw) + $out_bytes = transform_bytes -in_bytes $clear_bytes -salt_bytes $salt -key_str $master_key + $mac = password_mac_generate -encrypted_key_bytes $out_bytes -master_key $master_key -salt $salt + return b41_encode -binary ($salt + $out_bytes + $mac) # [String] +} + +function decrypt_type_6_password([string]$encrypted_keystring, [string]$master_key) { + password_mac_verify -encrypted_keystring $encrypted_keystring -master_key $master_key + # The encrypted_keystring is base41(SALT + Encrypted Key + MAC) + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $out_bytes = transform_bytes -in_bytes $encrypted_pw -salt_bytes $salt -key_str $master_key + return [Text.Encoding]::UTF8.GetString($out_bytes).TrimEnd([char]0) +} + +###### Example usage ###### + +# This was a password (Cisco123) generated on a router with the master_key also set to Cisco123 +$enc_pass = "fe_a``iJYE\DZYJhDhTP[``MYaTgRH_MAAB" +$master_key = "Cisco123" +$decrypted_pass = decrypt_type_6_password -master_key $master_key -encrypted_keystring $enc_pass +Write-Host "$enc_pass decrypts to '$decrypted_pass'" + +# Test generating and decrypting +$password_to_be_encrypted = "1234567890123456ABCDabcd" # "ABCD" +$encrypted_password = encrypt_type_6_password -cleartext_pw $password_to_be_encrypted -master_key $master_key +$decrypted_generated_password = decrypt_type_6_password -encrypted_keystring $encrypted_password -master_key $master_key +Write-Host "'$password_to_be_encrypted' encrypts to '$encrypted_password' decrypts to '$decrypted_generated_password'" From 20448122ddd79d9673fa5dfcaa8251d3153128f9 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Mon, 7 Apr 2025 13:28:47 -0400 Subject: [PATCH 2/7] Update and rename encode6.ps1 to encode6_dotnet6.ps1 EncryptECB requires .NET 6+ --- powershell/{encode6.ps1 => encode6_dotnet6.ps1} | 1 + 1 file changed, 1 insertion(+) rename powershell/{encode6.ps1 => encode6_dotnet6.ps1} (99%) diff --git a/powershell/encode6.ps1 b/powershell/encode6_dotnet6.ps1 similarity index 99% rename from powershell/encode6.ps1 rename to powershell/encode6_dotnet6.ps1 index c3f0938..814f7d3 100644 --- a/powershell/encode6.ps1 +++ b/powershell/encode6_dotnet6.ps1 @@ -1,5 +1,6 @@ # Based on https://github.com/CiscoDevNet/Type-6-Password-Encode/blob/main/encode6.py # Which was: "Copyright (c) 2018 Cisco Systems. All rights reserved." +# EncryptECB requires .NET 6+. $TYPE6_SALT_LEN = 8 $TYPE6_MAC_LEN = 4 From 81aed383df6ebfa5e483067c2775b296a14bf767 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Mon, 7 Apr 2025 13:29:56 -0400 Subject: [PATCH 3/7] Add encode6.ps1 with older .NET compatibility. Add encode6.ps1 with older .NET compatibility. --- powershell/encode6.ps1 | 137 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 powershell/encode6.ps1 diff --git a/powershell/encode6.ps1 b/powershell/encode6.ps1 new file mode 100644 index 0000000..0adc1b4 --- /dev/null +++ b/powershell/encode6.ps1 @@ -0,0 +1,137 @@ +# Based on https://github.com/CiscoDevNet/Type-6-Password-Encode/blob/main/encode6.py +# Which was: "Copyright (c) 2018 Cisco Systems. All rights reserved." +# EncryptECB requires .NET 6+. Using CreateEncryptor + Transform*Block Instead! + +$TYPE6_SALT_LEN = 8 +$TYPE6_MAC_LEN = 4 + +function Get-AesEncryptor([Byte[]]$key_bytes) { + $aes = [Security.Cryptography.AES]::Create() + $aes.KeySize = 128 + $aes.Mode = [Security.Cryptography.CipherMode]::ECB + $aes.Padding = [Security.Cryptography.PaddingMode]::None + return $aes.CreateEncryptor($key_bytes,$null) +} + +function base41_decode($three_symbols) { + if($three_symbols.Length -ne 3) { throw "Three Symbols Length Must Be 3!" } + $INT_CAP_A = [int]'A'[0] # Int Value of Character (A) + $x = [int]$three_symbols[0] - $INT_CAP_A + $y = [int]$three_symbols[1] - $INT_CAP_A + $z = [int]$three_symbols[2] - $INT_CAP_A + [uint16]$num16 = ($x * 41 * 41) + ($y * 41) + $z # 16 bit Integer + [Byte[]]$two_bytes = [System.BitConverter]::GetBytes($num16) + if ([BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + return $two_bytes # [Byte[]] +} + +function base41_encode([Byte[]]$two_bytes) { + if($two_bytes.Length -ne 2) { throw "Two Bytes Length Must Be 2!"} + $b41_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_``abcdefghi" + if([System.BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + $number = [BitConverter]::ToUInt16($two_bytes,0) + $z = -1 # Below equivalent of z = number % 41 + $number = [Math]::DivRem($number,41,[ref]$z) # number //= 41 + $y = -1 # Below equivalent of y = number % 41 + $x = [Math]::DivRem($number,41,[ref]$y) # number //= 41 + return $b41_chars[$x] + $b41_chars[$y] + $b41_chars[$z] # [String] +} + +function b41_decode($encoded_string) { + if($encoded_string.Length % 3 -ne 0) { throw "Encoded String Length Must Be Divisible by 3!" } + $decoded_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($i=0; $i -lt $encoded_string.Length; $i += 3) { + $chunk = $encoded_string[$i..($i + 3-1)] + $decoded_bytes += base41_decode -three_symbols $chunk + } + # Adjust Last Index to Remove Padding + $last_index = $decoded_bytes.Length -1 - $(if ($decoded_bytes[-1] -eq 0) { 1 } else { 2 }) + return $decoded_bytes[0..$last_index] # [Byte[]] +} + +function b41_encode([Byte[]]$binary) { + $encoded_str = "" + for ($i=0; $i -lt $binary.Length; $i += 2) { + $val = $binary[$i..($i+2-1)] + if ($val.Length -eq 2) { + $encoded_str += base41_encode -two_bytes $val + } + } + $pad = if ($binary.Length % 2 -ne 0) { $binary[-1], [Byte]0 } else { [Byte[]](0,1) } + $encoded_str += base41_encode -two_bytes $pad + return $encoded_str +} + +function password_mac_verify($encrypted_keystring, $master_key <# str #>) { + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $mac = $a[($a.Length-$TYPE6_MAC_LEN)..($a.Length-1)] + + $calculated_mac = password_mac_generate -encrypted_key_bytes $encrypted_pw -master_key $master_key -salt $salt + if (-not [Linq.Enumerable]::SequenceEqual([Byte[]]$calculated_mac, [Byte[]]$mac)) { + throw "Password Validation failed" + } +} + +function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str #>, [Byte[]]$salt) { + $password = [Text.Encoding]::UTF8.GetBytes($master_key) + $password_md5_digest = [Security.Cryptography.MD5]::Create().ComputeHash($password) + $auth_key = (Get-AesEncryptor $password_md5_digest).TransformFinalBlock($salt + [Byte[]](0,0,0,0,0,0,0,0),0,16) + $hmaccer = [Security.Cryptography.HMACSHA1]::new() + $hmaccer.Key = $auth_key + $hash_bytes = $hmaccer.ComputeHash($encrypted_key_bytes) + return $hash_bytes[0..($TYPE6_MAC_LEN-1)] # Truncate to TYPE6_MAC_LEN +} + +function transform_bytes($in_bytes, $salt_bytes, $key_str) { + $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $aes = Get-AesEncryptor ([Security.Cryptography.MD5]::Create().ComputeHash($key_bytes)) + $aes = Get-AesEncryptor $aes.TransformFinalBlock($salt_bytes + [Byte[]](0,0,0,0,0,0,0,1),0,16) + $out_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($x=0; $x -lt $in_bytes.Length; ++$x) { + $x_mod_16 = -1 # get by reference below + $x_div_16 = [Math]::DivRem($x,16,[ref]$x_mod_16) + if ($x_mod_16 -eq 0) { # New Key for every block size + $block_key = [Byte[]]::new(16) # Sixteen Zero Bytes (128 bits) + $block_key[3] = $x_div_16 # x // 16 + $block_key = $aes.TransformFinalBlock($block_key,0,16) + } + $x_byte = $in_bytes[$x] + $out_bytes += $x_byte -bxor $block_key[$x_mod_16] + } + return $out_bytes +} + +function encrypt_type_6_password([string]$cleartext_pw, [string]$master_key) { + $salt = [Byte[]]::new($TYPE6_SALT_LEN) + [Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($salt) + $clear_bytes = [Text.Encoding]::UTF8.GetBytes($cleartext_pw) + $out_bytes = transform_bytes -in_bytes $clear_bytes -salt_bytes $salt -key_str $master_key + $mac = password_mac_generate -encrypted_key_bytes $out_bytes -master_key $master_key -salt $salt + return b41_encode -binary ($salt + $out_bytes + $mac) # [String] +} + +function decrypt_type_6_password([string]$encrypted_keystring, [string]$master_key) { + password_mac_verify -encrypted_keystring $encrypted_keystring -master_key $master_key + # The encrypted_keystring is base41(SALT + Encrypted Key + MAC) + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $out_bytes = transform_bytes -in_bytes $encrypted_pw -salt_bytes $salt -key_str $master_key + return [Text.Encoding]::UTF8.GetString($out_bytes).TrimEnd([char]0) +} + +###### Example usage ###### + +# This was a password (Cisco123) generated on a router with the master_key also set to Cisco123 +$enc_pass = "fe_a``iJYE\DZYJhDhTP[``MYaTgRH_MAAB" +$master_key = "Cisco123" +$decrypted_pass = decrypt_type_6_password -master_key $master_key -encrypted_keystring $enc_pass +Write-Host "$enc_pass decrypts to '$decrypted_pass'" + +# Test generating and decrypting +$password_to_be_encrypted = "1234567890123456ABCDabcd" # "ABCD" +$encrypted_password = encrypt_type_6_password -cleartext_pw $password_to_be_encrypted -master_key $master_key +$decrypted_generated_password = decrypt_type_6_password -encrypted_keystring $encrypted_password -master_key $master_key +Write-Host "'$password_to_be_encrypted' encrypts to '$encrypted_password' decrypts to '$decrypted_generated_password'" From 80eb0e9494ed1e92e8b426e4066afb894359c793 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Mon, 7 Apr 2025 22:17:59 -0400 Subject: [PATCH 4/7] Add encode6_git_bash.ps1 for .NET MD5 issue Add encode6_git_bash.ps1 for .NET MD5 issue. FIPS compliance settings in Windows might block MD5 within .NET. This version uses Git Bash with OpenSSL for MD5 hashing. --- powershell/encode6_git_bash.ps1 | 146 ++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 powershell/encode6_git_bash.ps1 diff --git a/powershell/encode6_git_bash.ps1 b/powershell/encode6_git_bash.ps1 new file mode 100644 index 0000000..cc57e39 --- /dev/null +++ b/powershell/encode6_git_bash.ps1 @@ -0,0 +1,146 @@ +# Based on https://github.com/CiscoDevNet/Type-6-Password-Encode/blob/main/encode6.py +# Which was: "Copyright (c) 2018 Cisco Systems. All rights reserved." +# For compatibility with older .NET uses CreateEncryptor + Transform*Block. +# Dependency: Git Bash (use openssl to workaround issue if .NET MD5 fails) + +$TYPE6_SALT_LEN = 8 +$TYPE6_MAC_LEN = 4 + +function Get-MD5Hash([Byte[]]$in_bytes) { + $bash = 'C:\Program Files\Git\bin\bash.exe' + $b64_str = [Convert]::ToBase64String($in_bytes) + $md5_str = $b64_str | & $bash -c "tr -d '\r' | base64 -d | openssl dgst -md5 -c" + $md5_bytes = ForEach($str in ((-split $md5_str)[1] -split ':')) {[Convert]::ToByte($str,16)} + return $md5_bytes +} + +function Get-AesEncryptor([Byte[]]$key_bytes) { + $aes = [Security.Cryptography.AES]::Create() + $aes.KeySize = 128 + $aes.Mode = [Security.Cryptography.CipherMode]::ECB + $aes.Padding = [Security.Cryptography.PaddingMode]::None + return $aes.CreateEncryptor($key_bytes,$null) +} + +function base41_decode($three_symbols) { + if($three_symbols.Length -ne 3) { throw "Three Symbols Length Must Be 3!" } + $INT_CAP_A = [int]'A'[0] # Int Value of Character (A) + $x = [int]$three_symbols[0] - $INT_CAP_A + $y = [int]$three_symbols[1] - $INT_CAP_A + $z = [int]$three_symbols[2] - $INT_CAP_A + [uint16]$num16 = ($x * 41 * 41) + ($y * 41) + $z # 16 bit Integer + [Byte[]]$two_bytes = [System.BitConverter]::GetBytes($num16) + if ([BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + return $two_bytes # [Byte[]] +} + +function base41_encode([Byte[]]$two_bytes) { + if($two_bytes.Length -ne 2) { throw "Two Bytes Length Must Be 2!"} + $b41_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_``abcdefghi" + if([System.BitConverter]::IsLittleEndian) { [Array]::Reverse($two_bytes) } + $number = [BitConverter]::ToUInt16($two_bytes,0) + $z = -1 # Below equivalent of z = number % 41 + $number = [Math]::DivRem($number,41,[ref]$z) # number //= 41 + $y = -1 # Below equivalent of y = number % 41 + $x = [Math]::DivRem($number,41,[ref]$y) # number //= 41 + return $b41_chars[$x] + $b41_chars[$y] + $b41_chars[$z] # [String] +} + +function b41_decode($encoded_string) { + if($encoded_string.Length % 3 -ne 0) { throw "Encoded String Length Must Be Divisible by 3!" } + $decoded_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($i=0; $i -lt $encoded_string.Length; $i += 3) { + $chunk = $encoded_string[$i..($i + 3-1)] + $decoded_bytes += base41_decode -three_symbols $chunk + } + # Adjust Last Index to Remove Padding + $last_index = $decoded_bytes.Length -1 - $(if ($decoded_bytes[-1] -eq 0) { 1 } else { 2 }) + return $decoded_bytes[0..$last_index] # [Byte[]] +} + +function b41_encode([Byte[]]$binary) { + $encoded_str = "" + for ($i=0; $i -lt $binary.Length; $i += 2) { + $val = $binary[$i..($i+2-1)] + if ($val.Length -eq 2) { + $encoded_str += base41_encode -two_bytes $val + } + } + $pad = if ($binary.Length % 2 -ne 0) { $binary[-1], [Byte]0 } else { [Byte[]](0,1) } + $encoded_str += base41_encode -two_bytes $pad + return $encoded_str +} + +function password_mac_verify($encrypted_keystring, $master_key <# str #>) { + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $mac = $a[($a.Length-$TYPE6_MAC_LEN)..($a.Length-1)] + + $calculated_mac = password_mac_generate -encrypted_key_bytes $encrypted_pw -master_key $master_key -salt $salt + if (-not [Linq.Enumerable]::SequenceEqual([Byte[]]$calculated_mac, [Byte[]]$mac)) { + throw "Password Validation failed" + } +} + +function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str #>, [Byte[]]$salt) { + $password = [Text.Encoding]::UTF8.GetBytes($master_key) + $password_md5_digest = Get-MD5Hash $password + $auth_key = (Get-AesEncryptor $password_md5_digest).TransformFinalBlock($salt + [Byte[]](0,0,0,0,0,0,0,0),0,16) + $hmaccer = [Security.Cryptography.HMACSHA1]::new() + $hmaccer.Key = $auth_key + $hash_bytes = $hmaccer.ComputeHash($encrypted_key_bytes) + return $hash_bytes[0..($TYPE6_MAC_LEN-1)] # Truncate to TYPE6_MAC_LEN +} + +function transform_bytes($in_bytes, $salt_bytes, $key_str) { + $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $aes = Get-AesEncryptor (Get-MD5Hash $key_bytes) + $aes = Get-AesEncryptor $aes.TransformFinalBlock($salt_bytes + [Byte[]](0,0,0,0,0,0,0,1),0,16) + $out_bytes = [Byte[]]::new(0) # Empty Byte Array + for ($x=0; $x -lt $in_bytes.Length; ++$x) { + $x_mod_16 = -1 # get by reference below + $x_div_16 = [Math]::DivRem($x,16,[ref]$x_mod_16) + if ($x_mod_16 -eq 0) { # New Key for every block size + $block_key = [Byte[]]::new(16) # Sixteen Zero Bytes (128 bits) + $block_key[3] = $x_div_16 # x // 16 + $block_key = $aes.TransformFinalBlock($block_key,0,16) + } + $x_byte = $in_bytes[$x] + $out_bytes += $x_byte -bxor $block_key[$x_mod_16] + } + return $out_bytes +} + +function encrypt_type_6_password([string]$cleartext_pw, [string]$master_key) { + $salt = [Byte[]]::new($TYPE6_SALT_LEN) + [Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($salt) + $clear_bytes = [Text.Encoding]::UTF8.GetBytes($cleartext_pw) + $out_bytes = transform_bytes -in_bytes $clear_bytes -salt_bytes $salt -key_str $master_key + $mac = password_mac_generate -encrypted_key_bytes $out_bytes -master_key $master_key -salt $salt + return b41_encode -binary ($salt + $out_bytes + $mac) # [String] +} + +function decrypt_type_6_password([string]$encrypted_keystring, [string]$master_key) { + password_mac_verify -encrypted_keystring $encrypted_keystring -master_key $master_key + # The encrypted_keystring is base41(SALT + Encrypted Key + MAC) + $a = b41_decode $encrypted_keystring + $salt = $a[0..($TYPE6_SALT_LEN-1)] + $encrypted_pw = $a[$TYPE6_SALT_LEN..($a.Length-1-$TYPE6_MAC_LEN)] + $out_bytes = transform_bytes -in_bytes $encrypted_pw -salt_bytes $salt -key_str $master_key + return [Text.Encoding]::UTF8.GetString($out_bytes).TrimEnd([char]0) +} + +###### Example usage ###### + +# This was a password (Cisco123) generated on a router with the master_key also set to Cisco123 +$enc_pass = "fe_a``iJYE\DZYJhDhTP[``MYaTgRH_MAAB" +$master_key = "Cisco123" +$decrypted_pass = decrypt_type_6_password -master_key $master_key -encrypted_keystring $enc_pass +Write-Host "$enc_pass decrypts to '$decrypted_pass'" + +# Test generating and decrypting +$password_to_be_encrypted = "1234567890123456ABCDabcd" # "ABCD" +$encrypted_password = encrypt_type_6_password -cleartext_pw $password_to_be_encrypted -master_key $master_key +$decrypted_generated_password = decrypt_type_6_password -encrypted_keystring $encrypted_password -master_key $master_key +Write-Host "'$password_to_be_encrypted' encrypts to '$encrypted_password' decrypts to '$decrypted_generated_password'" From c9b9932582b07d5573ce6edbe4e9b2904b5755c7 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Mon, 7 Apr 2025 22:27:09 -0400 Subject: [PATCH 5/7] Update encode6_git_bash.ps1 variable name agreement. --- powershell/encode6_git_bash.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/encode6_git_bash.ps1 b/powershell/encode6_git_bash.ps1 index cc57e39..d6a5ffa 100644 --- a/powershell/encode6_git_bash.ps1 +++ b/powershell/encode6_git_bash.ps1 @@ -94,7 +94,7 @@ function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str } function transform_bytes($in_bytes, $salt_bytes, $key_str) { - $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $key_bytes = [Text.Encoding]::UTF8.GetBytes($key_str) $aes = Get-AesEncryptor (Get-MD5Hash $key_bytes) $aes = Get-AesEncryptor $aes.TransformFinalBlock($salt_bytes + [Byte[]](0,0,0,0,0,0,0,1),0,16) $out_bytes = [Byte[]]::new(0) # Empty Byte Array From 1916be2cf8dc588804b483be8152624b51e8a5f6 Mon Sep 17 00:00:00 2001 From: notesbytom Date: Mon, 7 Apr 2025 22:28:43 -0400 Subject: [PATCH 6/7] Update encode6_dotnet6.ps1 variable name agreement. --- powershell/encode6_dotnet6.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/encode6_dotnet6.ps1 b/powershell/encode6_dotnet6.ps1 index 814f7d3..1e94a74 100644 --- a/powershell/encode6_dotnet6.ps1 +++ b/powershell/encode6_dotnet6.ps1 @@ -81,7 +81,7 @@ function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str } function transform_bytes($in_bytes, $salt_bytes, $key_str) { - $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $key_bytes = [Text.Encoding]::UTF8.GetBytes($key_str) $aes = [Security.Cryptography.AES]::Create() $aes.KeySize = 128 $aes.Key = [Security.Cryptography.MD5]::Create().ComputeHash($key_bytes) From 571a82de39f09be285de6c28a621e5ef4530f0cb Mon Sep 17 00:00:00 2001 From: notesbytom Date: Tue, 8 Apr 2025 20:22:03 -0400 Subject: [PATCH 7/7] Update encode6.ps1 variable name agreement --- powershell/encode6.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/encode6.ps1 b/powershell/encode6.ps1 index 0adc1b4..e401d0e 100644 --- a/powershell/encode6.ps1 +++ b/powershell/encode6.ps1 @@ -85,7 +85,7 @@ function password_mac_generate([Byte[]]$encrypted_key_bytes, $master_key <# str } function transform_bytes($in_bytes, $salt_bytes, $key_str) { - $key_bytes = [Text.Encoding]::UTF8.GetBytes($master_key) + $key_bytes = [Text.Encoding]::UTF8.GetBytes($key_str) $aes = Get-AesEncryptor ([Security.Cryptography.MD5]::Create().ComputeHash($key_bytes)) $aes = Get-AesEncryptor $aes.TransformFinalBlock($salt_bytes + [Byte[]](0,0,0,0,0,0,0,1),0,16) $out_bytes = [Byte[]]::new(0) # Empty Byte Array