SoFunction
Updated on 2025-04-11

Java implements OTP (dynamic password) service

What is OTP?

The full name of OTP is One-Time Password, which is often called "one-time password" or "dynamic password" in Chinese. It is a dynamically generated short-term valid password for authentication, often providing additional security when logging in or performing sensitive operations. OTP is widely used in mainstream platforms such as Google, Microsoft, and GitHub to enhance the security of user accounts.

Features of OTP include:

  • One-time use: Each password can only be used once and cannot be repeated.
  • Timeliness: The password is valid for a short period of time and cannot be used after expiration.
  • Dynamic generation: Passwords are generated dynamically based on time or counter.

The principle of OTP generation

There are two common OTP implementation standards:

  • HOTP(HMAC-Based One-Time Password): Counter-based OTP.

  • TOTP(Time-Based One-Time Password): Time-based OTP.

TOTP is the most widely used standard at present. It uses the shared secret key and the current time as input, and combines the HMAC-SHA1 algorithm to generate a short digital password. Here are the main steps of TOTP:

  • Divide the current timestamp by the time step (for example, 30 seconds) to get the time index.

  • The HMAC algorithm is used to calculate the hash value of the time index.

  • Extracts the dynamic offset of the hash value and generates a 6-bit or 8-bit digital password.

Implement OTP service in Java

The following is a Java-based OTP service implementation that supports generation and verification of OTP.

Introduce dependencies

On the projectAdd the following dependencies to the file:

<dependencies>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version>
    </dependency>
</dependencies>

Implement OTP generation logic

The following code implements time-based TOTP generation and verification functions:

import ;
import ;
import .Base32;
import ;
import ;

import ;
import ;

public class OtpService {

    private static final int TIME_STEP = 30; // Time step (seconds)    private static final int OTP_LENGTH = 6; // OTP length    private static final int MAX_ATTEMPTS = 5; // Maximum number of attempts    private static final long BLOCK_DURATION = 300_000; // Block time (milliseconds)
    private final ConcurrentHashMap&lt;String, AtomicInteger&gt; attemptCounter = new ConcurrentHashMap&lt;&gt;();
    private final ConcurrentHashMap&lt;String, Long&gt; blockedUsers = new ConcurrentHashMap&lt;&gt;();

    // Generate TOTP    public String generateTOTP(String secret) throws Exception {
        long timeIndex = ().getEpochSecond() / TIME_STEP;
        return generateOtp(secret, timeIndex);
    }

    // Verify TOTP    public boolean validateTOTP(String secret, String otp, String userId) throws Exception {
        if (isBlocked(userId)) {
            ("User is temporarily blocked: " + userId);
            return false;
        }

        long timeIndex = ().getEpochSecond() / TIME_STEP;

        // Check OTP in the verification window        for (int i = -1; i &lt;= 1; i++) {
            String generatedOtp = generateOtp(secret, timeIndex + i);
            if ((otp)) {
                resetAttempts(userId);
                return true;
            }
        }

        recordFailedAttempt(userId);
        return false;
    }

    private String generateOtp(String secret, long timeIndex) throws Exception {
        // Decode Base32 key        Base32 base32 = new Base32();
        byte[] keyBytes = (secret);

        // Conversion time index is a byte array        byte[] timeBytes = (8).putLong(timeIndex).array();

        // Generate hash using HMAC-SHA1        Mac mac = ("HmacSHA1");
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "HmacSHA1");
        (keySpec);
        byte[] hash = (timeBytes);

        // Extract dynamic offsets        int offset = hash[ - 1] &amp; 0x0F;
        int binary = ((hash[offset] &amp; 0x7F) &lt;&lt; 24) | ((hash[offset + 1] &amp; 0xFF) &lt;&lt; 16)
                | ((hash[offset + 2] &amp; 0xFF) &lt;&lt; 8) | (hash[offset + 3] &amp; 0xFF);

        // Generate OTP        int otp = binary % (int) (10, OTP_LENGTH);
        return ("%0" + OTP_LENGTH + "d", otp);
    }

    private void recordFailedAttempt(String userId) {
        (userId, new AtomicInteger(0));
        int attempts = (userId).incrementAndGet();

        if (attempts &gt;= MAX_ATTEMPTS) {
            (userId, ());
            ("User blocked due to multiple failed attempts: " + userId);
        }
    }

    private void resetAttempts(String userId) {
        (userId);
        (userId);
    }

    private boolean isBlocked(String userId) {
        Long blockTime = (userId);
        if (blockTime == null) {
            return false;
        }

        if (() - blockTime &gt; BLOCK_DURATION) {
            (userId);
            return false;
        }
        return true;
    }
}

Testing Services

Here is an example of generating and validating OTP using the above OTP service:

public class OtpServiceTest {
    public static void main(String[] args) throws Exception {
        OtpService otpService = new OtpService();

        // Use Base32 encoding key        String secret = "JBSWY3DPEHPK3PXP";
        String userId = "user123";

        // Generate OTP        String otp = (secret);
        ("Generated OTP: " + otp);

        // Try to verify OTP        for (int i = 0; i &lt; 7; i++) {
            boolean isValid = (secret, otp, userId);
            ("Attempt " + (i + 1) + ": Is OTP valid: " + isValid);
        }
    }
}

Optimization suggestions

Security

  • Use a secure random number generator to generate a shared key.

  • Transfer data over HTTPS to prevent man-in-the-middle attacks.

Time synchronization

  • Time between the client and the server must be synchronized, otherwise OTP verification may fail.

Prevent violent cracking

  • Increases the number of failed attempts limit and blocking mechanism.

Production environment

  • Securely store shared keys in the database to avoid leakage.

  • Implement rate limiting to prevent brute-breaking attacks.

This article introduces the basic principles of OTP and implements a simple OTP service through Java, which is compatible with mainstream applications such as Google Authenticator and Microsoft Authenticator. OTP technology provides users with additional authentication security through dynamic passwords, and is one of the most reliable two-factor authentication technologies at present.

This is the end of this article about Java implementing OTP (dynamic password) service. For more related Java OTP dynamic password content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!