jchambers / java-otp

A one-time password (HOTP/TOTP) library for Java
MIT License
455 stars 122 forks source link

the result of below code is different with the one of google authenticator #19

Closed FrancisJen closed 3 years ago

FrancisJen commented 3 years ago
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Base64;

public class OTP {
    static TimeBasedOneTimePasswordGenerator totp;

    static {
        try {
            totp = new TimeBasedOneTimePasswordGenerator();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    final static Instant now = Instant.now();
    final static Instant later = now.plus(totp.getTimeStep());

    public OTP() throws NoSuchAlgorithmException {
    }

    public static String otpNow(String key) throws InvalidKeyException {
        // decode the base64 encoded string
        byte[] decodedKey = Base64.getDecoder().decode(key);
        // rebuild key using SecretKeySpec
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
        Integer code =  totp.generateOneTimePassword(originalKey, now);
        System.out.println(code);
        if(code.toString().length() < 6) {
            code = code * 10;
        }
        return code.toString();
    }

    public static Integer otpNow(Key key) throws InvalidKeyException {
        return totp.generateOneTimePassword(key, now);
    }

    public static Integer otpLater(Key key) throws InvalidKeyException {
        return totp.generateOneTimePassword(key, later);
    }

    public static String otpLater(String key) throws InvalidKeyException {
        // decode the base64 encoded string
        byte[] decodedKey = Base64.getDecoder().decode(key);
        // rebuild key using SecretKeySpec
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
        Integer code =  totp.generateOneTimePassword(originalKey, later);
        System.out.println(code);
        if(code.toString().length() < 6) {
            code = code * 10;
        }
        return code.toString();
    }

    public static void main(String[] args) throws InvalidKeyException {
        String key = "XX";
        System.out.println(OTP.otpNow(key));
    }
}
jchambers commented 3 years ago

I'm afraid there isn't really enough information here for me to identify a problem, but I do appreciate the effort to provide a reproduction case. What algorithm/code length is Google Authenticator using for this key?

Also, please note that this is incorrect:

if(code.toString().length() < 6) {
    code = code * 10;
}

return code.toString();

I recommend this instead (assuming your code length is 6):

return String.format("%06d", code);
jchambers commented 3 years ago

Closing due to lack of information.