Exercise 10: Secure Randomness in Python & Java

This exercise gives you practice at generating pseudorandom numbers securely using the facilities offered by the standard libraries of Python and Java. If you are doing this on your own PC, there is nothing else to install, beyond having working installations of Python 3 and the JDK.

Python

Note: the first of the tasks below can be done in Linux, WSL 2 or macOS, but not in a native Windows environment.

  1. Open a terminal window and run the Python REPL. Then try this:

    >>> f = open("/dev/urandom", "rb")
    >>> f.read(16).hex()
    

    The first of these lines opens the file-like object /dev/urandom for reading of binary data. Unix-inspired operating systems like Linux and macOS expose a range of services to users through interfaces based in the filesystem. /dev/urandom is the particular filesystem interface from which we can can obtain cryptographically strong pseudorandom numbers generated by the OS1.

    The second line reads 16 bytes from the opened file, then returns these bytes as a printable string of hex digits. Try repeating this line a few times to satisfy yourself that a different, seemingly random sequence of bytes is produced each time.

  2. In a Python REPL, use the secrets module to achieve the same result as the previous task:

    >>> import secrets
    >>> secrets.token_hex(16)
    

    This is simpler than the previous approach and also has the benefit of being cross-platform2. Again, try repeating the call to the token_hex() function a few times to satisfy yourself that the output changes randomly.

  3. In the same Python REPL that was used for the previous task, try this:

    >>> secrets.token_urlsafe(16)
    

    The token_urlsafe() function is similar to token_hex() but it uses Base64 encoding for the random bytes instead of hexadecimal. This scheme produces a shorter output string, averaging 1.3 characters per byte instead of 2 – making it more convenient for use in web applications where you need to generate a random URL.

  4. Look at the Recipes and Best Practices section of the API documentation for secrets. This gives three examples of using the module to generate random passwords. Implement one of these examples as a Python program and test it.

Java

  1. In your favourite editor or IDE, write a Java program that generates 16 random bytes (suitable for use as a key or IV in AES, for example) and then writes these bytes to a binary file. Use the SecureRandom class from the java.security package for this – see the API documentation for further details. For a simple way of writing the bytes out to a file, see the exercise on Symmetric Ciphers in Java.

  2. Compile and run your program, then examine the contents of the file.

    Note that most text editors can’t be used to view binary files like this in a helpful way, but if you use VSCode then you could install the Hex Editor extension to do this. On Linux or macOS you could also use the xxd tool from the command line to do a hex dump of the file. If all else fails, you could upload the file to an online hex viewer.

    Run the program and examine its output a few more times to satisfy yourself that the output changes in a random fashion.


  1. In fact, there are two such interfaces: /dev/random and /dev/urandom. The differences between these are subtle and often misunderstood, thanks to misleading and outdated documentation↩︎

  2. On Windows, it will use the BCryptGenRandom system call of that OS, rather than accessing /dev/urandom↩︎