1. 6
  1. 15

    There are a few (many) issues with this post. I feel like the author didn’t completely grasp the idea behind 2FA.

    2FA solutions usually combine 2 elements of the following categories (more information here):

    • Something you know
    • Something you have
    • Something you are

    Services asking for a phone number for 2FA don’t treat it as an additional password, they use it to send out tokens which are used to verify the “possession” of this phone number. Otherwise, a phone number is an easy to guess and worse than average password. After many SIM swapping incidents, most of the big services also allow you to create an TOTP token, which is completely anonymous (and not the same as a password!)

    Additionally, just taking a plain hash of a phone number doesn’t actually improve the security all that much. The input space of phone numbers is relatively small and easily enumerated: an attacker might just do a brute-force search for the correct phone number. Using a slower hash and a salt will slow this down, but to properly mangle phone numbers some form of encryption is needed. (and even then, there might be some issues)

    As for collisions, you should be able to test this yourself and verify that no 2 phone numbers hash to the same SHA256 hash. I think this will even be the case for md5. Generally, to hash a secret, you should use a hash that is specifically created to hash passwords (Scrypt/Argon2id). These hashes are slow by design, so brute forcing passwords becomes more difficult.

    1. 4

      Not sure you fully got it, I think the idea is that they hash the phone number so that it isn’t available in case a hacker gets access to the database, but they can still send an SMS verification token if you type in your phone number.

      1. 14

        A hacker will be able to use dictionary attack to recover the phone numbers from their hashes. Phone numbers have too little entropy to resist that. It’s going to be a only small road bump, even if you use a relatively expensive hash function.

        1. 3

          On top of that I’m pretty sure for every major service you’ll be able to determine the subset of numbers your target may use. Simply by looking at the TLD of their email (you already have that info, or you wouldn’t try to break the 2FA at that point) and then looking at wikipedia which numbers are used by the top 3 mobile providers. When we’re talking about amazon you might just look at the language I do my reviews in and you know which country to look for, same problem for any other service that has localized user content. And last but not least you’ll have to explain other people why entering your mobile number anywhere else is suddenly a security hazard for this specific 2FA algorithm.

          (Please just use a hardware key, TOTP or something else that isn’t based on how cheap an IMSI catcher or number transfer is in your country. We’ve had state wide attacks on peoples accounts via SMS 2FA.)

          1. 0
            1. 9

              The salt doesn’t make it significantly harder to guess one particular user’s phone number. The input space is still just all legal phone numbers, which, coupled by a fast hash algorithm, isn’t that big. In fact, my desktop runs sha256 on every single 7 digit number (the size of phone numbers in Norway), with a 64-byte salt, in under 4 seconds, using fairly naïve (but multi-threaded) C.

              The salt just means that you have to spend on average <2 seconds per user, it makes it so you can’t make a complete table which maps a hash to a phone number. Throw a few GPUs at the problem and those <2 seconds per user becomes milliseconds per user.

              (The source code I threw together to test, in case you wanna check my work: https://p.mort.coffee/alh.c - with the sha256 implementation from https://github.com/ckolivas/cgminer/blob/master/sha2.h and https://github.com/ckolivas/cgminer/blob/master/sha2.c)

              EDIT: I messed up the code. I was accidentally running through almost the entire range of numbers in parallel and then running through it again single threaded. Here’s the fixed code: https://p.mort.coffee/NPQ.c - It actually runs through the entire range of Norwegian phone numbers, from 0 to 9999999, in 231 milliseconds. You don’t even need the GPUs anymore. Those 11-digit UK and US phone numbers will still be a problem, but depending on context, there may still be tricks you can do to knock a few bits of entropy off the search space.

              1. 1

                Salt is a protection against rainbow tables. Phone number space is so tiny you don’t even need to bother with raindbow tables. A single Raspberry Pi can brute-force all phone numbers in the world in under an hour.

            2. 1

              I’m sure I don’t get it. If the company only stores my hashed number, how do they reverse it to send me an SMS?

              1. 2

                The idea is that you have to reenter your phone number, which they then use to both verify and text you.

                1. 1

                  They don’t, they ask you for it every time you log in.

            3. 6

              There aren’t a lot of phone numbers, so you’ll want to at least salt your hash so that a rainbow table of pre-computed sha256 values isn’t useful.

              But, someone with your db and salt can likely still usefully brute force things unless you’re using a deliberately slow hash.

              So I’d guess that the same advice applies to phone numbers as passwords (i.e. use something like scrypt or argon2), I think the search space is similar to weak passwords?

              log2(10^10) ~= 33bits


              According to one study involving half a million users, the average password entropy was estimated at 40.54 bits

              Oh - possibly quite a bit smaller. Maybe too small to do anything useful?

              1. 2

                It’s even more restricted than that - only the last 4 digits, in North America, are free to use all 10 possible values. The others are subject to various forms of restrictions, assignments and rules. See the “Modern Plan” section here: https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Numbering_plan

              2. 4

                Aside from all of the SS7-related issues, there’s one big problem with phone numbers for 2FA, which unfortunately systems such as Signal inherit: They conflate an identifier with a capability and then don’t provide any revocation mechanism for the capability. Having a person’s phone number grants you the ability to call them, send them messages, and so on. Normally, this kind of problem is solved with an indirection layer. For example, if you have your own domain then you can provide a throw-away email address to everyone who asks for it and set it to reject email if they start sending you spam. Each generated email address is a capability to send you mail and they’re distinct from your identity. Services like AppleID automate this. Some banks do the same with credit cards: they provide a mechanism for generating single-use credit card numbers with an expiry date one month in the future (because that’s the granularity of credit card expiry dates) that will accept one transaction and then reject all others.

                With a telephone, once someone has your unique identifier they can send you messages. I would love for Signal to grow a mechanism where you can generate a one-time-use code for key exchange that lets the sender negotiate a new key that they can use to communicate with you, such that they don’t know your phone number and only the system that negotiated the key pair can send you messages. Any attempts to use the code a second time should be automatically rejected. Once key exchange has completed, there’s an easy revocation mechanism: if you delete the your key from the pair then you can’t receive any messages from the sender and so you’ve effectively blocked them. I think they’ve got a chunk of the functionality for this in the sealed sender mechanism already.

                1. 3

                  A bit confusing. First, the premise is that people don’t want to give away their phone number, but the people who enter the number don’t see if it is getting hashed. Second, is it actually true that people are hesitant to enter their phone number because of spam? Phone numbers used to be in big public books! Third, brute-forcing a phone number is really easy, so hashing it doesn’t provide a lot of protections.

                  So, I guess the protection is weak but the target is also low value so it kind of makes sense…?

                  1. 1

                    I fiercely protect my phone number from most companies. Can someone tell me if the following fear is justified: I go to a restaurant and they ask me to scan a QR code to see the menu on my phone. Now the restaurant company knows my phone number and, presumably, once I’ve paid with a credit card, my identity is attached to it.

                    1. 7

                      No, they would not get your phone number. A QR code is just a bar code of a URL.

                      1. 1

                        My worry is that their website captures my number. So their QR menu would be a trap.

                        1. 4

                          No, it would be the same as any other website. They don’t see your number. They get your IP address, which could determine roughly where you are, and maybe the type of device and browser you are using. If you have any tracking cookies, they might get a little more.

                      2. 4

                        QR codes are basically just URLs, so the restaurant doesn’t get your phone number. They may get metadata from you visiting the URL.

                        Merchants (restaurants) usually don’t get any user-identifying info about cards when you make a payment. Not because card processors want to protect your privacy, but because they want to sell this data separately.