Hey,
I’m currently doing some testing with two-factor authentication.
For this I wrote a test script in Java to create a totp from an existing key.
I used the library “dev.samstevens.totp”.
The script works so far and I wanted to test it now in Lucee.
Unfortunately the lucee returns wrong totps. However, the time is correct when testing, so I don’t know what else it could be.
If I set the commandbox to Adobe 2021 the correct ones (like in the Java testscript) come out.
So the code works when running directly with java or adobe 2021, only on lucee it returning wrong results.
The only real dependency the library has is “Commens-Codec”. However, I included that in my test jar. Maybe the old “Commens-Codec” is loaded from the Lucee again, which has a bug?
Do any of you already have 2FA running or use this library?
My Code:
Java:
public static String generate(String secret) throws CodeGenerationException, UnknownHostException {
TimeProvider timeProvider = new NtpTimeProvider("pool.ntp.org");
CodeGenerator codeGenerator = new DefaultCodeGenerator();
long currentBucket = Math.floorDiv(timeProvider.getTime(), 30);
return codeGenerator.generate(secret, currentBucket);
}
Yep with 5.3.9-RC2 its working.
It seems to be a problem which commons-codec Base32 which was fixed in 1.10.
Is there a way that my library uses that version instead of 1.9? Or do i have to wait for the lucee 5.3.9 release?
Currently my “TotpTest-0.1.0-jar-with-dependencies.jar” included commons codec 1.15 but it seems lucee still uses the bundled version.
You really shouldn’t need a java library with dependencies to do TOTP… In the past I did it using the java crypt functions directly, some java.math.* stuff… The only part that needed a java library was generating a QR code image.
It’s probably even easier nowadays since CF10 added HMAC functions.
The part in the cfc that does hmac can be modified:
i.e. line 84
var key = base32decode(arguments.base32Secret);
var secretKeySpec = createObject("java", "javax.crypto.spec.SecretKeySpec" ).init(key, "HmacSHA1");
var mac = createObject("java", "javax.crypto.Mac").getInstance(secretKeySpec.getAlgorithm());
mac.init(secretKeySpec);
var buffer = createObject("java", "java.nio.ByteBuffer").allocate(8);
buffer.putLong(arguments.counter);
var h = mac.doFinal(buffer.array());
becomes something like
var key = base32decode(arguments.base32Secret);
var buffer = createObject("java", "java.nio.ByteBuffer").allocate(8);
buffer.putLong(arguments.counter);
var h = BinaryDecode( hmac( buffer.array(), key, "HMACSHA1" ) , "hex" );
The buffer part can probably be done with binarydecode as well.