Secure OTP generation in Java

Carvia Tech | July 25, 2020 | 2 min read | 0 views


In this article we will learn how to generate a cryptographically strong OTP in Java using SecureRandom class.

Issue with Random/ThreadLocalRandom

Random and ThreadLocalRandom based implementation are not cryptographically strong, so a hacker might get an opportunity to guess the OTP based on some previous OTP generated by the system.

An insecure implemenation will look like below:

Cryptographically poor implementation for OTP generation
import java.util.concurrent.ThreadLocalRandom;

public String generateInsecure(int maxLength, String allowedChars) {
    ThreadLocalRandom random = ThreadLocalRandom.current();
    final StringBuilder otp = new StringBuilder(maxLength);
    for (int i = 0; i < 8; i++) {
        otp.append(allowedChars.charAt(random.nextInt(allowedChars.length())));
    }
    return otp.toString();
}

OtpGenerator otpGenerator = new OtpGenerator();
String otpInsecure = otpGenerator.generateInsecure(8, "123456789");
System.out.println(otpInsecure);

A more secure way is to use SecureRandom instead of java.util.Random or java.util.concurrent.ThreadLocalRandom for the security purpose.

Using SecureRandom

SecureRandom class provides a cryptographically strong random number generator (RNG). We will develop a small OTP generator that uses SecureRandom.

Secure and Safe OTP generation
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class OtpGenerator {

    private final SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); (1)

    public OtpGenerator() throws NoSuchAlgorithmException {
    }

    public String generate(int maxLength) {
        final StringBuilder otp = new StringBuilder(maxLength);
        for (int i = 0; i < maxLength; i++) {
            otp.append(secureRandom.nextInt(9));
        }
        return otp.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        OtpGenerator otpGenerator = new OtpGenerator();

        String otp1 = otpGenerator.generate(8);
        System.out.println(otp1);
    }
}
1 SecureRandom instance is thread-safe and can be used by multiple threads concurrently.

If you have a constraint of using selected characters inside OTP, then the current version can be tweaked a bit to allow character selection.

using selected characters in OTP
public String generate(int maxLength, String allowedChars) {
    final StringBuilder otp = new StringBuilder(maxLength);
    for (int i = 0; i < maxLength; i++) {
        otp.append(allowedChars.charAt(secureRandom.nextInt(allowedChars.length())));
    }
    return otp.toString();
}

...
String otp2 = otpGenerator.generate(8, "123456789ABCDE");
System.out.println(otp2);

Thats' all.


Top articles in this category:
  1. Allow insecure SSL in Java 11 HttpClient
  2. Generate Random Numbers in a range using Java 8
  3. HmacSHA256 Signature in Java
  4. Precision and scale for a Double in java
  5. can we write a java method that swaps two integers
  6. Diamond Problem of Inheritance in Java 8
  7. Is Java Pure Object Oriented Language?


Find more on this topic:
Core Java image
Core Java

Core Java - OOP Concepts, Garbage Collection, Multi-threading, Collections Framework, Java 8 Features, Lambda Functions, Streams.

Last updated 1 week ago


Recommended books for interview preparation:

This website uses cookies to ensure you get the best experience on our website. more info