Generating a 20 character hex string with PowerShell

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');
# generating 20 random bytes in hexadecimal form:

1..20 | %{ '{0:X)' -f (Get-Random -Max 256) }

:black_small_square:

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.

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

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

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

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
(1..20 | %{ '{0:X}' -f (Get-Random -Max 16) }) -join ''

@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.
:black_small_square:

your original string is not hexadecimal!
hex digits - it’s digits 0-9 and letters a-f, but mot M, y, W … Hexadecimal - Wikipedia

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

 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

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.

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

it’s decrypted into 10 bytes and 20 base64 characters decrypted into 15 bytes :slight_smile:

The original question is to generate a 20 bytes random key, not characters. 20 bytes, is a 160-bit key. The suggested minimum of 16 bytes is because it’s 128-bit and considered sufficient entropy according to the OWASP project.

Depending on the serialization method, it could generate various lengths when serialized to a string of text.
For instance hexadecimal, or base64url, or Ascii85.

To generate a hex string in PowerShell based on bits you could use the following code:

function Get-RandomHex {
    param(
        [int] $Bits = 256
    )
    $bytes = new-object 'System.Byte[]' ($Bits/8)
    (new-object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes)
    (new-object System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary @(,$bytes)).ToString()
}

Get-RandomHex -Bits 160

Example output:

2E0DF234643789B48A09CDDB471B860BCAB929EE

Note that this uses a cryptographic provider to ensure true randomness. The script doesn’t work when the bits cannot be divided by 8.

Warning: Other solutions in this thread with the … operator may not generate results that are the full length in defined bits.

I don’t know what brought you to this Bart, but I am grateful for your response. I would like to learn more about how these pieces work and how I could use PowerShell to create things like certs. So what brought this old post to your attention?