I found a project on GitHub to generate and check tokens (TOTP). I tried to get it working but failed. Here is the code:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dev.samstevens.totp.code.CodeGenerator;
import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.code.DefaultCodeGenerator;
import dev.samstevens.totp.code.DefaultCodeVerifier;
import dev.samstevens.totp.code.HashingAlgorithm;
import dev.samstevens.totp.exceptions.CodeGenerationException;
import dev.samstevens.totp.exceptions.QrGenerationException;
import dev.samstevens.totp.qr.QrData;
import dev.samstevens.totp.qr.QrGenerator;
import dev.samstevens.totp.qr.ZxingPngQrGenerator;
import dev.samstevens.totp.secret.DefaultSecretGenerator;
import dev.samstevens.totp.secret.SecretGenerator;
import dev.samstevens.totp.time.SystemTimeProvider;
import dev.samstevens.totp.time.TimeProvider;
import dev.samstevens.totp.recovery.RecoveryCodeGenerator;
import static dev.samstevens.totp.util.Utils.getDataUriForImage;
/**
* Servlet implementation class TwoFactorAuthentication
*/
public class TwoFactorAuthentication extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TwoFactorAuthentication() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
//SecretGenerator secretGenerator = new DefaultSecretGenerator();
//String secret = secretGenerator.generate();
String secret = "XAFXRG3TNMLHENVAQTD5ZJOTC2MHTIVE";
QrData data = new QrData.Builder()
.label("[email protected]")
.secret(secret)
.issuer("PORTAL")
.algorithm(HashingAlgorithm.SHA256) // More on this below
.digits(6)
.period(60)
.build();
String code = request.getQueryString().replace("code=", "");
response.getWriter().append("\r\nCode: " + code);//.append(request.getContextPath());
TimeProvider timeProvider = new SystemTimeProvider();
CodeGenerator codeGenerator = new DefaultCodeGenerator(HashingAlgorithm.SHA256);
DefaultCodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
verifier.setTimePeriod(60);
verifier.setAllowedTimePeriodDiscrepancy(2);
// secret = the shared secret for the user
// code = the code submitted by the user
boolean successful = verifier.isValidCode(secret, code);
if (successful) System.out.println(successful);
response.getWriter().append("\r\nResult: " + successful);//.append(request.getContextPath());
try {
QrGenerator generator = new ZxingPngQrGenerator();
byte[] imageData = generator.generate(data);
String mimeType = generator.getImageMimeType();
String dataUri = getDataUriForImage(imageData, mimeType);
response.getWriter().append("\r\ndataUri: " + dataUri);//.append(request.getContextPath());
} catch (QrGenerationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
I generated the QR code using the project as you can see above, and scanned it to an authenticator app to generate tokens for me. Whatever code I give the form, the authenticator app fails. Can anyone explain to me what am I doing wrong here?
I ran into the same issue with Google Authenticator app recently. It turns out, some authenticator apps silently ignore the
period
anddigits
parameters from the URI. In case of Google Authenticator, it simply defaults to30
and6
, respectively.This causes code verification to fail, as the app generating the code and the verifying utility work with different parameters.