Generating a 20 character hex string with PowerShell

Tagged: , ,

This topic contains 11 replies, has 4 voices, and was last updated by Profile photo of Max Kozlov Max Kozlov 5 months ago.

  • Author
    Posts
  • #60451
    Profile photo of i255d
    i255d
    Participant

    I am working on generating JWT (Jason Web Tokens) for use with the API (Application Programming Interface) for Box. Box is a company that does "File sharing, storage and collaboration". I have created a small group of functions to work through automating the handling the accounts of employees that have left the company.

    In an effort to create a process that is entirely hands free, I need to be able to authenticate with Box's interface securely without being prompted. I may get into what a JST is an how it works after I get this all pulled together, but for right now, there are three pieces of data used in a JWT, the Header, Claims, and Signature, and they need to be serialized to UTF-8 bytes, then encoded using the Base64url encoding.

    One of the components of the Claims piece is the 'jti', which is a random hex string.

    One of the Box employees has written an example of how to do this in another language, with I am hoping will help someone to identify and show me how to do this in PowerShell.

    var sessionToken = crypto.randomBytes(20).toString('hex');
  • #60456
    Profile photo of Al
    Al
    Participant
    # generating 20 random bytes in hexadecimal form:
    
    1..20 | %{ '{0:X)' -f (Get-Random -Max 256) }
    

    ▪

  • #60457
    Profile photo of i255d
    i255d
    Participant

    I may not have been as clear as I need to be, in part, because I don't know much about hex.

    What I need is a string like:
    jti = "M4yeY3W63TxHa9jFek85"

    In the example above, once you correct the {0:X) with {0:X}, gives an array of numbers.
    And considering the output can be either one or two digits, it may produce a number that is a lot longer the 20 characters.

    At first I thought I would try something like this:

    $canString = ''
    foreach( $digit in (1..10 | foreach{ '{0:X}' -f (Get-Random -Max 256) })){
        $canString = "$canString" + "$digit"
    
    }
    $canString

    The problem with that is it would produce 14 to 20 characters.

  • #60463
    Profile photo of i255d
    i255d
    Participant

    In an effort to deal with the variable length above, I thought about creating a function with a group match that only took the first 20 characters.

    function Get-RandomHexString {
        param( [Int32]$Length = 20 )
        $hexArray = 1..$Length | foreach{ '{0:X}' -f (Get-Random -Max 256) } 
        "$hexArray".ToString().Replace(' ','') -match "(?\w{$Length})" | Out-Null
        $matches.digits
    }
    Get-RandomHexString

    The one question I still have is does this string have to be an actual hex, and is the output an actual hex?

    PS C:\EEDevOps> Get-RandomHexString
    BF40A8A7C61DE9AE6D2A

    PS C:\EEDevOps> Get-RandomHexString
    B4FFDF9D01D232D49407

    PS C:\EEDevOps> Get-RandomHexString
    5125678A4443AA854797

    PS C:\EEDevOps> Get-RandomHexString
    826F892B351C47F63F15

    PS C:\EEDevOps> Get-RandomHexString
    CEF169B1D4F91684242A

    PS C:\EEDevOps> Get-RandomHexString
    FFE4374E62E8AEC7EFA7

    PS C:\EEDevOps> Get-RandomHexString
    12792B482A34A2F6C909

  • #60466
    Profile photo of i255d
    i255d
    Participant

    Honestly, I thought someone would be able to show me how to use a .NET class or something to do this in one line.

    • #60487
      Profile photo of Ron
      Ron
      Participant
      (1..20 | %{ '{0:X}' -f (Get-Random -Max 16) }) -join ''
  • #60480
    Profile photo of i255d
    i255d
    Participant

    I talked with a couple of programmers where I work, and asked if they had any ideas on how to generate this with a built in class in Windows and they said yes, System.Security.Cryptography.

    I wrote this from what I could find. It isn't any shorter, and I am not sure it is working any better.

    function Get-RandomHexNumber{
        param( 
            [int] $length = 20,
            [string] $chars = "0123456789ABCDEF"
        )
            $bytes = new-object "System.Byte[]" $length
            $rnd = new-object System.Security.Cryptography.RNGCryptoServiceProvider
            $rnd.GetBytes($bytes)
            $result = ""
            1..$length | foreach{
                $result += $chars[ $bytes[$_] % $chars.Length ]    
            }
            $result
    }
    Get-RandomHexNumber -length 20
  • #60483
    Profile photo of i255d
    i255d
    Participant

    I talked with a couple of programmers at my office and they said they had done similar thing with System.Security.Cryptography.

    I wrote this function using this class, it is not any shorter, and I am not sure it is any better.

    I did learn a little more about what hex number are here:
    https://www.khanacademy.org/math/algebra-home/alg-intro-to-algebra/algebra-alternate-number-bases/v/hexadecimal-number-system

    function Get-RandomHexNumber{
        param( 
            [int] $length = 20,
            [string] $chars = "0123456789ABCDEF"
        )
            $bytes = new-object "System.Byte[]" $length
            $rnd = new-object System.Security.Cryptography.RNGCryptoServiceProvider
            $rnd.GetBytes($bytes)
            $result = ""
            1..$length | foreach{
                $result += $chars[ $bytes[$_] % $chars.Length ]	
            }
            $result
    }
    Get-RandomHexNumber -length 20
  • #60498
    Profile photo of Al
    Al
    Participant

    @i255d : your original question is, clearly, about bytes written as hexadecimal form. But, your 1st reply, changes that to something quite different.
    I guess, you want to have a look at Membership.GeneratePassword static method in Cryptography namespace. It will give you a string with random characters.
    ▪

  • #60522
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    your original string is not hexadecimal!
    hex digits – it's digits 0-9 and letters a-f, but mot M, y, W .... https://en.wikipedia.org/wiki/Hexadecimal

    and your string is base64 encoded some other string.
    at least i can decode it 🙂

     D:\> [Text.Encoding]::Default.GetString([Convert]::FromBase64String("M4yeY3W63TxHa9jFek85"))
    3ЊћcuєЭ
    

    and encoding is reverse process. for example:

     D:\> [Convert]::ToBase64String((1..15 | % {Get-Random -Minimum 0 -Maximum 256}))
    HQFPx55qXCWAw6NORdrN
    
  • #60571
    Profile photo of i255d
    i255d
    Participant

    Yes, as I have walked through this process, I figured out that for it to be a hex number, the characters had to be 0-F, and I did notice also, that the string given in the example by Box is not a hex number.

    I just went back to Box to see what the actual requirement is:
    jti required String A unique identifier specified by the client for this JWT. This is a unique string that is at least 16 characters and at most 128 characters.

    I guess it doesn't need to be a hex, I assumed that from the code one of their people said they used to get it:
    var sessionToken = crypto.randomBytes(20).toString('hex');

    Either way, I have finished with this part, an I am now going to open another question to figure out how to create the signature of the JWT.

  • #60622
    Profile photo of Max Kozlov
    Max Kozlov
    Participant

    20-character hexadecimal strings less unique than base64 with the same length 🙂

    it's decrypted into 10 bytes and 20 base64 characters decrypted into 15 bytes 🙂

You must be logged in to reply to this topic.