Code Monkey home page Code Monkey logo

java-otp's People

Contributors

jchambers avatar valfirst avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-otp's Issues

JPMS module

Can you add a module-info.java or make this project an automatic module? I can't use it in my modular application otherwise.

NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer

The following code as is from test ExampleApp.java returns error:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer;
	at com.eatthepath.otp.HmacOneTimePasswordGenerator.generateOneTimePassword(HmacOneTimePasswordGenerator.java:140)
	at com.eatthepath.otp.TimeBasedOneTimePasswordGenerator.generateOneTimePassword(TimeBasedOneTimePasswordGenerator.java:143)
	at com.eatthepath.otp.TimeBasedOneTimePasswordGenerator.generateOneTimePasswordString(TimeBasedOneTimePasswordGenerator.java:175)
	at com.eatthepath.otp.TimeBasedOneTimePasswordGenerator.generateOneTimePasswordString(TimeBasedOneTimePasswordGenerator.java:160)
	at simple.ExampleApp.main(ExampleApp.java:30)
package simple;

import javax.crypto.KeyGenerator;

import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;

public class ExampleApp {
    public static void main(final String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator();

        final Key key;
        {
            final KeyGenerator keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm());

            // Key length should match the length of the HMAC output (160 bits for SHA-1, 256 bits
            // for SHA-256, and 512 bits for SHA-512).
            keyGenerator.init(160);

            key = keyGenerator.generateKey();
        }

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

        System.out.println("Current password: " + totp.generateOneTimePasswordString(key, now));
        System.out.println("Future password:  " + totp.generateOneTimePasswordString(key, later));
    }
}

java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer;

Hello.
Recently I have this java.lang.NoSuchMethodError on:

at com.eatthepath.otp.HmacOneTimePasswordGenerator.generateOneTimePassword(HmacOneTimePasswordGenerator.java:140)
	at com.eatthepath.otp.TimeBasedOneTimePasswordGenerator.generateOneTimePassword(TimeBasedOneTimePasswordGenerator.java:143)

I guess this is something related to the latest Java 1.8 updated version. Currently I am using:

openjdk version "**1.8.0_312**"
OpenJDK Runtime Environment (Temurin)(**build 1.8.0_312-b07**)
OpenJDK 64-Bit Server VM (Temurin)(build 25.312-b07, mixed mode)

Downloaded on https://adoptium.net/?variant=openjdk8 .

Curiously this wasn't happening on previous Java 1.8 update version.

I am trying to get more information about it and will update this issue as soon as I have, however could you please take a look on this? Perhaps we have more people facing same issue.

This is the version I am using, which I believe is the latest one:

<dependency>
	<groupId>com.eatthepath</groupId>
	<artifactId>java-otp</artifactId>
	<version>0.3.0</version>
</dependency>

Thanks in advance.

Secret key issue

I've got my secret key as a string. How can I use thid code without creating a Key object ?

Release 0.1 not supported

Hello,

according to your README.md Release 0.1 is no longer supported but it is the only release available.
Do you plan release a new version anytime soon or should I vendor/submodule/subtree your repo?

Thanks

Issue with leading 0's

I have small question. Because the return type is int, the leading 0's are being dropped. This is being an issue for in the long run as the otp that is being shown is only 5 digits.

Now, can the return type be an String so that the user does not worry about the leading 0's. Personally, we had to waste a lot of time only to come to this conculsion.

Using a secret

Hello,
Given that TOTP needs a shared secret string, how will you generate the code using your library starting from a string? I am planning to embed your library in an app where the user will have another TOTP compliant app to generate the user code that will be compared against the TOTP created by your library. In your example usage you start with a random key.
Any chance you could create an example that starts with a string as a shared secret?

thanks

Handle NoSuchAlgorithmException exceptions for required algorithms

The documentation of the Mac class requires that every Java platform supports the following algorithms:

  • HmacMD5
  • HmacSHA1
  • HmacSHA256

What do you think about adding static factory methods (or changing the existing constructors) to catch NoSuchAlgorithmException for these algorithms and wrap them inside some unchecked exceptions? Since these algorithms will always be available (unless the JVM is incorrectly configured?) the user currently has to deal with exceptions which can never occur.

OTP Code validation problem

HI ,

I have generated the otp using java-otp.jar file , trying to validate the generated otp code using otp.verify ( which is part otp-java.3.2.1) . Below is the sample code.

Note: I am using java7

I have a server which uses TOTP builder and built with java 8 .
I have a client build with java 7 , To get the access , i have used "TimeBasedOneTimePasswordGenerator".
Is it right approach to use the otp code generated with generateOneTimePassword() and validate with totp.verify(TOTP.Builder(x).build and then with totp.verify()?

Could you please help me , what is the wrong in the below code

import com.bastiaanjansen.otp.HMACAlgorithm;
import com.bastiaanjansen.otp.TOTP;
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.UndeclaredThrowableException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;

import java.time.Duration;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base32;

import static com.eatthepath.otp.TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA512;
import static java.util.concurrent.TimeUnit.SECONDS;

public class Checktotp {

// Coverting the Secret Key to String

public static String convertSecretKeyToString(SecretKey secretKey) throws NoSuchAlgorithmException {
    byte[] rawData = secretKey.getEncoded();
    String encodedKey = Base64.getEncoder().encodeToString(rawData);
    System.out.println("ALG USed" + secretKey.getAlgorithm());
    System.out.println("Format is " + secretKey.getFormat());
    return encodedKey;
}

// Converting the String to Secret Key
public static SecretKey convertStringToSecretKeyto(String encodedKey) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException {

    byte[] decodedKey =  Base64.getDecoder().decode(encodedKey); //encodedKey.getBytes();
    SecretKey originalKey = new SecretKeySpec(encodedKey.getBytes(), 0,decodedKey.length ,"AES");
    return originalKey;
}

public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, UnsupportedEncodingException {


    TOTP totp_latest;
    final SecretKey key;
    String sec =  "RktZUlBCNUQyUU5ERVlRWkY2WE9XQkY3TUU0REw1Q1NZRlZOQkZUQkdaUUVEVUNOU1I1UlpHWlQ3MlFDVDVFUUFJSUZMVzMzR09TRTQ1S1pCVURaUlJTNklLRUI2RFIzV1hFSVJQWT0";
    key = convertStringToSecretKeyto(sec);
    byte[] secret1 = Base64.getDecoder().decode(sec);
    totp_latest = new TOTP.Builder(secret1)
            .withPasswordLength(6)
            .withAlgorithm(HMACAlgorithm.SHA512)
            .withPeriod(Duration.ofSeconds(10))
            .build();

// Generating the otp using otp-java-1.3.2
totp_latest.now();
System.out.println("OTP Code with Latest Jar File otp-java-1.3.2 " + totp_latest.now());

// Generating the otp using java-otp-0.1.0 .jar
String code1 = otpNow(sec);
System.out.println("OTP Code with old Jar File java-otp.0.1.0.jar " + code1);

    if ( totp_latest.verify(code1)) {
        System.out.println("The OTP is matched ");
    }
    else {
        System.out.println("OTP Code is Not Matched");
    }





}


public static String otpNow(String key) throws InvalidKeyException, NoSuchAlgorithmException {
    // decode the base64 encoded string
    byte[] decodedKey = Base64.getDecoder().decode(key);

    // rebuild key using SecretKeySpec
    SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");

    final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator(30, SECONDS,   6, TOTP_ALGORITHM_HMAC_SHA512);
    final Date now = new Date();


    String code = String.valueOf(totp.generateOneTimePassword(originalKey,now ));


    return code;
}

}

Only one empty TimeBasedOneTimePasswordGenerator constructor available

new TimeBasedOneTimePasswordGenerator() - works ok
new TimeBasedOneTimePasswordGenerator(Duration d) - the constructor is undefined
new TimeBasedOneTimePasswordGenerator(Duration d, int passLength) - the constructor is undefined
new TimeBasedOneTimePasswordGenerator(Duration d, int passLength, String hmacAlgo) - the constructor is undefined

running on v 0.3.0

Time step is not always honored

Java version:

openjdk 17.0.3 2022-04-19
OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.22.04.1)
OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.22.04.1, mixed mode, sharing)

Library version: 0.3.1
OS: Ubuntu Linux

I have had issues with the library not being consistent in how long time intervals are handled.

In my use case, I need to have the time interval valid for 15 minutes. In some cases it generates the correct code for the entire 15 minute interval, in other cases the code is only valid for 5 minutes before another code is generated.

Here is the code I am using:

var key = getKey(emailAddress);
var now = Instant.now();
var otp = otpGenerator.generateOneTimePasswordString(key, now);

logger.info(String.format("Time Step is: %d", otpGenerator.getTimeStep().getSeconds()));
logger.info(String.format("Code for 0 seconds: %s", key));
logger.info(String.format("Code for 60 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(60))));
logger.info(String.format("Code for 120 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(120))));
logger.info(String.format("Code for 180 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(180))));
logger.info(String.format("Code for 240 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(240))));
logger.info(String.format("Code for 300 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(300))));
logger.info(String.format("Code for 360 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(360))));
logger.info(String.format("Code for 420 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(420))));
logger.info(String.format("Code for 480 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(480))));
logger.info(String.format("Code for 540 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(540))));
logger.info(String.format("Code for 600 seconds: %s", otpGenerator.generateOneTimePassword(key, now.plusSeconds(600))));

And this is one of the cases where I have called it and it generated a different code. Notice in this case, the message that indicates a new key was created so it isn't the case that this was the same key as a previous instance (and yes, I am aware of the typo in the first print statement that is trying to print the key instead of the code).

(image removed and added in a different comment)

TOTP Generating different value with a particular timestep

I have the following code setup for testing the library

final Key key;
final KeyGenerator keyGenerator = KeyGenerator.getInstance(TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA512);

keyGenerator.init(512);

key = keyGenerator.generateKey();

TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator(Duration.ofSeconds(30), 6, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA512);

System.out.format("Time: %d Password:  %06d\n", Instant.now().getEpochSecond(), totp.generateOneTimePassword(key, Instant.now()));
			Thread.sleep(15 * 1000);
System.out.format("Time: %d Password:  %06d\n", Instant.now().getEpochSecond(), totp.generateOneTimePassword(key, Instant.now()));
			Thread.sleep(14 * 1000);
System.out.format("Time: %d Password:  %06d\n", Instant.now().getEpochSecond(), totp.generateOneTimePassword(key, Instant.now()));

Technically all the tree totp codes should be identical right ?

project to gradle| Jar

Hi, friend, it would be great if this project was available to use as a dependency on Gradle to use it on Android or the JAR. I made a fork in this project to make that feature possible, but now I do not have much time. However, if you can add that functionality before I have more time available, it would be fabulous. Since I am short of time I will have to copy your classes and add them to my project .

HOTP generator return zero otp code

Hi! I catch strange issue, i get from generator zero otp code with current counter 22165.

I attaching a reproducible example with a key.

import com.eatthepath.otp.HmacOneTimePasswordGenerator;
import org.apache.commons.codec.binary.Base32;
import org.junit.Assert;
import org.junit.Test;

import javax.crypto.spec.SecretKeySpec;

public class HotpZeroValueTest {

  private static final String KEY = "ANGNYSN4D3IZV523MRTXNRJU647E7R64";

  @Test
  public void test1() throws Exception {
    Base32 base32 = new Base32(false);
    HmacOneTimePasswordGenerator hotpGenerator = new HmacOneTimePasswordGenerator(6);
    SecretKeySpec key = new SecretKeySpec(base32.decode(KEY), HmacOneTimePasswordGenerator.HOTP_HMAC_ALGORITHM);

    int otpCode = hotpGenerator.generateOneTimePassword(key, 22164);
    Assert.assertEquals(100637, otpCode);
    otpCode = hotpGenerator.generateOneTimePassword(key, 22166);
    Assert.assertEquals(607204, otpCode);
    otpCode = hotpGenerator.generateOneTimePassword(key, 22165);
    Assert.assertEquals(0, otpCode);
  }
}

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

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));
    }
}

Import secrets

I didn't find any examples how to import secrets. Since I wrote an example which works for me, I wanted to share it.

Here it says that the secret key is encoded with base32, so the kotlin code looks like following:

val key = SecretKeySpec(Base32().decode("<YOUR-SECRET>"), "RAW")

I hope it's ok to share this. I think the best would be to show this example in README.

When first digit of generated pin is 0, it is being handled as octal number

As the title says, there are some times when the first digit of the randomly generated One Time Pin is 0. In those cases, Java handles the integer as octal, and the generateOneTimePassword method returns the decimal value of the octal number generated.

For example, if generateOneTimePassword generates 012345 (6 digits), it will return the integer 5349 (4 digits), which is the decimal representation of the octal 012345.

Related issues:
#14
#4

Workaround, as stated in issue #14 :

String oneTimePasswordString = String.format("%06d", oneTimePassword);

Publish artifact to Maven

I tried to look for this library in Maven, but I cannot find it. It would be super handy to quickly include the library into Maven or Gradle based projects. Any plan to publish it to any Maven repository?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.