passman
passman copied to clipboard
Unable to process TOTP
Bug report
Passman is unable to process TOTP.
Steps to reproduce
- Insert TOTP into Passman
NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYA
Expected behaviour
Passman outputs TOTP code
Actual behaviour
No code is generated
In the Chrome console I can see
framework.js:14327 String of HEX type must be in byte increments
(anonymous) @ framework.js:14327
Configuration
Operating system:
Browser:
Latest Chrome
Extensions that might cause interference: uBlock
Passman version: Latest
Operating system: Ubuntu Xenial
Web server: Nginx 1.12.1
Database: sqlite
PHP version: 7.1.3
cloud server: Nextcloud
cloud version: 11.0.2 (stable)
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
I'd just like to mention that Google Authenticator handle's this just fine
The reason that GAuth can read is that they use a different lib.
We use the llqrcode
lib for reading qrcodes. I think the lib has trouble reading your qr code.
@brantje Sorry, my bad. Here you go: (same as above)
Note to self: this lib works https://github.com/LazarSoft/jsqrcode
@brantje I just tested removing 2 last characters from the secret makes it present an OTP value again (incorrect but still). Perhaps the secret is to long for the decoder?
The mouse cursor in the image messes up the reading of the qr code
@brantje The cursor is there because I screenshoted the QR code. The secret I'm talking about is present just above the QR code in orignal post which I'm 100% diden't have any cursor when I uploaded it to passman.
Just create an new credential and upload the QR below as OTP to Passman and you'll see what I mean.
Hmmm both give different secrets. Think that will be solved once i switched the lib.
I have the same issue with Amazon.de. The QR code is recognised by passman and resolved to the identical secret. Passman however does not show me the 6 digit key. As it was the first OTP I wanted to use I tried the GitHub.com QR code and everything works fine and as expected.
Now that I switched from Chromium to Firefox I have that problem too :( Any chance to get it resolved soon as it's really boring ? :/
@vincegre so you say it depends on the browser?
I have the exact same problem. I uploaded the QR code from Amazon, which Passman resolved to the exact secret displayed on the Amazon website, but no secret is generated.
I tried inputing the secret by hand (or rather copy-pasting), and then a 6 digits secret is generated, but it doesn't validate on the Amazon website.
I'm experiencing the same issue. When I delete two characters from the end of the code, it appears to accept it visually (OTP is generated, timer starts counting down, etc.). It should be mentioned that the code from Amazon is 52 characters, and without the aforementioned two characters, is exactly 50 characters long. This seems like a hard limitation somewhere in Passman that is silently failing :thinking:
I encountered the same bug and decided to dig deeper:
Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.
With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.
As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.
The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.
The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:
--- passman-master/js/app/directives/otp.js 2018-02-04 02:27:24.000000000 +0100
+++ passman-mod/js/app/directives/otp.js 2018-02-04 14:53:48.360029328 +0100
@@ -53,10 +53,15 @@
bits += leftpad(val.toString(2), 5, '0');
}
+ for (i = i % 8; i > 0; i--) {
+ bits += leftpad('0', 5, '0');
+ }
+
for (i = 0; i + 4 <= bits.length; i += 4) {
var chunk = bits.substr(i, 4);
hex = hex + parseInt(chunk, 2).toString(16);
}
+
return hex;
}
The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.
edit: fixed patch
@alexw65500 workaround is working here, so the patch should work too :)
@alexw65500 Can confirm! The workaround is working great for Amazon!
I am also facing the same issue with Mastodon.
3mic y2hg uz5j 2p6s mnno elcn gpch n4sq
-> This is the secret and Passman generates wrong OTP everytime, I tested it with another app and it worked.
Update: I just tested it after removing the space between those characters and it worked! 3micy2hguz5j2p6smnnoelcngpchn4sq
-> This works with Passman
This is an interesting topic. I presume passman is using the jssha lib. We have experienced the same problem with a 52 character long base 32 string. But when I apply this workaround the jssha fails for base 32 strings of length 103 or 26 which worked previously. A string of length 32 functions with and without the workaround because it is a modulus of 8 so that makes sense. But to catch the other cases I cannot see what is the distinction as neither a length of 52 or 103 or 26 are divisible by 8 yet the padding fails for the 103 and 26 (dropbox by the way). Any ideas?
@alexw65500 - have you submitted this as a PR?
This should get fixed as it's still a problem, and the workaround above is valid.
@alexw65500 - have you submitted this as a PR?
No, the patch is super ugly and nothing I would merge as maintainer. That's basically the first time I used JS and it's just using the code around the problem for the fix with zero JS knowledge. So this is only a quick hack and it's not hard to do that better...
Just confirming that manually padding the value worked for me as well!
I encountered the same bug and decided to dig deeper:
Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.
With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.
As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.
The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.
The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:
--- passman-master/js/app/directives/otp.js 2018-02-04 02:27:24.000000000 +0100 +++ passman-mod/js/app/directives/otp.js 2018-02-04 14:53:48.360029328 +0100 @@ -53,10 +53,15 @@ bits += leftpad(val.toString(2), 5, '0'); } + for (i = i % 8; i > 0; i--) { + bits += leftpad('0', 5, '0'); + } + for (i = 0; i + 4 <= bits.length; i += 4) { var chunk = bits.substr(i, 4); hex = hex + parseInt(chunk, 2).toString(16); } + return hex; }
The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.
edit: fixed patch
The problem remains for me with Amazon (52 characters OTP code). I'm using Nextcloud 18.0.3 and Passman 2.3.5. The workaround mentioned above still solves the issue for now though (right padding with A). Has the official fix made it to production yet ? Is it released ? Thanks
The problem remains for me with Amazon (52 characters OTP code). I'm using Nextcloud 18.0.3 and Passman 2.3.5. The workaround mentioned above still solves the issue for now though (right padding with A). Has the official fix made it to production yet ? Is it released ? Thanks
You should pass at an other tool, passman is unhappy a dead project since a while :(
I encountered the same bug and decided to dig deeper:
Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.
With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.
As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.
The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.
The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:
--- passman-master/js/app/directives/otp.js 2018-02-04 02:27:24.000000000 +0100 +++ passman-mod/js/app/directives/otp.js 2018-02-04 14:53:48.360029328 +0100 @@ -53,10 +53,15 @@ bits += leftpad(val.toString(2), 5, '0'); } + for (i = i % 8; i > 0; i--) { + bits += leftpad('0', 5, '0'); + } + for (i = 0; i + 4 <= bits.length; i += 4) { var chunk = bits.substr(i, 4); hex = hex + parseInt(chunk, 2).toString(16); } + return hex; }
The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.
edit: fixed patch
Really thanks. It works! Have a nice day.
Issue can be closed fix with #649