FWIW, our Information Security Engineer requested the use of RNGCryptoServiceProvider because Get-Random uses the system clock as the default seed, so in his opinion, deriving the generated string would be relatively trivial. In his explanation, the resulting Base64 string using RNGCryptoServiceProvider is longer than 15 characters, but the entropy is coming from the original 15 bytes, which should put cracking beyond nation-state capabilities...possibly. In the end, we've opted for a combination of both methods to ensure complexity requirements are met.
========== $randombytes = new-object byte[] 15 (new-object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($randombytes) $pass = [System.Convert]::ToBase64String($randombytes) $a = ([char[]](get-random -input (33..47) -count 2)) -join "" $b = ([char[]](get-random -input (48..57) -count 2)) -join "" $password = $a + $pass + $b ========== As stated earlier, we use the above in an automated script that runs on a routine basis to change passwords for disabled accounts. I used the same technique to put together a quick random password generator for other use cases. A handy little trick was incorporating an automatic copy to the clipboard to make recording the password easier, and then emptying the clipboard upon exit. Sticking with the "secure" theme, I wanted to prevent the script from be stopped or exited prior to the clipboard being emptied, so I incorporated the code from here: http://mymsworld.kahsky.com/?p=154 to prevent the powershell window from being closed, and used Try/Finally blocks to handle Ctrl+C input. ========== #Calling user32.dll methods for Windows and Menus $MethodsCall = ' [DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable); [DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong); [DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable); ' #Create a new namespace for the Methods to be able to call them Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32 #WM_SYSCOMMAND Message $MF_GRAYED = 0x00000001L #Indicates that the menu item is disabled and grayed so that it cannot be selected. $MF_BYCOMMAND = 0x0 #Gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag. $MF_DISABLED = 0x00000002L #Indicates that the menu item is disabled, but not grayed, so it cannot be selected. $MF_ENABLED = 0x00000000L #Indicates that the menu item is enabled and restored from a grayed state so that it can be selected. #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx $SC_CLOSE = 0xF060 $SC_CONTEXTHELP = 0xF180 $SC_MAXIMIZE = 0xF030 $SC_MINIMIZE = 0xF020 $SC_TASKLIST = 0xF130 $SC_MOUSEMENU = 0xF090 $SC_KEYMENU = 0xF100 #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx $GWL_EXSTYLE = -20 $GWL_STYLE = -16 #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898(v=vs.85).aspx #WM_SETICON Message - http://msdn.microsoft.com/en-us/library/ms632643%28VS.85%29.aspx $WM_SETICON = 0x0080; $ICON_SMALL = 0; $ICON_BIG = 1; #Extended Window Styles $WS_EX_DLGMODALFRAME = 0x00000001L $WS_EX_NOACTIVATE = 0x08000000L $WS_EX_TOOLWINDOW = 0x00000080L $WS_EX_STATICEDGE = 0x00020000L $WS_EX_WINDOWEDGE = 0x00000100L $WS_EX_TRANSPARENT = 0x00000020L $WS_EX_CLIENTEDGE = 0x00000200L $WS_EX_LAYERED = 0x00080000 $WS_EX_TOPMOST = 0x00000008L #... http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx #Get window handle of Powershell process (Ensure there is only one Powershell window opened) $PSWindow = (Get-Process Powershell) | where {$_.MainWindowTitle -like "*Powershell*"} $hwnd = $PSWindow.MainWindowHandle #Get System menu of windows handled $hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0) #Window Style : TOOLWINDOW [Win32.NativeMethods]::SetWindowLongPtr($hwnd, $GWL_EXSTYLE, $WS_EX_TOOLWINDOW) | Out-Null #Disable X Button and window itself [Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_DISABLED) | Out-Null [Win32.NativeMethods]::EnableWindow($hwnd, 0) | Out-Null Try { [Console]::TreatControlCAsInput = $True # Header Information Write-Host "Random Password Generator" -ForeGroundColor Magenta Write-Host "Created on: 2/3/2016" -ForeGroundColor Magenta Write-Host "Author: Sean Martin" -ForeGroundColor Magenta Write-Host "" Write-Host "This script will generate a randomized 24 character password that meets existing complexity requirements." -ForeGroundColor Magenta Write-Host "---------------------------------------------------------------------------------------------------------" -ForeGroundColor Yellow # Generate Random Password $randombytes = new-object byte[] 15 (new-object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($randombytes) $pass = [System.Convert]::ToBase64String($randombytes) $a = ([char[]](get-random -input (33..47) -count 2)) -join "" $b = ([char[]](get-random -input (48..57) -count 2)) -join "" $password = $a + $pass + $b $password | clip # Display Password Write-Host "" Write-Host "Your password is: " -ForeGroundColor Cyan Write-Host "" Write-Host "$Password" -ForeGroundColor Yellow Write-Host "" Write-Host "The password has been automatically copied to the clipboard for your convenience." Write-Host "Please paste the password to a safe location as the clipboard will be cleared upon exit." Write-Host "" Write-Host "The script exit automatically in 10 seconds" -ForeGroundColor Cyan Start-sleep 10 # Clear Clipboard $null | clip } Finally { [Console]::TreatControlCAsInput = $False } #Enable X Button [Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_ENABLED) | Out-Null [Win32.NativeMethods]::EnableWindow($hwnd, 1) | Out-Null Exit ========== - Sean On Mon, Feb 8, 2016 at 7:25 AM, Sean Martin <[email protected]> wrote: > That is very cool. As much as I appreciate the mention, this is where I > came up with the concept: > > > https://gallery.technet.microsoft.com/scriptcenter/Simple-random-code-b2c9c9c9 > > - Sean > > On Fri, Feb 5, 2016 at 5:58 PM, Michael B. Smith <[email protected]> > wrote: > >> Ok. Here is my final version, and I’ll probably blog about it. J Great >> stuff. I love these kinds of conversations! >> >> >> >> -----start----- >> >> ## >> >> ## Create-Password >> >> ## >> >> ## February 5, 2016 >> >> ## michael at TheEssentialExchange dot com >> >> ## >> >> ## Based on an idea from Sean Martin >> >> ## seanmartin14 at gmail dot com >> >> ## >> >> >> >> Param( >> >> [int] $Length = 20, >> >> [bool] $AllPrintableAscii = $false >> >> ) >> >> >> >> function range >> >> { >> >> Param( >> >> [char] $start, >> >> [char] $finish >> >> ) >> >> >> >> [int]$start .. [int]$finish >> >> } >> >> >> >> ## ASCII table: >> >> ## >> https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters >> >> >> >> ## I intentionally exclude <space>, since if a space >> occurs as the first >> >> ## or last character, most password input dialogs will >> trim the <space>. >> >> >> >> $password = '' >> >> if( $AllPrintableAscii ) >> >> { >> >> $password = ( [char[]]( Get-Random >> -InputObject ( 33..126 ) -Count 20 ) ) -Join '' >> >> } >> >> else >> >> { >> >> $validChars = ( range 'a' 'z' ) + >> >> ( range 'A' >> 'Z' ) + >> >> ( range '0' >> '9' ) + >> >> ( [char[]] >> '!@#$%^&*()' ) >> >> >> >> $password = ( [char[]]( Get-Random >> -InputObject $validChars -Count 20 ) ) -Join '' >> >> } >> >> >> >> $password >> >> -----end----- >> >> >> >> *From:* [email protected] [mailto: >> [email protected]] *On Behalf Of *Michael B. Smith >> *Sent:* Friday, February 5, 2016 9:31 PM >> >> *To:* [email protected] >> *Subject:* RE: [powershell] Random Password Generator >> >> >> >> Here is the medium easier-to-understand version: >> >> >> >> function range { param( [char]$start, [char]$finish ) [int]$start .. >> [int]$finish } >> >> >> >> $validChars = ( range 'a' 'z' ) + ( range 'A' 'Z' ) + ( range '0' '9' ) + >> ( [char[]] '!@#$%^&*()' ) >> >> >> >> ( [char[]]( Get-Random -InputObject $validChars -Count 20 ) ) -Join '' >> >> >> >> >> >> *From:* [email protected] [ >> mailto:[email protected] <[email protected]>] *On >> Behalf Of *Michael B. Smith >> *Sent:* Friday, February 5, 2016 9:16 PM >> *To:* [email protected] >> *Subject:* RE: [powershell] Random Password Generator >> >> >> >> You can do that with this solution as well. >> >> >> >> Here is the long version: >> >> >> >> $upperCase = 65..90 >> >> $lowerCase = 97..122 >> >> $numbers = 48..57 >> >> $bang = , ( [char] '!' ) >> >> $splat = , ( [char] '@' ) >> >> $hash = , ( [char] '#' ) >> >> $dollar = , ( [char] '$' ) >> >> $percent = , ( [char] '%' ) >> >> $carat = , ( [char] '^' ) >> >> $amp = , ( [char] '&' ) >> >> $star = , ( [char] '*' ) >> >> $lparen = , ( [char] '(' ) >> >> $rparen = , ( [char] ')' ) >> >> >> >> $characters = $upperCase + $lowerCase + $numbers + $bang + $splat + $hash >> + $dollar + $percent + $carat + $amp + $star + $lparen + $rparen >> >> >> >> ( [char[]]( Get-Random -InputObject $characters -Count 20 ) ) -Join '' >> >> >> >> Here is the short version: >> >> >> >> [char[]] $validChars = 65..90 + 97..122 + 48..57 + ( [char[]] >> '!@#$%^&*()' ) >> >> ( [char[]]( Get-Random -InputObject $validChars -Count 20 ) ) -Join '' >> >> >> >> >> >> *From:* [email protected] [ >> mailto:[email protected] <[email protected]>] *On >> Behalf Of *Scott Crawford >> *Sent:* Friday, February 5, 2016 8:31 PM >> *To:* [email protected] >> *Subject:* RE: [powershell] Random Password Generator >> >> >> >> That’s fantastic. >> >> >> >> This had been my solution and I do kinda like seeing the actual valid >> characters cuz it makes it easy to edit out quotes or other possible >> illegal values. But, it’s tough to beat the elegance of yours when valid >> characters aren’t a concern. >> >> >> >> $Chars = >> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()" >> >> $Rand = New-Object System.Random >> >> For ($i = 1; $i -le 20; $i++) { >> >> $Password = $Password + $Chars.Substring($Rand.Next(0, >> $Chars.Length), 1) >> >> } >> >> $Password >> >> >> >> *From:* [email protected] [ >> mailto:[email protected] <[email protected]>] *On >> Behalf Of *Michael B. Smith >> *Sent:* Friday, February 5, 2016 7:07 PM >> *To:* [email protected] >> *Subject:* RE: [powershell] Random Password Generator >> >> >> >> Interestingly enough, you can take Get-Random and get an even better >> random password. Take a look at this: >> >> >> >> ( [char[]]( Get-Random -Input ( 33..126 ) -Count 20 ) ) -Join '' >> >> >> >> Great solution using all of the printable ASCII characters (except for >> the <space> character). >> >> >> >> *From:* [email protected] [ >> mailto:[email protected] <[email protected]>] *On >> Behalf Of *Michael B. Smith >> *Sent:* Thursday, February 4, 2016 3:39 PM >> *To:* [email protected] >> *Subject:* RE: [powershell] Random Password Generator >> >> >> >> That’s very nice. I never would have thought of that application of >> Get-Random. >> >> >> >> *From:* [email protected] [ >> mailto:[email protected] <[email protected]>] *On >> Behalf Of *Sean Martin >> *Sent:* Thursday, February 4, 2016 10:44 AM >> *To:* [email protected] >> *Subject:* Re: [powershell] Random Password Generator >> >> >> >> You make a good point. How about this? >> >> >> >> $randombytes = new-object byte[] 15 >> (new-object >> System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($randombytes) >> $pass = [System.Convert]::ToBase64String($randombytes) >> $a = ([char[]](get-random -input (33..47 + 48..57) -count 4)) -join "" >> $password = $a + $pass >> >> >> >> - Sean >> >> >> >> >> >> On Wed, Feb 3, 2016 at 6:36 PM, Michael B. Smith <[email protected]> >> wrote: >> >> The maximum entropy you get from Base64 is 2.58 bits per character, kinda >> by definition( ln2( 6 ) ). Given that your maximum length is 15 digits, >> that limits you to ~38 bits of entropy. At a thousand guesses a second, >> that’s about 8 years to brute force. Not bad. >> >> >> >> However, you’ve GIVEN UP over 10 bits of entropy because of four constant >> characters, taking you to about 28 bits of entropy. Believe it or not, >> having constants makes a password far far easier to crack. (This is why the >> revelation of a non-random non-prime in netcat/socat is such a big deal – >> it makes Diffie-Helman much much simpler to crack.) >> >> >> >> That’s about 3 days to brute force. >> >> >> >> That is completely believable for someone to spend the time/energy to >> crack. (And remember, the 3 days assumes that your password is the last one >> checked, out of the entire “password universe” – on average, assume half >> that.) >> >> >> >> So, the lesson here is that 15 bytes of base64 is fine (if impossible to >> remember). But don’t use constants. Evah. >> >> >> >> *From:* [email protected] [mailto: >> [email protected]] *On Behalf Of *Sean Martin >> *Sent:* Wednesday, February 3, 2016 3:24 PM >> *To:* [email protected] >> *Subject:* [powershell] Random Password Generator >> >> >> >> I don't get the opportunity to contribute all that often so I thought I >> would throw this out there in case it helps anyone. >> >> >> I got the method from this article: >> https://www.scriptjunkie.us/2013/09/secure-random-password-generation/ >> >> >> >> I modify the resulting password by prepending/appending a couple of >> special and numerical characters to ensure it meets complexity requirements >> in my current environment. >> >> >> >> Easy way to generate a secure password whenever the need arises. >> Critiques are always welcome. >> >> >> >> =================================================================== >> >> >> >> # Generate Random Password >> >> >> $randombytes = new-object byte[] 15 >> (new-object >> System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($randombytes) >> $pass = [System.Convert]::ToBase64String($randombytes) >> $password = "&#" + $pass + "82" >> >> >> Write-Host "" >> Write-Host "Your password is: " -ForeGroundColor Cyan -NoNewLine >> Write-Host "$Password" -ForeGroundColor Yellow >> Write-Host "" >> Write-Host "" >> Write-Host "Press enter to exit script..." -ForeGroundColor Cyan >> >> >> $Pause = Read-Host >> >> Exit >> >> >> >> ================================================================== >> >> >> >> - Sean >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> >> ================================================ >> Did you know you can also post and find answers on PowerShell in the >> forums? >> http://www.myitforum.com/forums/default.asp?catApp=1 >> > > > ================================================ > Did you know you can also post and find answers on PowerShell in the > forums? > http://www.myitforum.com/forums/default.asp?catApp=1 > ================================================ Did you know you can also post and find answers on PowerShell in the forums? http://www.myitforum.com/forums/default.asp?catApp=1
