[ACCEPTED]-How to generate a verification code/number?-data-consistency
After some research, I think I'll go with 8 the ISO 7064 Mod 97,10 formula. It seems pretty solid as it 7 is used to validate IBAN (International 6 Bank Account Number).
The formula is very 5 simple:
- Take a number :
123456
- Apply the following formula to obtain the 2 digits checksum :
mod(98 - mod(number * 100, 97), 97)
=> 76 - Concat number and checksum to obtain the code => 12345676
- To validate a code, verify that
mod(code, 97) == 1
Test :
mod(12345676, 97) = 1
=> GOODmod(21345676, 97) = 50
=> BAD !mod(12345678, 97) = 10
=> BAD !
Apparently, this algorithm 4 catches most of the errors.
Another interesting 3 option was the Verhoeff algorithm. It has only one verification 2 digit and is more difficult to implement 1 (compared to the simple formula above).
For 1M combinations you'll need 6 digits. To 15 make sure that there aren't any accidentally 14 valid codes, I suggest 9 digits with a 1/1000 13 chance that a random code works. I'd also 12 suggest using another digit (10 total) to 11 perform an integrity check. As far as distribution patterns, random 10 will suffice and the check digit will ensure 9 that a single error will not result in a 8 correct code.
Edit: Apparently I didn't fully 7 read your request. Using a credit card number, you 6 could perform a hash on it (MD5 or SHA1 5 or something similar). You then truncate 4 at an appropriate spot (for example 9 characters) and 3 convert to base 10. Then you add the check 2 digit(s) and this should more or less work 1 for your purposes.
You want to segment your code. Part of 23 it should be a 16-bit CRC of the rest of 22 the code.
If all you want is a verification 21 number then just use a sequence number (assuming 20 you have a single point of generation). That 19 way you know you are not getting duplicates.
Then 18 you prefix the sequence with a CRC-16 of 17 that sequence number AND some private key. You 16 can use anything for the private key, as 15 long as you keep it private. Make it something 14 big, at least a GUID, but it could be the text 13 to War and Peace from project Gutenberg. Just needs to be secret and constant. Having 12 a private key prevents people from being 11 able to forge a key, but using a 16 bit 10 CR makes it easier to break.
To validate 9 you just split the number into its two parts, and 8 then take a CRC-16 of the sequence number 7 and the private key.
If you want to obscure 6 the sequential portion more, then split 5 the CRC in two parts. Put 3 digits at the 4 front and 2 at the back of the sequence 3 (zero pad so the length of the CRC is consistent).
This 2 method allows you to start with smaller 1 keys too. The first 10 keys will be 6 digits.
Does it have to be only numbers? You could 11 create a random number between 1 and 1M 10 (I'd suggest even higher though) and then 9 Base32 encode it. The next thing you need to do is Hash 8 that value (using a secret salt value) and 7 base32 encode the hash. Then append the 6 two strings together, perhaps separated 5 by the dash.
That way, you can verify the 4 incoming code algorithmically. You just 3 take the left side of the code, hash it 2 using your secret salt, and compare that 1 value to the right side of the code.
- I must have a reasonnable number of possible combinations (let's say 1M)
- The code must be as short as possible, to avoid errors from the user
Well, if you want it to have at least one 2 million combinations, then you need at least 1 six digits. Is that short enough?
When you are creating the verification code, do 18 you have access to the caller's phone number?
If 17 so I would use the caller's phone number 16 and run it through some sort of hashing 15 function so that you can guarantee that 14 the verification code you gave to the caller 13 in step 1 is the same one that they are 12 entering in step 2 (to make sure they aren't 11 using a friend's validation code or they 10 simply made a very lucky guess).
About the 9 hashing, I'm not sure if it's possible to 8 take a 10 digit number and come out with 7 a hash result that would be < 10 digits 6 (I guess you'd have to live with a certain 5 amount of collision) but I think this would 4 help ensure the user is who they say they 3 are.
Of course this won't work if the phone 2 number used in step 1 is different than 1 the one they are calling from in step 2.
Assuming you already know how to detect 25 which key the user hit, this should be doable 24 reasonably easily. In the security world, there 23 is the notion of a "one time" password. This 22 is sometimes referred to as a "disposable 21 password." Normally these are restricted 20 to the (easily typable) ASCII values. So, [a-zA-z0-9] and 19 a bunch of easily typable symbols. like 18 comma, period, semi colon, and parenthesis. In 17 your case, though, you'd probably want to 16 limit the range to [0-9] and possibly include 15 * and #.
I am unable to explain all the technical 14 details of how these one-time codes are 13 generated (or work) adequately. There is 12 some intermediate math behind it, which 11 I'd butcher without first reviewing it myself. Suffice 10 it to say that you use an algorithm to generate 9 a stream of one time passwords. No matter 8 how mnay previous codes you know, the subsequent 7 one should be impossibel to guess! In your 6 case, you'll simply use each password on 5 the list as the user's random code.
Rather 4 than fail at explaining the details of the 3 implementation myself, I'll direct you to 2 a 9 page article where you can read up on 1 it youself: https://www.grc.com/ppp.htm
It sounds like you have the unspoken requirement 7 that it must be quickly determined, via 6 algorithm, that the code is valid. This 5 would rule out you simply handing out a 4 list of one time pad numbers.
There are several 3 ways people have done this in the past.
- Make a public key and private key. Encode the numbers 0-999,999 using the private key, and hand out the results. You'll need to throw in some random numbers to make the result come out to the longer version, and you'll have to convert the result from base 64 to base 10. When you get a number entered, convert it back to base64, apply the private key, and see if the intereting numbers are under 1,000,000 (discard the random numbers).
- Use a reversible hash function
- Use the first million numbers from a PRN seeded at a specific value. The "checking" function can get the seed, and know that the next million values are good. It can either generate them each time and check one by one when a code is received, or on program startup store them all in a table, sorted, and then use binary search (maximum of compares) since one million integers is not a whole lot of space.
There 2 are a bunch of other options, but these 1 are common and easy to implement.
-Adam
You linked to the check digits project, and using the 13 "encode" function seems like a 12 good solution. It says:
encode may throw 11 an exception if 'bad' data (e.g. non-numeric) is 10 passed to it, while verify only returns 9 true or false. The idea here is that encode 8 normally gets it's data from 'trusted' internal 7 sources (a database key for instance), so 6 it should be pretty usual, in fact, exceptional 5 that bad data is being passed in.
So it sounds 4 like you could pass the encode function 3 a database key (5 digits, for instance) and 2 you could get a number out that would meet 1 your requirements.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.