PSmRemoteNG.psm1
# find mRemoteNG install location $mRNGDirectory = 'HKLM:\SOFTWARE\mRemoteNG', 'HKLM:\SOFTWARE\WOW6432Node\mRemoteNG' | ForEach-Object { Get-ItemProperty -Path $_ -Name InstallDir -ErrorAction SilentlyContinue } | Select-Object -First 1 -ExpandProperty InstallDir # load assemblies try { [void][System.Reflection.Assembly]::LoadFile( "$mRNGDirectory\mRemoteNG.exe" ) [void][System.Reflection.Assembly]::LoadFile( "$mRNGDirectory\BouncyCastle.Crypto.dll" ) } catch { throw $Messages.AssemblyLoadError } <# .SYNOPSIS Import an mRemoteNG root connections node from a confCons.xml file. .PARAMETER EncryptionKey The encryption key for the confCons.xml file. .EXAMPLE $RootNode = Import-MRNGRootNode -Path .\confCons.xml -EncryptionKey ( Read-Host 'Encryiption Key' -AsSecureString ) #> function Import-MRNGRootNode { [OutputType([mRemoteNG.Tree.Root.RootNodeInfo])] param( [Parameter(Mandatory)] [System.IO.FileInfo] $Path, [securestring] $EncryptionKey = ( ConvertTo-SecureString -String 'mR3m' -AsPlainText -Force ) ) # resolve the path $Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath( $Path ) # load the XML $DataProvider = [mRemoteNG.Config.DataProviders.FileDataProvider]::new( $Path ) $XmlString = $DataProvider.Load() # create a function to return the password # this is what mRemoteNG expects [Func[mRemoteNG.Tools.Optional[securestring]]]$Auth = { $EncryptionKey } # create a deserializer $Deserializer = [mRemoteNG.Config.Serializers.Xml.XmlConnectionsDeserializer]::new($Auth) # return the connections ( $Deserializer.Deserialize( $XmlString ) ).RootNodes.Item(0) } <# .SYNOPSIS Create an empty mRemoteNG root connections node. .PARAMETER EncryptionKey The encryption key to use for this connections file. .EXAMPLE $RootNode = New-MRNGRootNode #> function New-MRNGRootNode { [OutputType([mRemoteNG.Tree.Root.RootNodeInfo])] param( [securestring] $EncryptionKey = ( ConvertTo-SecureString -String 'mR3m' -AsPlainText -Force ) ) # convert the encryption key to plaintext $EncryptionKeyBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( $EncryptionKey ) $EncryptionKeyText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( $EncryptionKeyBSTR ) $RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection') # set a password? if ( $EncryptionKeyText -ne $RootNode.DefaultPassword ) { $RootNode.Password = $true $RootNode.PasswordString = $EncryptionKeyText } $RootNode } <# .SYNOPSIS Create an mRemoteNG container node. .EXAMPLE New-MRNGContainer -Name 'Test Container' -Parent $RootNode -Protocol SSH2 .EXAMPLE $Container = New-MRNGContainer -Name 'Test Container' $RootContainer.AddChild( $Container ) $Container2 = New-MRNGContainer -Name 'Child Container' $Container.AddChild( $Container2 ) #> function New-MRNGContainer { [OutputType([mRemoteNG.Container.ContainerInfo])] [CmdletBinding()] param() dynamicparam { $DPDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $SkipParameters = 'Inheritance', 'ConstantID', 'IsContainer' [mRemoteNG.Container.ContainerInfo].GetProperties() | Where-Object { $SkipParameters -notcontains $_.Name } | ForEach-Object { $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.ParameterSetName = '__AllParameterSets' $Collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $Collection.Add($Attribute) $Parameter = New-Object System.Management.Automation.RuntimeDefinedParameter( $_.Name, $_.PropertyType, $Collection ) $DPDictionary.Add( $_.Name, $Parameter ) } $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.ParameterSetName = '__AllParameterSets' $Collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $Collection.Add($Attribute) $Parameter = New-Object System.Management.Automation.RuntimeDefinedParameter( 'Inheritance', [hashtable], $Collection ) $DPDictionary.Add( 'Inheritance', $Parameter ) return $DPDictionary } process { $ContainerInfo = [mRemoteNG.Container.ContainerInfo]::new() # set default port if ( $PSBoundParameters.Keys -contains 'Protocol' -and $PSBoundParameters.Keys -notcontains 'Port' ) { $PSBoundParameters.Port = switch ( $PSBoundParameters.Protocol ) { 'RDP' { 3389 } 'VNC' { 5900 } 'SSH1' { 22 } 'SSH2' { 22 } 'Telnet' { 23 } 'Rlogin' { 513 } 'RAW' { 23 } 'HTTP' { 80 } 'HTTPS' { 443 } 'IntApp' { 0 } } } # set connection properties $PSBoundParameters.Keys | Where-Object { $_ -notmatch 'Parent|Children|Inheritance' } | Where-Object { [mRemoteNG.Container.ContainerInfo].GetProperties().Name -contains $_ } | ForEach-Object { $ContainerInfo.$_ = $PSBoundParameters.$_ } # configure inheritance if ( $PSBoundParameters.Keys -contains 'Inheritance' ) { # process EverythingInherited first if ( $PSBoundParameters.Inheritance.Keys -contains 'EverythingInherited' ) { $ContainerInfo.Inheritance.EverythingInherited = $true } # process all other inheritence $PSBoundParameters.Inheritance.Keys | Where-Object { $_ -ne 'EverythingInherited' } | ForEach-Object { $ContainerInfo.Inheritance.$_ = $PSBoundParameters.Inheritance.$_ } } # if children is specified we append if ( $PSBoundParameters.Keys -contains 'Children' ) { $PSBoundParameters.Children | ForEach-Object { $ContainerInfo.AddChild($_) Write-Verbose ( 'Child ''{0}'' added to ''{1}''.' -f $_.Name, $ContainerInfo.Name ) } } # if parent is specified we append, otherwise we output if ( $PSBoundParameters.Keys -contains 'Parent' ) { $PSBoundParameters.Parent.AddChild( $ContainerInfo ) Write-Verbose ( 'Container ''{0}'' added to ''{1}''.' -f $ContainerInfo.Name, $PSBoundParameters.Parent.Name ) } $ContainerInfo } } <# .SYNOPSIS Create an mRemoteNG connection node. .EXAMPLE New-MRNGConnection -Name 'Test Connection' -HostName '127.0.0.1' -Parent $RootNode -Protocol SSH2 -Inheritance (New-MRNGInheritanceConfiguration -EverythingInherited -Protocol:$false) .EXAMPLE $Connection = New-MRNGConnection -Name 'Test Connection' -HostName '127.0.0.1' $RootContainer.AddChild( $Connection ) #> function New-MRNGConnection { [OutputType([mRemoteNG.Connection.ConnectionInfo])] [CmdletBinding()] param() dynamicparam { $DPDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $SkipParameters = 'Inheritance', 'ConstantID', 'IsContainer' [mRemoteNG.Connection.ConnectionInfo].GetProperties() | Where-Object { $SkipParameters -notcontains $_.Name } | ForEach-Object { $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.ParameterSetName = '__AllParameterSets' $Collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $Collection.Add($Attribute) $Parameter = New-Object System.Management.Automation.RuntimeDefinedParameter( $_.Name, $_.PropertyType, $Collection ) $DPDictionary.Add( $_.Name, $Parameter ) } $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.ParameterSetName = '__AllParameterSets' $Collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $Collection.Add($Attribute) $Parameter = New-Object System.Management.Automation.RuntimeDefinedParameter( 'Inheritance', [hashtable], $Collection ) $DPDictionary.Add( 'Inheritance', $Parameter ) return $DPDictionary } process { $ConnectionInfo = [mRemoteNG.Connection.ConnectionInfo]::new() # set default port if ( $PSBoundParameters.Keys -contains 'Protocol' -and $PSBoundParameters.Keys -notcontains 'Port' ) { $PSBoundParameters.Port = switch ( $PSBoundParameters.Protocol ) { 'RDP' { 3389 } 'VNC' { 5900 } 'SSH1' { 22 } 'SSH2' { 22 } 'Telnet' { 23 } 'Rlogin' { 513 } 'RAW' { 23 } 'HTTP' { 80 } 'HTTPS' { 443 } 'IntApp' { 0 } } } # set connection properties $PSBoundParameters.Keys | Where-Object { $_ -notmatch 'Parent|Inheritance' } | Where-Object { [mRemoteNG.Connection.ConnectionInfo].GetProperties().Name -contains $_ } | ForEach-Object { $ConnectionInfo.$_ = $PSBoundParameters.$_ } # configure inheritance if ( $PSBoundParameters.Keys -contains 'Inheritance' ) { # process EverythingInherited first if ( $PSBoundParameters.Inheritance.Keys -contains 'EverythingInherited' ) { $ConnectionInfo.Inheritance.EverythingInherited = $true } # process all other inheritence $PSBoundParameters.Inheritance.Keys | Where-Object { $_ -ne 'EverythingInherited' } | ForEach-Object { $ConnectionInfo.Inheritance.$_ = $PSBoundParameters.Inheritance.$_ } } # if parent is specified we append, otherwise we output if ( $PSBoundParameters.Keys -contains 'Parent' ) { $PSBoundParameters.Parent.AddChild( $ConnectionInfo ) Write-Verbose ( 'Connection ''{0}'' added to ''{1}''.' -f $ConnectionInfo.Name, $PSBoundParameters.Parent.Name ) } $ConnectionInfo } } <# .SYNOPSIS Helper function to build an inheritance configuration. .EXAMPLE New-MRNGInheritanceConfiguration -EverythingInherited -Icon:$false # inherits everything except the icon #> function New-MRNGInheritanceConfiguration { [OutputType([hashtable])] [CmdletBinding()] param() dynamicparam { $DPDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary [mRemoteNG.Connection.ConnectionInfoInheritance].GetProperties() | Where-Object { $_.Name -ne 'Parent' } | ForEach-Object { $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.ParameterSetName = '__AllParameterSets' $Collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $Collection.Add($Attribute) $Parameter = New-Object System.Management.Automation.RuntimeDefinedParameter( $_.Name, [switch], $Collection ) $DPDictionary.Add( $_.Name, $Parameter ) } return $DPDictionary } process { $ReturnHashtable = @{} $PSBoundParameters.Keys | Where-Object { [mRemoteNG.Connection.ConnectionInfoInheritance].GetProperties().Name -contains $_ } | ForEach-Object { $ReturnHashtable.$_ = $PSBoundParameters.$_ } $ReturnHashtable } } <# .SYNOPSIS Exports the mRemoteNG connection file with the encryption parameters specified. .PARAMETER RootNode The mRemoteNG root connections node generated by New-MRNGRootNode. .PARAMETER Path The path to export the connection file to. .PARAMETER EncryptionKey The encryption key to use to secure the connections file. If no password is supplied the default mRemoteNG encryption key is "mR3m". .PARAMETER EncryptionEngine The encryption engine to use when encrypting the connection passwords. Choices are 'AES', 'Serpent', and 'Twofish'. The default is 'AES'. .PARAMETER BlockCipherMode The block cipher mode to use when encrypting the connection passwords. Choices are 'GCM', 'CCM', and 'EAX'. The default is 'GCM'. .PARAMETER KeyDerivationIterations The number of key derivation iterations to perform when encrypting the connection passwords. Valid values are in the range 1,000 to 50,000. .PARAMETER SortConnections Should the exported connections be sorted? .EXAMPLE Export-MRNGConnectionFile -RootNode $RootNode -Path .\Connections.xml (Get-Credential).Password -SortConnections #> function Export-MRNGConnectionFile { [OutputType([void])] param( [Parameter(Mandatory)] [mRemoteNG.Tree.Root.RootNodeInfo] $RootNode, [Parameter(Mandatory)] [System.IO.FileInfo] $Path, [ValidateSet('AES', 'Serpent', 'Twofish')] [string] $EncryptionEngine = 'AES', [ValidateSet('GCM', 'CCM', 'EAX')] [string] $BlockCipherMode = 'GCM', [ValidateRange(1000, 50000)] [int] $KeyDerivationIterations = 1000, [switch] $SortConnections ) # resolve the path $Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath( $Path ) # get the encryption key as [securestring] if ( $RootNode.Password ) { $EncryptionKey = $RootNode.PasswordString | ConvertTo-SecureString -AsPlainText -Force } else { $EncryptionKey = $RootNode.DefaultPassword | ConvertTo-SecureString -AsPlainText -Force } # choose the encryption engine $Engine = switch ( $EncryptionEngine ) { 'AES' { [Org.BouncyCastle.Crypto.Engines.AesEngine]::new() } 'Serpent' { [Org.BouncyCastle.Crypto.Engines.SerpentEngine]::new() } 'Twofish' { [Org.BouncyCastle.Crypto.Engines.TwofishEngine]::new() } } # choose the cipher mode $Cipher = switch ( $BlockCipherMode ) { 'GCM' { [Org.BouncyCastle.Crypto.Modes.GcmBlockCipher]::new( $Engine ) } 'CCM' { [Org.BouncyCastle.Crypto.Modes.CcmBlockCipher]::new( $Engine ) } 'EAX' { [Org.BouncyCastle.Crypto.Modes.EaxBlockCipher]::new( $Engine ) } } # XML serializer $CryptoProvider = [mRemoteNG.Security.SymmetricEncryption.AeadCryptographyProvider]::new( $Cipher ) $SaveFilter = [mRemoteNG.Security.SaveFilter]::new() $ConnectionNodeSerializer = [mRemoteNG.Config.Serializers.Xml.XmlConnectionNodeSerializer26]::new($CryptoProvider, $EncryptionKey, $SaveFilter) $XmlSerializer = [mRemoteNG.Config.Serializers.Xml.XmlConnectionsSerializer]::new($CryptoProvider, $ConnectionNodeSerializer) # should we sort? if ( $SortConnections ) { $RootNode.SortRecursive() } # save the connection file $FilePathProvider = [mRemoteNG.Config.DataProviders.FileDataProvider]::new( $Path ) $FilePathProvider.Save( $XmlSerializer.Serialize( $RootNode ) ) } <# .SYNOPSIS Convert a mRemoteNG secure string to plain text. .PARAMETER EncryptedMessage The mRemoteNG secure string to be converted. .PARAMETER EncryptionKey The encryption key that was used when encrypting the ConfCons.xml file. If no password is supplied the default mRemoteNG encryption key is "mR3m". .PARAMETER EncryptionEngine The encryption engine to use when decrypting the string. Choices are 'AES', 'Serpent', and 'Twofish'. The default is 'AES'. .PARAMETER BlockCipherMode The block cipher mode to use when decrypting the string. Choices are 'GCM', 'CCM', and 'EAX'. The default is 'GCM'. .PARAMETER KeyDerivationIterations The number of key derivation iterations to perform when decrypting the string. Valid values are in the range 1,000 to 50,000. .EXAMPLE ConvertFrom-MRNGSecureString -EncryptedMessage 'pLs5zen+UvaqFnn2KDn2eTrhO60gjzagqFnI/8n3dF74zCj9lZDGvR1nJ8bxf5OCuHJW8gcWFWOicNIvV4h1' .EXAMPLE ConvertFrom-MRNGSecureString -EncryptedMessage 'LkJUc6Q60hsZmX6QImOS+1nvFYQLNNCfP7iEupby8Ey84Dz+3u7lRo93YaL6fJf2GCXOtpXtzgZACxhVKcJh' -EncryptionEngine Serpent -BlockCipherMode EAX .EXAMPLE ConvertFrom-MRNGSecureString -EncryptedMessage 'MqE3IQxYiLioTaD86rzRusDmiD2nX2b9uabDASZdRB9+gk7ygLWSqYFVEg5zqa65qe6j3ZPtgeLxKNZiIoGv' -EncryptionKey ( 'password' | ConvertTo-SecureString -AsPlainText -Force ) #> function ConvertFrom-MRNGSecureString { [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $EncryptedMessage, [ValidateNotNullOrEmpty()] [securestring] $EncryptionKey = ( ConvertTo-SecureString -String 'mR3m' -AsPlainText -Force ), [ValidateSet('AES', 'Serpent', 'Twofish')] [string] $EncryptionEngine = 'AES', [ValidateSet('GCM', 'CCM', 'EAX')] [string] $BlockCipherMode = 'GCM', [ValidateRange(1000, 50000)] [int] $KeyDerivationIterations = 1000 ) # choose the text encoding $Encoding = [System.Text.Encoding]::UTF8 # convert the $EncryptionKey to plain text $EncryptionKeyBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( $EncryptionKey ) $EncryptionKeyText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( $EncryptionKeyBSTR ) $EncryptionKeyBytes = [Org.BouncyCastle.Crypto.PbeParametersGenerator]::Pkcs5PasswordToBytes( [char[]]$EncryptionKeyText ) # convert the base64 encoded string to a byte array $EncryptedMessageBytes = [convert]::FromBase64String( $EncryptedMessage ) # choose the encryption engine $Engine = switch ( $EncryptionEngine ) { 'AES' { [Org.BouncyCastle.Crypto.Engines.AesEngine]::new() } 'Serpent' { [Org.BouncyCastle.Crypto.Engines.SerpentEngine]::new() } 'Twofish' { [Org.BouncyCastle.Crypto.Engines.TwofishEngine]::new() } } # choose the cipher mode $Cipher = switch ( $BlockCipherMode ) { 'GCM' { [Org.BouncyCastle.Crypto.Modes.GcmBlockCipher]::new( $Engine ) } 'CCM' { [Org.BouncyCastle.Crypto.Modes.CcmBlockCipher]::new( $Engine ) } 'EAX' { [Org.BouncyCastle.Crypto.Modes.EaxBlockCipher]::new( $Engine ) } } # generate a new random string $SecureRandom = [Org.BouncyCastle.Security.SecureRandom]::new() # defaults from mRemoteNG source $NonceBitSize = 128 $MacBitSize = 128 $KeyBitSize = 256 $SaltBitSize = 128 $MinPasswordLength = 1 # get the salt $Salt = New-Object byte[] ( $SaltBitSize/8 ) [array]::Copy( $EncryptedMessageBytes, 0, $Salt, 0, $Salt.Length ) # get the key $KeyGenerator = [Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator]::new() $KeyGenerator.Init( $EncryptionKeyBytes, $Salt, $KeyDerivationIterations ) $KeyParameter = $KeyGenerator.GenerateDerivedMacParameters($KeyBitSize) $KeyBytes = $KeyParameter.GetKey() # create the cipher reader $CipherStream = New-Object System.IO.MemoryStream (, $EncryptedMessageBytes ) $CipherReader = New-Object System.IO.BinaryReader ( $CipherStream ) # get the payload $Payload = $CipherReader.ReadBytes( $Salt.Length ) # get the nonce $Nonce = $CipherReader.ReadBytes( $NonceBitSize / 8 ) # build the decryption parameters $Parameters = [Org.BouncyCastle.Crypto.Parameters.AeadParameters]::new( $KeyParameter, $MacBitSize, $Nonce, $Payload ) # initialize the Cipher $Cipher.Init( $false, $Parameters ) # get the cipher text $CipherTextBytes = $CipherReader.ReadBytes( $EncryptedMessageBytes.Length - $Nonce.Length ) # read the decoded text byte array $PlainTextByteArray = New-Object byte[] ( $Cipher.GetOutputSize( $CipherTextBytes.Length ) ) # get the length of the decoded string $Len = $Cipher.ProcessBytes( $CipherTextBytes, 0, $CipherTextBytes.Length, $PlainTextByteArray, 0 ) # do finial decryption $Cipher.DoFinal( $PlainTextByteArray, $Len ) > $null # output UTF8 encoded string $Encoding.GetString( $PlainTextByteArray ) } <# .SYNOPSIS Convert a plain text string to a mRemoteNG secure string. .PARAMETER Message The string to be converted. .PARAMETER EncryptionKey The encryption key to use when encrypting the string. It should match what you are using in your ConfCons.xml file. If no password is supplied the default mRemoteNG encryption key is "mR3m". .PARAMETER EncryptionEngine The encryption engine to use when encrypting the string. Choices are 'AES', 'Serpent', and 'Twofish'. The default is 'AES'. .PARAMETER BlockCipherMode The block cipher mode to use when encrypting the string. Choices are 'GCM', 'CCM', and 'EAX'. The default is 'GCM'. .PARAMETER KeyDerivationIterations The number of key derivation iterations to perform when encrypting the string. Valid values are in the range 1,000 to 50,000. .EXAMPLE ConvertTo-MRNGSecureString -Message 'SecureP@ssword!' .EXAMPLE ConvertTo-MRNGSecureString -Message 'SecureP@ssword!' -EncryptionEngine Serpent -BlockCipherMode EAX .EXAMPLE ConvertTo-MRNGSecureString -Message 'SecureP@ssword!' -EncryptionKey ( 'password' | ConvertTo-SecureString -AsPlainText -Force ) #> function ConvertTo-MRNGSecureString { [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Message, [ValidateNotNullOrEmpty()] [securestring] $EncryptionKey = ( ConvertTo-SecureString -String 'mR3m' -AsPlainText -Force ), [ValidateSet('AES', 'Serpent', 'Twofish')] [string] $EncryptionEngine = 'AES', [ValidateSet('GCM', 'CCM', 'EAX')] [string] $BlockCipherMode = 'GCM', [ValidateRange(1000, 50000)] [int] $KeyDerivationIterations = 1000 ) # choose the text encoding $Encoding = [System.Text.Encoding]::UTF8 # convert the $EncryptionKey to plain text $EncryptionKeyBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( $EncryptionKey ) $EncryptionKeyText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( $EncryptionKeyBSTR ) $EncryptionKeyBytes = [Org.BouncyCastle.Crypto.PbeParametersGenerator]::Pkcs5PasswordToBytes( [char[]]$EncryptionKeyText ) # convert message to byte array $MessageBytes = $Encoding.GetBytes($Message) # choose the encryption engine $Engine = switch ( $EncryptionEngine ) { 'AES' { [Org.BouncyCastle.Crypto.Engines.AesEngine]::new() } 'Serpent' { [Org.BouncyCastle.Crypto.Engines.SerpentEngine]::new() } 'Twofish' { [Org.BouncyCastle.Crypto.Engines.TwofishEngine]::new() } } # choose the cipher mode $Cipher = switch ( $BlockCipherMode ) { 'GCM' { [Org.BouncyCastle.Crypto.Modes.GcmBlockCipher]::new( $Engine ) } 'CCM' { [Org.BouncyCastle.Crypto.Modes.CcmBlockCipher]::new( $Engine ) } 'EAX' { [Org.BouncyCastle.Crypto.Modes.EaxBlockCipher]::new( $Engine ) } } # generate a new random string $SecureRandom = [Org.BouncyCastle.Security.SecureRandom]::new() # defaults from mRemoteNG source $NonceBitSize = 128 $MacBitSize = 128 $KeyBitSize = 256 $SaltBitSize = 128 $MinPasswordLength = 1 # create the salt $Salt = New-Object byte[] ( $SaltBitSize/8 ) $SecureRandom.NextBytes($Salt) # create the key $KeyGenerator = [Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator]::new() $KeyGenerator.Init( $EncryptionKeyBytes, $Salt, $KeyDerivationIterations ) $KeyParameter = $KeyGenerator.GenerateDerivedMacParameters($KeyBitSize) $KeyBytes = $KeyParameter.GetKey() # create the payload and add the salt $Payload = New-Object byte[] ( $Salt.Length ) [array]::Copy( $Salt, 0, $Payload, 0, $Salt.Length ) # create the nonce $Nonce = New-Object byte[] ( $NonceBitSize / 8 ) $SecureRandom.NextBytes( $Nonce, 0, $Nonce.Length ) # build the encryption parameters $Parameters = [Org.BouncyCastle.Crypto.Parameters.AeadParameters]::new( $KeyParameter, $MacBitSize, $Nonce, $Payload ) # initialize the cipher $Cipher.Init( $true, $Parameters ) # encrypt the message $CipherText = New-Object byte[] ($Cipher.GetOutputSize( $MessageBytes.Length )) $Len = $Cipher.ProcessBytes( $MessageBytes, 0, $MessageBytes.Length, $CipherText, 0 ) $Cipher.DoFinal( $CipherText, $Len ) > $null # create a binary stream $CombinedStream = New-Object System.IO.MemoryStream $BinaryWriter = New-Object System.IO.BinaryWriter ( $CombinedStream ) # write the payload, nonce, and cipher to the binary stream $BinaryWriter.Write( $Payload ) $BinaryWriter.Write( $Nonce ) $BinaryWriter.Write( $CipherText ) # convert the binary stream to a base64 encoded string [convert]::ToBase64String( $CombinedStream.ToArray() ) } # SIG # Begin signature block # MIIesgYJKoZIhvcNAQcCoIIeozCCHp8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUSteiarZo00I03b9tTWCZPUh9 # Lvigghm9MIIEhDCCA2ygAwIBAgIQQhrylAmEGR9SCkvGJCanSzANBgkqhkiG9w0B # AQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNV # BAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRU # cnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTA1MDYwNzA4MDkxMFoXDTIwMDUzMDEw # NDgzOFowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2Fs # dCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8G # A1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNF # UkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6q # gT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x # 2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ # w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbH # d2pBnqcP1/vulBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh # 2JU022R5KP+6LhHC5ehbkkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzT # bafc8H9vg2XiaquHhnUCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rE # JlTvA73gJMtUGjAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwDgYDVR0P # AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQG # A1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVz # dEV4dGVybmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGG # GWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEFBQADggEBAE1C # L6bBiusHgJBYRoz4GTlmKjxaLG3P1NmHVY15CxKIe0CP1cf4S41VFmOtt1fcOyu9 # 08FPHgOHS0Sb4+JARSbzJkkraoTxVHrUQtr802q7Zn7Knurpu9wHx8OSToM8gUmf # ktUyCepJLqERcZo20sVOaLbLDhslFq9s3l122B9ysZMmhhfbGN6vRenf+5ivFBjt # pF72iZRF8FUESt3/J90GSkD2tLzx5A+ZArv9XQ4uKMG+O18aP5cQhLwWPtijnGMd # ZstcX9o+8w8KCTUi29vAPwD55g1dZ9H9oB4DK9lA977Mh2ZUgKajuPUZYtXSJrGY # Ju6ay0SnRVqBlRUa9VEwggTmMIIDzqADAgECAhBiXE2QjNVC+6supXM/8VQZMA0G # CSqGSIb3DQEBBQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNV # BAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdv # cmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMU # VVROLVVTRVJGaXJzdC1PYmplY3QwHhcNMTEwNDI3MDAwMDAwWhcNMjAwNTMwMTA0 # ODM4WjB6MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy # MRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEg # MB4GA1UEAxMXQ09NT0RPIFRpbWUgU3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEB # AQUAA4IBDwAwggEKAoIBAQCqgvGEqVvYcbXSXSvt9BMgDPmb6dGPdF5u7uspSNjI # vizrCmFgzL2SjXzddLsKnmhOqnUkcyeuN/MagqVtuMgJRkx+oYPp4gNgpCEQJ0Ca # WeFtrz6CryFpWW1jzM6x9haaeYOXOh0Mr8l90U7Yw0ahpZiqYM5V1BIR8zsLbMaI # upUu76BGRTl8rOnjrehXl1/++8IJjf6OmqU/WUb8xy1dhIfwb1gmw/BC/FXeZb5n # OGOzEbGhJe2pm75I30x3wKoZC7b9So8seVWx/llaWm1VixxD9rFVcimJTUA/vn9J # AV08m1wI+8ridRUFk50IYv+6Dduq+LW/EDLKcuoIJs0ZAgMBAAGjggFKMIIBRjAf # BgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUZCKGtkqJ # yQQP0ARYkiuzbj0eJ2wwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C # AQAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMEIGA1Ud # HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZp # cnN0LU9iamVjdC5jcmwwdAYIKwYBBQUHAQEEaDBmMD0GCCsGAQUFBzAChjFodHRw # Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVROQWRkVHJ1c3RPYmplY3RfQ0EuY3J0MCUG # CCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEB # BQUAA4IBAQARyT3hBeg7ZazJdDEDt9qDOMaSuv3N+Ntjm30ekKSYyNlYaDS18Ash # U55ZRv1jhd/+R6pw5D9eCJUoXxTx/SKucOS38bC2Vp+xZ7hog16oYNuYOfbcSV4T # p5BnS+Nu5+vwQ8fQL33/llqnA9abVKAj06XCoI75T9GyBiH+IV0njKCv2bBS7vzI # 7bec8ckmONalMu1Il5RePeA9NbSwyVivx1j/YnQWkmRB2sqo64sDvcFOrh+RMrjh # JDt77RRoCYaWKMk7yWwowiVp9UphreAn+FOndRWwUTGw8UH/PlomHmB+4uNqOZrE # 6u4/5rITP1UDBE0LkHLU6/u8h5BRsjgZMIIE/jCCA+agAwIBAgIQK3PbdGMRTFpb # MkryMFdySTANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS # R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD # T01PRE8gQ0EgTGltaXRlZDEgMB4GA1UEAxMXQ09NT0RPIFRpbWUgU3RhbXBpbmcg # Q0EwHhcNMTkwNTAyMDAwMDAwWhcNMjAwNTMwMTA0ODM4WjCBgzELMAkGA1UEBhMC # R0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9y # ZDEYMBYGA1UECgwPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDDCJTZWN0aWdvIFNI # QS0xIFRpbWUgU3RhbXBpbmcgU2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A # MIIBCgKCAQEAv1I2gjrcdDcNeNV/FlAZZu26GpnRYziaDGayQNungFC/aS42Lwpn # P0ChSopjNZvQGcx0qhcZkSu1VSAZ+8AaOm3KOZuC8rqVoRrYNMe4iXtwiHBRZmns # d/7GlHJ6zyWB7TSCmt8IFTcxtG2uHL8Y1Q3P/rXhxPuxR3Hp+u5jkezx7M5ZBBF8 # rgtgU+oq874vAg/QTF0xEy8eaQ+Fm0WWwo0Si2euH69pqwaWgQDfkXyVHOaeGWTf # dshgRC9J449/YGpFORNEIaW6+5H6QUDtTQK0S3/f4uA9uKrzGthBg49/M+1BBuJ9 # nj9ThI0o2t12xr33jh44zcDLYCQD3npMqwIDAQABo4IBdDCCAXAwHwYDVR0jBBgw # FoAUZCKGtkqJyQQP0ARYkiuzbj0eJ2wwHQYDVR0OBBYEFK7u2WC6XvUsARL9jo2y # VXI1Rm/xMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM # MAoGCCsGAQUFBwMIMEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQMIMCUwIwYIKwYB # BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMEIGA1UdHwQ7MDkwN6A1oDOG # MWh0dHA6Ly9jcmwuc2VjdGlnby5jb20vQ09NT0RPVGltZVN0YW1waW5nQ0FfMi5j # cmwwcgYIKwYBBQUHAQEEZjBkMD0GCCsGAQUFBzAChjFodHRwOi8vY3J0LnNlY3Rp # Z28uY29tL0NPTU9ET1RpbWVTdGFtcGluZ0NBXzIuY3J0MCMGCCsGAQUFBzABhhdo # dHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAen+pStKw # pBwdDZ0tXMauWt2PRR3wnlyQ9l6scP7T2c3kGaQKQ3VgaoOkw5mEIDG61v5MzxP4 # EPdUCX7q3NIuedcHTFS3tcmdsvDyHiQU0JzHyGeqC2K3tPEG5OfkIUsZMpk0uRlh # dwozkGdswIhKkvWhQwHzrqJvyZW9ljj3g/etfCgf8zjfjiHIcWhTLcuuquIwF4Mi # KRi14YyJ6274fji7kE+5Xwc0EmuX1eY7kb4AFyFu4m38UnnvgSW6zxPQ+90rzYG2 # V4lO8N3zC0o0yoX/CLmWX+sRE+DhxQOtVxzhXZIGvhvIPD+lIJ9p0GnBxcLJPufF # cvfqG5bilK+GLjCCBUwwggQ0oAMCAQICEQCV7K1bRdp1yZPPBYrFbG8VMA0GCSqG # SIb3DQEBCwUAMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNo # ZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRl # ZDEkMCIGA1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE5MTAx # NTAwMDAwMFoXDTIwMTAwNzIzNTk1OVowgZQxCzAJBgNVBAYTAlVTMQ4wDAYDVQQR # DAU2MDEyMDERMA8GA1UECAwISWxsaW5vaXMxDjAMBgNVBAcMBUVsZ2luMRowGAYD # VQQJDBExMjg3IEJsYWNraGF3ayBEcjEaMBgGA1UECgwRU2hhbm5vbiBHcmF5YnJv # b2sxGjAYBgNVBAMMEVNoYW5ub24gR3JheWJyb29rMIIBIjANBgkqhkiG9w0BAQEF # AAOCAQ8AMIIBCgKCAQEA1A3wiJRalXGleCYOLaKdlD5iZrswpu4ChSnCx8XvkWeL # R/XBQSvebJXpF99sdVwwUeouEk1i5EA2AIU88DoEw0+1XxC6DAUwYAVXmo3M+dkv # OwNXHrWwSRqNwmhABHVejGOInKsi1jYa3DPI2dFBL19Trg0ez0oXkMVwbKGDpwt9 # U7WbbjveLcAPnpvR65dk3Jhb9bmCMirCnALjaOOnFzlCUiagx9nDszzw7fYRAlf6 # EJNnicwwBujOmA59q9urwAuEA7/VXTAMpE2wmhVsM4xqscbzAPs7PSVgkOTrZR6a # 51r1HSCzrULISVZKxF0mD4/6qOElqM/X/nd7q7dmSQIDAQABo4IBrjCCAaowHwYD # VR0jBBgwFoAUDuE6qFM6MdWKvsG7rWcaA4WtNA4wHQYDVR0OBBYEFJHiTLW7XSJv # Xn/hpQzh7bxSIUZ2MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1Ud # JQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBABgNVHSAEOTA3MDUG # DCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29t # L0NQUzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLnNlY3RpZ28uY29tL1Nl # Y3RpZ29SU0FDb2RlU2lnbmluZ0NBLmNybDBzBggrBgEFBQcBAQRnMGUwPgYIKwYB # BQUHMAKGMmh0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1JTQUNvZGVTaWdu # aW5nQ0EuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAm # BgNVHREEHzAdgRtzaGFubm9uLmdyYXlicm9va0BnbWFpbC5jb20wDQYJKoZIhvcN # AQELBQADggEBACNm23H5GuT8THomfaxBDdgN/4g4FgsClLsxhAyRyWxqnE4udxre # x1Dq3FQtdXoeXFPaaFYVH/zvmEFuh+oz65Ejomo2WPSOVKiF6NbLpxScHW2c1+yO # NHDqn/TGtx0+RrfUgOFgao/AzuRqxei90CotgUe73cpmG0JPdmV1+hnMAhojoO4g # bhfdb69y8fCaDzLoTmybz1JOfcinR12TLntNV+Def2CXaNoOV2VNKpauAiIh2BkK # 7LoabyBtMNQbMNCY33dyNq9V7tvVxdYOlPRoANB3SfATPtKQCrix7T85qrFoRHBC # SxTfYFHsyGQVno6lmMfQstJ6q+TQJz1gFcUwggX1MIID3aADAgECAhAdokgwb5sm # GNCC4JZ9M9NqMA0GCSqGSIb3DQEBDAUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRo # ZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0 # aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xODExMDIwMDAwMDBaFw0zMDEyMzEyMzU5 # NTlaMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIx # EDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEkMCIG # A1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0B # AQEFAAOCAQ8AMIIBCgKCAQEAhiKNMoV6GJ9J8JYvYwgeLdx8nxTP4ya2JWYpQIZU # RnQxYsUQ7bKHJ6aZy5UwwFb1pHXGqQ5QYqVRkRBq4Etirv3w+Bisp//uLjMg+gwZ # iahse60Aw2Gh3GllbR9uJ5bXl1GGpvQn5Xxqi5UeW2DVftcWkpwAL2j3l+1qcr44 # O2Pej79uTEFdEiAIWeg5zY/S1s8GtFcFtk6hPldrH5i8xGLWGwuNx2YbSp+dgcRy # QLXiX+8LRf+jzhemLVWwt7C8VGqdvI1WU8bwunlQSSz3A7n+L2U18iLqLAevRtn5 # RhzcjHxxKPP+p8YU3VWRbooRDd8GJJV9D6ehfDrahjVh0wIDAQABo4IBZDCCAWAw # HwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFA7hOqhT # OjHVir7Bu61nGgOFrTQOMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/ # AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMDBggrBgEFBQcDCDARBgNVHSAECjAIMAYG # BFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29t # L1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF # BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VT # RVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2Nz # cC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBNY1DtRzRKYaTb3moq # jJvxAAAeHWJ7Otcywvaz4GOz+2EAiJobbRAHBE++uOqJeCLrD0bs80ZeQEaJEvQL # d1qcKkE6/Nb06+f3FZUzw6GDKLfeL+SU94Uzgy1KQEi/msJPSrGPJPSzgTfTt2Sw # piNqWWhSQl//BOvhdGV5CPWpk95rcUCZlrp48bnI4sMIFrGrY1rIFYBtdF5KdX6l # uMNstc/fSnmHXMdATWM19jDTz7UKDgsEf6BLrrujpdCEAJM+U100pQA1aWy+nyAl # EA0Z+1CQYb45j3qOTfafDh7+B1ESZoMmGUiVzkrJwX/zOgWb+W/fiH/AI57SHkN6 # RTHBnE2p8FmyWRnoao0pBAJ3fEtLzXC+OrJVWng+vLtvAxAldxU0ivk2zEOS5LpP # 8WKTKCVXKftRGcehJUBqhFfGsp2xvBwK2nxnfn0u6ShMGH7EezFBcZpLKewLPVdQ # 0srd/Z4FUeVEeN0B3rF1mA1UJP3wTuPi+IO9crrLPTru8F4XkmhtyGH5pvEqCgul # ufSe7pgyBYWe6/mDKdPGLH29OncuizdCoGqC7TtKqpQQpOEN+BfFtlp5MxiS47V1 # +KHpjgolHuQe8Z9ahyP/n6RRnvs5gBHN27XEp6iAb+VT1ODjosLSWxr6MiYtaldw # HDykWC6j81tLB9wyWfOHpxptWDGCBF8wggRbAgEBMIGRMHwxCzAJBgNVBAYTAkdC # MRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQx # GDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEkMCIGA1UEAxMbU2VjdGlnbyBSU0Eg # Q29kZSBTaWduaW5nIENBAhEAleytW0XadcmTzwWKxWxvFTAJBgUrDgMCGgUAoHgw # GAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC # NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQx # FgQU/ZOeKzMn0jENxL8UtGrsfu7m1OgwDQYJKoZIhvcNAQEBBQAEggEAmljnQ5PV # kVJXpkl25uIHc8upTuF+WeAuRZlf0uVg23wAe1J/t9v6AqrlLhzOG5nnCOkoztvF # LsAYuFmNqaYzBlfP7gCfnwhGV0ZiOwqLiYPRRu7qx8bfaeSVfGer7oxGoOlRqCZ1 # CdpHfMcp9lzRaHZ2lUFoQYmcA8V8MIjtnbD4Dc95sEguMUM1uVU+6oF3xZmcip9U # vo6Cbv0yPcgXdpHG+4bf3YqUnFgahmgKR2TYU6UvZ3MAn2Mx2vX/0lxl0CTDky+Q # jgPNf6SqwnUGd6NXyk5ljCijOXx/d6Tj9wHpYs5MeIbwlIgAeCpJ6DpynpfWMFFB # MI2/Oh33spjSx6GCAigwggIkBgkqhkiG9w0BCQYxggIVMIICEQIBATCBjjB6MQsw # CQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQH # EwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEgMB4GA1UEAxMX # Q09NT0RPIFRpbWUgU3RhbXBpbmcgQ0ECECtz23RjEUxaWzJK8jBXckkwCQYFKw4D # AhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X # DTIwMDEyMzE2NTkzNFowIwYJKoZIhvcNAQkEMRYEFIzRY+To0DgkKpCN4FSnlunw # 59nAMA0GCSqGSIb3DQEBAQUABIIBAKWV0PRhdPSoiPOxKrN+vDvqriARDsEHYlah # 7MkzxiQqo3dPt0CTB4tqk+RJmvpmKiZxZ+/EI4ayMgFs/aybTQMdcZs2oOJRBO51 # OfH23utmqDckiB72QEu/AxCvGAh1I8BJopZxvEy7czd/QeH90ZXlNyhoJYagf2xW # R2eOS/oSJSbhDoXRwJ0lakHfm1YUCENP/WSBnytQajQEyZs5nj6nTtbolfylJmP7 # vOb07tZWvQ3r8TAhzLitJ1WCAiDfGwk4/qvoQfH8c6aMH/j6pcglIV8QM4YL5DOt # EZKajBxxEowDmrSF1o06GPkb+e9AItNH4raF9P7UIs4lIAt+mZc= # SIG # End signature block |