Length of secret? #10
-
Am I missing something? I'm looking to migrate a project from an outdated authenticator library to chillerlan/php-authenticator. From the read me:
So it seems the secret can still be 16 characters. However, when I set the secret length to 16; and generate a secret using the Am I missing something or am I confused somewhere? I'd like to re-use the existing secrets for now. |
Beta Was this translation helpful? Give feedback.
Replies: 11 comments
-
The secret length is the actual length of the binary secret string (which is used internally), not its base32 encoded representation. |
Beta Was this translation helpful? Give feedback.
-
So with the current version of the library, can we still have a base32 encoded representation that results in only 16 characters (as in the example from the read me)? |
Beta Was this translation helpful? Give feedback.
-
The minimum length for a secure secret string is 128 bits (with 160 bits recommended), that's why the lower limit is set to 16 bytes - shorter secret strings could compromise the security and are therefore not allowed to be created. However, nothing stops you from feeding a shorter secret to the (I think the secret string in the exampple was shortened and is not a representation for actual values) |
Beta Was this translation helpful? Give feedback.
-
Thanks, good to know. I'm trying to migrate away from this library. It also seems to use the minimum of 16 bytes. But there I do end up with a 16-character secret (similar to the demo URI from your read me). I believe it uses the same function to generate the 16 bytes. Is this then related to how your library currently encodes the secret? |
Beta Was this translation helpful? Give feedback.
-
Yea, the initial version of my library was "inspired" by that one, but over time I found out that several things were badly implemented. The secret phrase and the handling thereof is one of those - it converts the binary to base32 characters (which results in a base32 string with the same length as the secret) instead of properly base32 encoding the whole binary string, which as you have learned, results in a much longer string. So it's highly suggested to somehow migrate away from those short secrets as they're highly insecure. You might notice that both libraries generate different OTP codes with the same base32 secret. |
Beta Was this translation helpful? Give feedback.
-
Thanks for taking your time for the detailed explanation! :) "You might notice that both libraries generate different OTP codes with the same base32 secret." - I'm surprised; I'll check out then if some of the codes generated by e.g. Microsoft Authenticator or other authenticators are still accepted if I try to validate them with your library after using ´setSecret()´ |
Beta Was this translation helpful? Give feedback.
-
To be fair, I haven't checked this other library in a long time and it might have been fixed in the meantime, but back then i found out when I added the tests that check against the vectors provided in the RFC documents. |
Beta Was this translation helpful? Give feedback.
-
I can confirm your library does accept the secret key (16 characters) generated by the other library. The other library also generates 16 random bytes; and then seems to create a base32 encoded string of 16 characters based on that. That may indeed be flawed, or perhaps there's just a lot of confusion on this specification? For example, some online TOTP generators also end up displaying a 16 character secret? Example:
|
Beta Was this translation helpful? Give feedback.
-
I checked the other library and it does indeed base32 decode its generated secret internally before handing it over to
Neither of the two specifications says anything about base32 encoding - that's a portability feature that Google specified on their own (URI format), and it clearly states that the secret shall be base32 encoded. In their example over here they have a secret phrase |
Beta Was this translation helpful? Give feedback.
-
(Updated the above comment to clarify some things) |
Beta Was this translation helpful? Give feedback.
-
To conclude this: the secret length as per the specifications (RFCs 4226 and 6238) is the length of the binary string that is given to the HMAC hash function - there is no base32 encoding involved at all. Google's "Key URI format" specification uses base32 encoding in order to make the binary secret string portable (URL safe) - the base32 encoding naturally results in longer strings than the original secret. However, some of the top used libraries on packagist use some kind of pseudo base32 encoding, with a shorter secret string than requested as a result, which is highly insecure. Some of the bad examples:
(I'm gonna stop here, that was enough horrible code for today...) I'll close this issue here as resolved. |
Beta Was this translation helpful? Give feedback.
To conclude this: the secret length as per the specifications (RFCs 4226 and 6238) is the length of the binary string that is given to the HMAC hash function - there is no base32 encoding involved at all. Google's "Key URI format" specification uses base32 encoding in order to make the binary secret string portable (URL safe) - the base32 encoding naturally results in longer strings than the original secret.
However, some of the top used libraries on packagist use some kind of pseudo base32 encoding, with a shorter secret string than requested as a result, which is highly insecure.
Some of the bad examples:
phpgangsta/googleauthenticator
https://github.com/PHPGangsta/GoogleAuthenticator/b…