mirror of
https://github.com/itm4n/PrivescCheck
synced 2026-06-08 14:54:28 +00:00
601 lines
22 KiB
PowerShell
601 lines
22 KiB
PowerShell
function Invoke-Build {
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("PrivescCheck")]
|
|
[String] $Name,
|
|
|
|
[Switch] $NoNewSeed
|
|
)
|
|
|
|
begin {
|
|
|
|
$SanityCheck = $true
|
|
|
|
if (-not (Test-Path -Path "build")) {
|
|
Write-Message -Type Error "Build folder not found."
|
|
$SanityCheck = $false
|
|
}
|
|
|
|
$BuildProfilesJson = Get-FileContent -Type "build" -FileName "BuildProfiles.json" | Out-String | ConvertFrom-Json
|
|
if ($null -eq $BuildProfilesJson) {
|
|
Write-Message -Type Error "Failed to read build profile file."
|
|
$SanityCheck = $false
|
|
}
|
|
|
|
$RootPath = Split-Path -Path (Split-Path -Path $PSCommandPath -Parent) -Parent
|
|
|
|
$WordList = Get-FileContent -Type "data" -FileName "WordList.txt" | Where-Object { -not [String]::IsNullOrEmpty($_) }
|
|
if ($null -eq $WordList) {
|
|
Write-Message -Type Error "Failed to retrieve word list."
|
|
$SanityCheck = $false
|
|
}
|
|
|
|
if ($NoNewSeed) {
|
|
$Seed = Get-FileContent -Type "build" -FileName "Seed.txt" -ErrorAction SilentlyContinue | Out-String
|
|
if ([String]::IsNullOrEmpty($Seed)) {
|
|
Write-Message -Type Error -Message "Failed to read seed from file."
|
|
$SanityCheck = $false
|
|
}
|
|
else {
|
|
$Seed = [Int32]::Parse($Seed)
|
|
Write-Message -Message "Using seed: $($Seed)"
|
|
}
|
|
}
|
|
else {
|
|
$Seed = Get-RandomInt
|
|
Write-Message -Message "Generated seed: $($Seed)"
|
|
Set-FileContent -Type "build" -FileName "Seed.txt" -Content "$($Seed)"
|
|
}
|
|
|
|
# https://learn.microsoft.com/en-us/dotnet/api/system.platformid
|
|
$CurrentPlatform = [System.Environment]::OSVersion.Platform
|
|
$TestModuleImport = $CurrentPlatform -eq "Win32NT"
|
|
if ($TestModuleImport -eq $false) {
|
|
Write-Message -Type Warning -Message "Unsupported platform for module import testing: $($CurrentPlatform)"
|
|
}
|
|
|
|
$EncryptionKey = New-RandomByteArray -Size 32
|
|
}
|
|
|
|
process {
|
|
|
|
if (-not $SanityCheck) { return }
|
|
|
|
$BuildProfileObject = $BuildProfilesJson.Profiles | Where-Object { $_.Name -eq $Name }
|
|
if ($null -eq $BuildProfileObject) {
|
|
Write-Message -Type Error -Message "No build profile found for name: $($Name)"
|
|
return
|
|
}
|
|
|
|
$ScriptFilename = "$($BuildProfileObject.Name).ps1"
|
|
$ScriptPath = Join-Path -Path $RootPath -ChildPath "dist\$($ScriptFilename)"
|
|
$ScriptContent = ""
|
|
$ErrorCount = 0
|
|
$Modules = @()
|
|
|
|
Write-Message "Building script '$($ScriptFilename)'..."
|
|
|
|
foreach ($IncludeId in $BuildProfileObject.Includes) {
|
|
|
|
$IncludeObject = $BuildProfilesJson.Includes | Where-Object { $_.Id -eq $IncludeId }
|
|
if ($null -eq $IncludeObject) {
|
|
Write-Message -Type Error -Message "No include found for ID: $($IncludeId)"
|
|
return
|
|
}
|
|
|
|
$CurrentSeed = $Seed
|
|
|
|
foreach ($FileId in $IncludeObject.Files) {
|
|
|
|
$FileObject = $BuildProfilesJson.Files | Where-Object { $_.Id -eq $FileId }
|
|
if ($null -eq $FileObject) {
|
|
Write-Message -Type Error -Message "No file found for ID: $($FileId)"
|
|
return
|
|
}
|
|
|
|
$ModulePath = Join-Path -Path $RootPath -ChildPath $FileObject.Path
|
|
$ModuleItem = Get-Item -Path $ModulePath -ErrorAction SilentlyContinue
|
|
if ($null -eq $ModuleItem) {
|
|
Write-Message -Type Error "Failed to open file '$($ModulePath)'."
|
|
return
|
|
}
|
|
|
|
$ModuleFilename = $ModuleItem.Name
|
|
|
|
# Pick a random name for the current module
|
|
$RandomName = [String] (Get-Random -InputObject $WordList -Count 1 -SetSeed $CurrentSeed)
|
|
$WordList = $WordList | Where-Object { $_ -ne $RandomName }
|
|
$CurrentSeed = Get-RandomInt -Seed $CurrentSeed
|
|
|
|
$ModuleName = $RandomName.ToLower()
|
|
$ModuleName = ([regex] $ModuleName[0].ToString()).Replace($ModuleName, $ModuleName[0].ToString().ToUpper(), 1)
|
|
|
|
$Modules += $ModuleName
|
|
|
|
$ScriptBlock = Get-Content -Path $ModulePath | Out-String
|
|
|
|
foreach ($MatchAndReplace in $FileObject.MatchAndReplace) {
|
|
|
|
$DataToReplace = Get-FileContent -Type "data" -FileName $MatchAndReplace.DataFile | Out-String
|
|
if ($null -eq $DataToReplace) {
|
|
Write-Message -Type Error "Failed to retrieve data file content: $($MatchAndReplace.DataFile)"
|
|
return
|
|
}
|
|
|
|
$DataToReplace = ConvertTo-EmbeddedTextBlob -Text $DataToReplace
|
|
if ($null -eq $DataToReplace) {
|
|
Write-Message -Type Error "Failed to encode data file content: $($MatchAndReplace.DataFile)"
|
|
return
|
|
}
|
|
|
|
$ScriptBlock = $ScriptBlock -replace "{{$($MatchAndReplace.Tag)}}", $DataToReplace
|
|
|
|
Write-Message "Embedded data file '$($MatchAndReplace.DataFile)' into '$($ModuleFilename)'"
|
|
}
|
|
|
|
# Is the script block detected by AMSI after stripping the comments?
|
|
# Note: if the script block is caught by AMSI, an exception is triggered, so we go
|
|
# directly to the "catch" block. Otherwise, it means that the module was successfully
|
|
# loaded.
|
|
$ScriptBlock = Remove-CommentFromScriptBlock -ScriptBlock $ScriptBlock
|
|
|
|
if ($TestModuleImport) {
|
|
try {
|
|
& $ExecutionContext.InvokeCommand.NewScriptBlock($ScriptBlock)
|
|
Write-Message "File '$($ModuleFilename)' (name: '$($ModuleName)') was loaded successfully."
|
|
}
|
|
catch {
|
|
if ($_.FullyQualifiedErrorId -like "ScriptContainedMaliciousContent*") {
|
|
# Exception triggered because of AMSI.
|
|
$ErrorCount += 1
|
|
Write-Message -Type Error "Malicious content detected in module '$($ModuleFilename)' (name: '$($ModuleName)'): $($_.Exception.Message.Trim())"
|
|
}
|
|
elseif ($_.FullyQualifiedErrorId -eq "CommandNotFoundException") {
|
|
# Exception triggered because a non-existing command is invoked. This is expected
|
|
# in certain files.
|
|
if (@("New-Enum", "New-StructureField", "New-Function") -notcontains $_.TargetObject) {
|
|
$ErrorCount += 1
|
|
Write-Message -Type Error "Unexpected error while importing module '$($ModuleFilename)' (name: '$($ModuleName)'): $($_.Exception.Message.Trim())"
|
|
}
|
|
else {
|
|
Write-Message "File '$($ModuleFilename)' (name: '$($ModuleName)') was not loaded successfully (expected)."
|
|
}
|
|
}
|
|
else {
|
|
# Other unexpected exception
|
|
$ErrorCount += 1
|
|
Write-Message -Type Error "Unexpected error while importing module '$($ModuleFilename)' (name: '$($ModuleName)'): $($_.Exception.Message.Trim())"
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($FileObject.Compression -eq $true) {
|
|
$ScriptEncoded = ConvertTo-Gzip -InputText $ScriptBlock
|
|
}
|
|
else {
|
|
$ScriptEncoded = [Text.Encoding]::UTF8.GetBytes($ScriptBlock)
|
|
}
|
|
|
|
$ScriptEncoded = ConvertTo-AesEncrypted -InputBuffer $ScriptEncoded -Key $EncryptionKey
|
|
$ScriptEncoded = [System.Convert]::ToBase64String($ScriptEncoded)
|
|
$ScriptContent += "`$$($ModuleName) = `"$($ScriptEncoded)`"`r`n"
|
|
}
|
|
}
|
|
|
|
if ($ErrorCount -eq 0) {
|
|
Write-Message -Type Success "Build successful, writing result to file '$($ScriptPath)'..."
|
|
$ScriptContent += "`r`n$(Get-ScriptLoader -Modules $Modules -EncodedKey ([System.Convert]::ToBase64String($EncryptionKey)))"
|
|
$ScriptContent | Out-File -FilePath $ScriptPath -Encoding ascii
|
|
|
|
if ($BuildProfileName -eq "PrivescCheck") {
|
|
|
|
# If the output script is PrivescCheck.ps1, copy the result at the root of the
|
|
# project as well.
|
|
$ScriptPath = Join-Path -Path $RootPath -ChildPath "$($ScriptFilename)"
|
|
Write-Message -Type Info "Copying result to file '$($ScriptPath)'..."
|
|
$ScriptContent | Out-File -FilePath $ScriptPath -Encoding ascii
|
|
}
|
|
}
|
|
else {
|
|
Write-Message -Type Error "Build failed, check the build logs for more information."
|
|
}
|
|
}
|
|
}
|
|
|
|
function Write-Message {
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Position = 0, Mandatory = $true)]
|
|
[String] $Message,
|
|
[ValidateSet("Success", "Info", "Warning", "Error")]
|
|
[String] $Type
|
|
)
|
|
|
|
$Symbol = "[*]"; $Color = "Blue"
|
|
|
|
switch ($Type) {
|
|
"Success" {
|
|
$Symbol = "[+]"; $Color = "Green"
|
|
}
|
|
"Warning" {
|
|
$Symbol = "[!]"; $Color = "Yellow"
|
|
}
|
|
"Error" {
|
|
$Symbol = "[-]"; $Color = "Red"
|
|
}
|
|
}
|
|
|
|
Write-Host -NoNewline -ForegroundColor "$Color" "$($Symbol) "
|
|
Write-Host "$Message"
|
|
}
|
|
|
|
function Get-RandomInt {
|
|
|
|
[OutputType([Int32])]
|
|
[CmdletBinding()]
|
|
param (
|
|
[Int32] $Seed,
|
|
[Int32] $Min,
|
|
[Int32] $Max
|
|
)
|
|
|
|
if ($PSBoundParameters['Seed']) {
|
|
$Rand = New-Object -TypeName "System.Random" -ArgumentList $Seed
|
|
}
|
|
else {
|
|
$Rand = New-Object -TypeName "System.Random"
|
|
}
|
|
|
|
if ($PSBoundParameters['Min'] -and $PSBoundParameters['Max']) {
|
|
return $Rand.Next($Min, $Max)
|
|
}
|
|
|
|
if ($PSBoundParameters['Max']) {
|
|
return $Rand.Next($Max)
|
|
}
|
|
|
|
return $Rand.Next()
|
|
}
|
|
|
|
function Get-FilePath {
|
|
|
|
[OutputType([String])]
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("build", "data")]
|
|
[String] $Type,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $FileName
|
|
)
|
|
|
|
# The script path is 'C:\...\PrivescCheck\build\Build.ps1'
|
|
|
|
# Get the parent folder path: 'C:\...\PrivescCheck\build'
|
|
$RootFolderPath = Split-Path -Path $PSCommandPath -Parent
|
|
|
|
# Get the parent folder path: 'C:\...\PrivescCheck'
|
|
$RootFolderPath = Split-Path -Path $RootFolderPath -Parent
|
|
|
|
# Get the data folder path: 'C:\...\PrivescCheck\data'
|
|
$FilePath = Join-Path -Path $RootFolderPath -ChildPath $Type
|
|
|
|
# Get the data file path: 'C:\...\PrivescCheck\data\$FileName'
|
|
$FilePath = Join-Path -Path $FilePath -ChildPath $FileName
|
|
|
|
return $FilePath
|
|
}
|
|
|
|
function Get-FileContent {
|
|
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $Type,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $FileName
|
|
)
|
|
|
|
$FilePath = Get-FilePath -Type $Type -FileName $FileName
|
|
Get-Content -Path $FilePath -Encoding Ascii
|
|
}
|
|
|
|
function Set-FileContent {
|
|
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $Type,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $FileName,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[String] $Content
|
|
)
|
|
|
|
$FilePath = Get-FilePath -Type $Type -FileName $FileName
|
|
$Content | Set-Content -Path $FilePath -Encoding Ascii
|
|
}
|
|
|
|
function Get-LolDriver {
|
|
|
|
[CmdletBinding()]
|
|
param ()
|
|
|
|
$LolDriversUrl = "https://www.loldrivers.io/api/drivers.csv"
|
|
$LolDrivers = ""
|
|
try {
|
|
$LolDrivers = (New-Object Net.WebClient).DownloadString($LolDriversUrl)
|
|
}
|
|
catch {
|
|
Write-Message -Type Error -Message "Net.WebClient exception: $($_.Exception.Message)"
|
|
return
|
|
}
|
|
|
|
$LolDrivers = ConvertFrom-Csv -InputObject $LolDrivers
|
|
Write-Message -Type Success -Message "Successfully downloaded LOL driver list from $($LolDriversUrl) (count=$($LolDrivers.Count))"
|
|
|
|
$LolDriversVulnerable = $LolDrivers | Where-Object { $_.Category -like "*vulnerable*" }
|
|
Write-Message -Message "Filtered list on 'vulnerable' drivers (count=$($LolDriversVulnerable.Count))"
|
|
|
|
$LolDrivers = @()
|
|
$LolDriversVulnerable | ForEach-Object {
|
|
|
|
# Keep the UUID for future reference in the LOL drivers database.
|
|
$Result = New-Object -TypeName PSObject
|
|
$Result | Add-Member -MemberType "NoteProperty" -Name "Id" -Value $_.Id
|
|
|
|
# Extract all the valid hashes from the data
|
|
$HashesMd5 = [string[]] ($_.KnownVulnerableSamples_MD5 -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_.Length -eq 32 })
|
|
$HashesSha1 = [string[]] ($_.KnownVulnerableSamples_SHA1 -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_.Length -eq 40 })
|
|
$HashesSha256 = [string[]] ($_.KnownVulnerableSamples_SHA256 -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_.Length -eq 64 })
|
|
|
|
if (($HashesMd5.Count -eq 0) -and ($HashesSha1.Count -eq 0) -and ($HashesSha256.Count -eq 0)) {
|
|
Write-Message -Type Warning -Message "No hash found for entry with ID: $($_.Id)"
|
|
continue
|
|
}
|
|
|
|
# Find the hash list that has the most values
|
|
$HashesMax = (@($HashesMd5.Count, $HashesSha1.Count, $HashesSha256.Count) | Measure-Object -Maximum).Maximum
|
|
|
|
# Keep the hash list that has the most values, prioritize the shortest hashes
|
|
# to minimize the total space they will take in the final script.
|
|
if ($HashesMd5.Count -eq $HashesMax) {
|
|
$Result | Add-Member -MemberType "NoteProperty" -Name "Hash" -Value ($HashesMd5 -join ",")
|
|
}
|
|
elseif ($HashesSha1.Count -eq $HashesMax) {
|
|
$Result | Add-Member -MemberType "NoteProperty" -Name "Hash" -Value ($HashesSha1 -join ",")
|
|
}
|
|
elseif ($HashesSha256.Count -eq $HashesMax) {
|
|
$Result | Add-Member -MemberType "NoteProperty" -Name "Hash" -Value ($HashesSha256 -join ",")
|
|
}
|
|
|
|
$Result
|
|
}
|
|
}
|
|
|
|
function Update-LolDriverList {
|
|
|
|
[CmdletBinding()]
|
|
param ()
|
|
|
|
$VulnerableDriversFileName = "VulnerableDrivers.csv"
|
|
|
|
# Retrieve and process LOL driver list from the LOL drivers website.
|
|
$LolDrivers = Get-LolDriver
|
|
if ($null -eq $LolDrivers) {
|
|
Write-Message -Type Error -Message "Failed to retrieve or parse remote LOL driver list."
|
|
return
|
|
}
|
|
|
|
# Retrieve our local and processed version of the LOL driver list.
|
|
$LocalLolDriversContent = Get-FileContent -Type "data" -FileName $VulnerableDriversFileName -ErrorAction SilentlyContinue | Out-String
|
|
if ($null -ne $LocalLolDriversContent) {
|
|
$LocalLolDrivers = $LocalLolDriversContent | ConvertFrom-Csv
|
|
Write-Message -Message "Parsed local LOL driver list (count=$($LocalLolDrivers.Count))"
|
|
# Compare the two lists. If they are equal, we don't need to update our local file.
|
|
$Comparison = Compare-Object -ReferenceObject $LocalLolDrivers -DifferenceObject $LolDrivers -Property Id,Hash
|
|
if ($null -eq $Comparison) {
|
|
Write-Message -Type Success -Message "The local copy of the LOL driver list is already up-to-date."
|
|
return
|
|
}
|
|
}
|
|
|
|
Write-Message -Message "The local copy of the LOL driver list needs to be created or updated..."
|
|
|
|
# Convert the list to CSV and write to file.
|
|
$LolDriversCsv = $LolDrivers | ConvertTo-Csv -Delimiter "," -NoTypeInformation | Out-String
|
|
Set-FileContent -Type "data" -FileName $VulnerableDriversFileName -Content $LolDriversCsv
|
|
|
|
Write-Message -Type Success -Message "LOL driver list file created or updated: $($VulnerableDriversFileName)"
|
|
}
|
|
|
|
function Update-WordList {
|
|
|
|
[CmdletBinding()]
|
|
param (
|
|
[UInt32] $WordLength = 8
|
|
)
|
|
|
|
$WordListUrl = "https://raw.githubusercontent.com/CBHue/PyFuscation/master/wordList.txt"
|
|
$WordList = (New-Object Net.WebClient).DownloadString($WordListUrl)
|
|
|
|
if ($null -eq $WordList) {
|
|
throw "Word list is empty"
|
|
}
|
|
|
|
$WordList = $WordList -split "`n" | ForEach-Object { $_.Trim() }
|
|
$WordList = $WordList | Where-Object { (-not [string]::IsNullOrEmpty($_)) -and ($_.Length -eq $WordLength) -and ($_.ToLower() -match "^[a-z]+$") }
|
|
|
|
Set-FileContent -Type "data" -FileName "WordList.txt" -Content ($WordList | Out-String)
|
|
}
|
|
|
|
function Get-ScriptLoader {
|
|
|
|
[OutputType([String])]
|
|
param (
|
|
[String[]] $Modules,
|
|
[String] $EncodedKey
|
|
)
|
|
|
|
$LoaderBlock = @"
|
|
@({{MODULE_LIST}}) | ForEach-Object {
|
|
`$dec = [Convert]::FromBase64String(`$_)
|
|
`$aes = [Security.Cryptography.Aes]::Create()
|
|
`$outbuf = New-Object Byte[] (`$dec.Length - `$aes.IV.Length)
|
|
`$aes.Key = [Convert]::FromBase64String("{{ENCODED_KEY}}")
|
|
`$aes.IV = `$dec[0..(`$aes.IV.Length - 1)]
|
|
`$rc = (New-Object Security.Cryptography.CryptoStream (New-Object IO.MemoryStream (, `$dec[`$aes.IV.Length..(`$dec.Length - 1)])), (`$aes.CreateDecryptor()), ([Security.Cryptography.CryptoStreamMode]::Read)).Read(`$outbuf, 0, `$outbuf.Length)
|
|
try {
|
|
`$sb = `$ExecutionContext.InvokeCommand.NewScriptBlock((ConvertFrom-Gzip -InputBuffer `$outbuf[0..(`$rc - 1)]))
|
|
} catch {
|
|
`$sb = `$ExecutionContext.InvokeCommand.NewScriptBlock(([Text.Encoding]::UTF8.GetString(`$outbuf[0..(`$rc - 1)])))
|
|
}
|
|
. `$sb
|
|
}
|
|
"@
|
|
|
|
$ModuleList = ($Modules | ForEach-Object { "`$$($_)" }) -join ','
|
|
$LoaderBlockResult = $LoaderBlock
|
|
$LoaderBlockResult = $LoaderBlockResult -replace "{{MODULE_LIST}}", $ModuleList
|
|
$LoaderBlockResult = $LoaderBlockResult -replace "{{ENCODED_KEY}}", $EncodedKey
|
|
|
|
return $LoaderBlockResult
|
|
}
|
|
|
|
function Remove-CommentFromScriptBlock {
|
|
|
|
[OutputType([String])]
|
|
[CmdletBinding()]
|
|
param(
|
|
[String] $ScriptBlock
|
|
)
|
|
|
|
$IsCommentBlock = $False
|
|
$Output = ""
|
|
|
|
ForEach ($Line in $ScriptBlock.Split("`n")) {
|
|
if ($Line -like "*<#*") {
|
|
$IsCommentBlock = $True
|
|
}
|
|
|
|
if ((-not $IsCommentBlock) -and ($Line -match "^\s*#.*")) {
|
|
continue
|
|
}
|
|
|
|
if (-not $IsCommentBlock) {
|
|
$Output += "$Line`n"
|
|
}
|
|
|
|
if ($Line -like "*#>*") {
|
|
$IsCommentBlock = $False
|
|
}
|
|
}
|
|
|
|
$Output
|
|
}
|
|
|
|
function ConvertTo-EmbeddedTextBlob {
|
|
param([String] $Text)
|
|
$Compressed = ConvertTo-Gzip -InputText $Text
|
|
[System.Convert]::ToBase64String($Compressed)
|
|
}
|
|
|
|
function ConvertTo-Gzip {
|
|
|
|
[CmdletBinding()]
|
|
param (
|
|
[string] $InputText
|
|
)
|
|
|
|
process {
|
|
[System.Text.Encoding] $Encoding = [System.Text.Encoding]::UTF8
|
|
[byte[]] $InputTextEncoded = $Encoding.GetBytes($InputText)
|
|
[System.IO.MemoryStream] $MemoryStream = New-Object System.IO.MemoryStream
|
|
$GzipStream = New-Object System.IO.Compression.GzipStream $MemoryStream, ([System.IO.Compression.CompressionMode]::Compress)
|
|
$GzipStream.Write($InputTextEncoded, 0, $InputTextEncoded.Length)
|
|
$GzipStream.Close()
|
|
$MemoryStream.Close()
|
|
$MemoryStream.ToArray()
|
|
}
|
|
}
|
|
|
|
function New-RandomByteArray {
|
|
|
|
[OutputType([Byte[]])]
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[ValidateSet(16, 32)]
|
|
[UInt32] $Size
|
|
)
|
|
|
|
# https://gist.github.com/lennybacon/9fcce97f84d1b760e8da0e9d0738536a
|
|
$Random = [System.Security.Cryptography.RandomNumberGenerator]::Create()
|
|
$Buffer = New-Object Byte[] $Size
|
|
$Random.GetBytes($Buffer)
|
|
return $Buffer
|
|
}
|
|
|
|
function ConvertTo-AesEncrypted {
|
|
|
|
[OutputType([Byte[]])]
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[Byte[]] $InputBuffer,
|
|
[Parameter(Mandatory=$true)]
|
|
[Byte[]] $Key
|
|
)
|
|
|
|
# https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes
|
|
$AesAlg = [System.Security.Cryptography.Aes]::Create()
|
|
|
|
$AesAlg.Key = $Key
|
|
$AesAlg.IV = New-RandomByteArray -Size 16
|
|
|
|
$Encryptor = $AesAlg.CreateEncryptor()
|
|
$MemoryStream = New-Object IO.MemoryStream
|
|
$CryptoStream = New-Object System.Security.Cryptography.CryptoStream $MemoryStream, $Encryptor, ([System.Security.Cryptography.CryptoStreamMode]::Write)
|
|
$CryptoStream.Write($InputBuffer, 0, $InputBuffer.Length)
|
|
$CryptoStream.FlushFinalBlock()
|
|
$Encrypted = $MemoryStream.ToArray()
|
|
$MemoryStream.Close()
|
|
$CryptoStream.Close()
|
|
|
|
return $AesAlg.IV + $Encrypted
|
|
}
|
|
|
|
function ConvertFrom-AesEncrypted {
|
|
|
|
[OutputType([Byte[]])]
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[Byte[]] $InputBuffer,
|
|
[Parameter(Mandatory=$true)]
|
|
[Byte[]] $Key
|
|
)
|
|
|
|
# https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes
|
|
$AesAlg = [System.Security.Cryptography.Aes]::Create()
|
|
|
|
$IV = $InputBuffer[0..($AesAlg.IV.Length - 1)]
|
|
$Encrypted = $InputBuffer[$AesAlg.IV.Length..($InputBuffer.Length - 1)]
|
|
$Buffer = New-Object Byte[] ($InputBuffer.Length - $AesAlg.IV.Length)
|
|
|
|
$AesAlg.Key = $Key
|
|
$AesAlg.IV = $IV
|
|
|
|
$Decryptor = $AesAlg.CreateDecryptor()
|
|
$MemoryStream = New-Object IO.MemoryStream (, $Encrypted)
|
|
$CryptoStream = New-Object System.Security.Cryptography.CryptoStream $MemoryStream, $Decryptor, ([System.Security.Cryptography.CryptoStreamMode]::Read)
|
|
$ReadCount = $CryptoStream.Read($Buffer, 0, $Buffer.Length)
|
|
$CryptoStream.Close()
|
|
$MemoryStream.Close()
|
|
|
|
return $Buffer[0..($ReadCount - 1)]
|
|
} |