I have a Nexus S (thanks, Mom!), which means I now have a phone that supports
NFC. That has led me to think about how I would create a payment system that
uses my mobile phone that is completely secure not only from sniffing but from
phone theft as well. In other words something better than EMV (as recently
shown again to be imperfect).
A
Buzz by Tim O'Reilly on the topic
finally caused me to decide to blog about this.
Two things should be stated upfront. First, I am no security expert; these
are just some ideas I have on the matter. Second, this is not meant to make
sense to your parents; I'm assuming only people comfortable with a smartphone
to use this system. I am more worried about a completely secure system than I
am about my parents being able to use this approach.
So, to start, the payment app will require some passphrase protection.
Whether this is a PIN, password, lock screen, or biometric I honestly don't
care as long as it can be used to perform some encryption.
The key point is that the user must know some secret to use the payment
app properly. This protects the user from having their dropped or stolen phone
being used to make a ton of charges.
Now, with the user logged into the payment app they visit their bank's website
(I might be saying "bank", but I mean whomever is going to handle your
transactions and knows your account number). There they will have a QR Code
(should be a simple enough QR Code to not require a high-end camera feature on
the phone) to
scan with their payment app. The barcode will contain a very large account
number (think 100 digits), an increment value, some identifier of who the bank
is, and a protocol version number. Thanks to having a camera in the phone, the
app just scans the QR Code and the user has to manually type nothing. And all
the info is encrypted on the phone based on the passphrase as entered by the
user. This prevents a clever thief from nabbing your phone and simply reading
the memory to get the details necessary to clone your phone to make charges.
The app will also reset its transaction count to zero.
With the payment app and phone ready to go, you can now pay for something.
Let's say you are at In-N-Out and just bought some food for $6.54. You hold your
phone up to the NFC pad of the POS system and two pieces of data are sent to
your phone: name of
the business and the amount to be paid. Your payment app will prompt you saying
that In-N-Out would like you to pay them $6.54. This helps prevent random
people trying to charge you under a fradulent name and the cost will be used as
a way to verify with the bank how much you are authorizing to charge. If you
decide to authorize the charge, you enter your passphrase and your details are
decrypted and the payment app gets down to business.
First, it temporarily increments your transaction count, multiplies it against
the increment value, appends it to your account number, and then hashes it.
This creates a number identifying your account unique per transaction. It also
allows the bank to easily associate the transaction with your account without
any overally expensive process (hashes are relatively cheap). I am using a
unique multiplier to help prevent people guessing the increment amount by
having you do two transactions in a row at the same POS system
(security-by-obscurity might be bad to rely on, but it doesn't hurt to make
input values into a hash function harder to guess).
Next, the $6.54 cost has your account appended to it and that string is hashed.
This will provide a way for the bank to easily verify that the amount
being charged is what you want to be charged.
These two hashed values along with your bank's identifier are sent back to the
POS system. All of this is sent to your bank along with the amount In-N-Out
wants to charge you. The bank can easily look up your account by the hashed
value. It can then easily hash the charge amount with your account to verify
the amount be asked matches what you authorized. The bank clears the charge.
Back at the POS system, it tells your phone the charge went through and the
transaction counter is permanently incremented by one. And the whole
transaction is finished without any repeatable values being sent from your
phone to the bank that can be sniffed. Nor is the charge amount unverifiable by
the bank to prevent the shop from altering the charged amount without you
knowing. And because of the hashing there is no easy way to brute force
discover your account number.
I see two issues with all of this. One is that I used the account number for
both hashed values. This could be a problem as it means the POS system has
two separate hashes involving your account number, which could make it easier
to reverse the hash (but very hard to do). While the value used in hashing the
charge amount could be changed (e.g., the account + increment or something),
I don't know how much that solves the problem (if it is a problem). Another
solution is that the protocol version number can change what hash is used. This
would allow, e.g., switching from SHA-2 to SHA-3 when it is selected.
The other is my worry that the transaction count could get out of sync. I see
three possible solutions to this is. One is not to worry about it and rely on
the phone waiting for the bank's response to increment the count. Two, the bank
could assume one or two missed transaction increments (e.g., it was cancelled
at the POS system) and simply check two or three possible identification
values. Third, a back-channel communication from the payment app to the bank
could be made to help keep the numbers in sync (something as simple as an HTTPS
connection).
I think this covers phone theft (by encrypting the data on the phone), POS
system lying about the charge amount (by creating a hash with the charge
amount), sniffing (by hashing everything in a way that is unique per
transaction with no repeated values as seen by the POS system) and replay
attacks (by using a transaction counter in a hash).