-
-
Save realslacker/b14f686ecd6dbcc229da5cb7a1ca92d9 to your computer and use it in GitHub Desktop.
Add-Type -Path 'C:\Program Files (x86)\mRemoteNG\BouncyCastle.Crypto.dll' | |
function ConvertFrom-MRNGSecurePassword { | |
param( | |
[Parameter(Mandatory)] | |
[ValidateNotNullOrEmpty()] | |
[string] | |
$EncryptedMessage, | |
[Parameter(Mandatory)] | |
[ValidateNotNullOrEmpty()] | |
[securestring] | |
$EncryptionKey | |
) | |
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( $EncryptionKey ) ) | |
$EncryptedMessageBytes = [convert]::FromBase64String( $EncryptedMessage ) | |
$Engine = [Org.BouncyCastle.Crypto.Engines.AesEngine]::new() | |
$Cipher = [Org.BouncyCastle.Crypto.Modes.GcmBlockCipher]::new($Engine) | |
$Encoding = [System.Text.Encoding]::UTF8 | |
$SecureRandom = [Org.BouncyCastle.Security.SecureRandom]::new() | |
$NonceBitSize = 128 | |
$MacBitSize = 128 | |
$KeyBitSize = 256 | |
$SaltBitSize = 128 | |
$KeyDerivationIterations = 1000 | |
$MinPasswordLength = 1 | |
$Salt = New-Object byte[] ( $SaltBitSize/8 ) | |
[array]::Copy( $EncryptedMessageBytes, 0, $Salt, 0, $Salt.Length ) | |
Write-Verbose ( "Salt: {0}" -f ($Salt -join ',') ) -Verbose | |
$PasswordInBytes = [Org.BouncyCastle.Crypto.PbeParametersGenerator]::Pkcs5PasswordToBytes( $Password.ToCharArray() ) | |
$KeyGenerator = [Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator]::new() | |
$KeyGenerator.Init( $PasswordInBytes, $Salt, $KeyDerivationIterations ) | |
$KeyParameter = $KeyGenerator.GenerateDerivedMacParameters($KeyBitSize) | |
$KeyBytes = $KeyParameter.GetKey() | |
$CipherStream = New-Object System.IO.MemoryStream (, $EncryptedMessageBytes ) | |
$CipherReader = New-Object System.IO.BinaryReader ( $CipherStream ) | |
$Payload = $CipherReader.ReadBytes( $Salt.Length ) | |
$Nonce = $CipherReader.ReadBytes( $NonceBitSize / 8 ) | |
Write-Verbose ( 'Nonce: {0}' -f ( $Nonce -join ',' ) ) -Verbose | |
$Parameters = [Org.BouncyCastle.Crypto.Parameters.AeadParameters]::new( $KeyParameter, $MacBitSize, $Nonce, $Payload ) | |
$Cipher.Init( $false, $Parameters ) | |
$CipherTextBytes = $CipherReader.ReadBytes( $EncryptedMessageBytes.Length - $Nonce.Length ) | |
$PlainText = New-Object byte[] ( $Cipher.GetOutputSize( $CipherTextBytes.Length ) ) | |
$Len = $Cipher.ProcessBytes( $CipherTextBytes, 0, $CipherTextBytes.Length, $PlainText, 0 ) | |
$Cipher.DoFinal( $PlainText, $Len ) > $null | |
$Encoding.GetString( $PlainText ) | |
} | |
function ConvertTo-MRNGSecurePassword { | |
param( | |
[Parameter(Mandatory)] | |
[ValidateNotNullOrEmpty()] | |
[string] | |
$Message, | |
[Parameter(Mandatory)] | |
[ValidateNotNullOrEmpty()] | |
[securestring] | |
$EncryptionKey | |
) | |
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR( $EncryptionKey ) ) | |
$MessageBytes = $Encoding.GetBytes($Message) | |
$Engine = [Org.BouncyCastle.Crypto.Engines.AesEngine]::new() | |
$Cipher = [Org.BouncyCastle.Crypto.Modes.GcmBlockCipher]::new($Engine) | |
$Encoding = [System.Text.Encoding]::UTF8 | |
$SecureRandom = [Org.BouncyCastle.Security.SecureRandom]::new() | |
$NonceBitSize = 128 | |
$MacBitSize = 128 | |
$KeyBitSize = 256 | |
$SaltBitSize = 128 | |
$KeyDerivationIterations = 1000 | |
$MinPasswordLength = 1 | |
$Salt = New-Object byte[] ( $SaltBitSize/8 ) | |
$SecureRandom.NextBytes($Salt) | |
Write-Verbose ( "Salt: {0}" -f ($Salt -join ',') ) -Verbose | |
$PasswordInBytes = [Org.BouncyCastle.Crypto.PbeParametersGenerator]::Pkcs5PasswordToBytes( $Password.ToCharArray() ) | |
$KeyGenerator = [Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator]::new() | |
$KeyGenerator.Init( $PasswordInBytes, $Salt, $KeyDerivationIterations ) | |
$KeyParameter = $KeyGenerator.GenerateDerivedMacParameters($KeyBitSize) | |
$KeyBytes = $KeyParameter.GetKey() | |
$Payload = New-Object byte[] ( $Salt.Length ) | |
[array]::Copy( $Salt, 0, $Payload, 0, $Salt.Length ) | |
$Nonce = New-Object byte[] ( $NonceBitSize / 8 ) | |
$SecureRandom.NextBytes( $Nonce, 0, $Nonce.Length ) | |
Write-Verbose ( 'Nonce: {0}' -f ( $Nonce -join ',' ) ) -Verbose | |
$Parameters = [Org.BouncyCastle.Crypto.Parameters.AeadParameters]::new( $KeyParameter, $MacBitSize, $Nonce, $Payload ) | |
$Cipher.Init( $true, $Parameters ) | |
$CipherText = New-Object byte[] ($Cipher.GetOutputSize( $MessageBytes.Length )) | |
$Len = $Cipher.ProcessBytes( $MessageBytes, 0, $MessageBytes.Length, $CipherText, 0 ) | |
$Cipher.DoFinal( $CipherText, $Len ) > $null | |
$CombinedStream = New-Object System.IO.MemoryStream | |
$BinaryWriter = New-Object System.IO.BinaryWriter ( $CombinedStream ) | |
$BinaryWriter.Write( $Payload ) | |
$BinaryWriter.Write( $Nonce ) | |
$BinaryWriter.Write( $CipherText ) | |
[convert]::ToBase64String( $CombinedStream.ToArray() ) | |
} | |
function New-MRNGRandomString ( $Length = 20 ) { | |
$SecureRandom = [Org.BouncyCastle.Security.SecureRandom]::new() | |
$StringBuilder = [System.Text.StringBuilder]::new() | |
[char[]]$AvailableChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+|[]{};:',./<>?" | |
for ( $i = 0; $i -lt $Length; $i ++ ) { | |
$RandomIndex = $SecureRandom.Next( $AvailableChars.Length - 1 ) | |
$StringBuilder.Append( $AvailableChars[ $RandomIndex ] ) > $null | |
} | |
return $StringBuilder.ToString() | |
} |
@reddwarf666 So glad it's useful to someone else!
Hi @realslacker
I recently upgraded to PowerShell Core 7 and when I ran my script which has this function "ConvertFrom-MRNGSecurePassword" it crashes on "$Cipher.DoFinal( $PlainText, $Len ) > $null"
Example:
$EncyptionKey = ConvertTo-SecureString -String "mR3m" -AsPlainText -Force
$DecodedPassword = ConvertFrom-MRNGSecurePassword -EncryptedMessage "8k8a2vU8B26YnxvtYaLX9EOqpAr4xnYziSa4thiapTt/J9y1VxcjYfkxu8wPldHXkk5Sg7qeh2Ce3ofSpS3Pc5obDsk7cE2UZ4Fij6SA" -EncryptionKey $EncyptionKey
MethodInvocationException: /Users/stevenspierenburg/Documents/mremote_testing/PSmRemoteNG-master/mRemoteNG-Password-Util.psm1:84
Line |
84 | $Cipher.DoFinal( $PlainText, $Len ) > $null
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling "DoFinal" with "2" argument(s): "mac check in GCM failed"
When I used the module as you have on "https://github.com/realslacker/PSmRemoteNG" I face the same issue:
ConvertFrom-MRNGSecureString -EncryptedMessage "8k8a2vU8B26YnxvtYaLX9EOqpAr4xnYziSa4thiapTt/J9y1VxcjYfkxu8wPldHXkk5Sg7qeh2Ce3ofSpS3Pc5obDsk7cE2UZ4Fij6SA"
MethodInvocationException:
Line |
104 | $Cipher.DoFinal( $PlainTextByteArray, $Len ) > $null
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling "DoFinal" with "2" argument(s): "mac check in GCM failed"
�~�t���p} �Ts����)C�ˋ@���
I downloaded the latest "BouncyCastle.Crypto.dll" from the site "http://www.bouncycastle.org/csharp/#RELEASENOTES186" and it did not resolve this problem I am seeing.
Do you have any idea what might be wrong?
System Information:
MacOS Catalina 10.15
PowerShell Core 7
DotNet --info output:
Version: 2.1.4
Commit SHA-1 hash: 5e8add2190
Runtime Environment:
OS Name: Mac OS X
OS Version: 10.15
OS Platform: Darwin
RID: osx.10.12-x64
Base Path: /usr/local/share/dotnet/sdk/2.1.4/
Microsoft .NET Core Shared Framework Host
Version : 2.0.5
Build : 17373eb129b3b05aa18ece963f8795d65ef8ea54
@realslacker Any idea what this could be?
I tried Powershell 7.0.1 but that did not solve the issue
I opened a issue on github for Powershell Core to see if they have any ideas:
PowerShell/PowerShell#12741
@realslacker It's been a while now and I thought to check in and see if maybe you found a solution to the issue?
Hi
I just found this module and wanted to thank you so, so much!
I have been using mRemoteNG for years now and it is one of the Windows apps I keep using because our team works 99% with Windows and MremoteNG. Nothing wrong with mRemoteNG, nothing at all and it is to date one of the best RDP managers out there.
But I have a Macbook and need to run a virtual system to run mRemoteNG. But I do not always want to start Windows just for that 1 tool. I know there are other RDP managers for MacOS but the thing holding me back was the fact that whatever tool I looked at would either not support importing mRemoteNG files or if they can they will discard the password.
So for years I had the idea/dream of having an RDP manager on MacOS that I would create a connection file for via PowerShell and use the mRemoteNG confCons file as source. The idea always broke at the password hurdle and I stopped before investing too much effort.
Our passwords change too frequently there are just too many servers to have to manually enter these passwords, I wanted to have an automated solution where 1 script does the transfer and everything just works, passwords included.
Thanks to your wonderful work I now have that dream! Finally, after years of hoping to solve the complete puzzle I can complete the story :-)
It consists of PowerShell Core, Royal TSX, a PS Core module of Royal to manipulate their connections file(s) and your password decoder. I ran a first test script tonight, pulling connections from confCons, decoding passwords, creating the same connections in a Royal TSX document and it all worked perfectly fine. Yay!
Again, I cannot thank you enough for solving the final piece of the puzzle and make this happen!
Regards,
Steven