Credit Card Info Encryption Best Practice: Use Padding to Avoid Known-Plaintext Attacks, a Lesson Learnt From Alan Turing's Cracking of the Enigma Code

Among the full set of eCommerce APIs, probably no APIs should pay more attention to confidentiality than APIs involving the transmission of credit card numbers.

Take this eCommerce retailer as an example:

They have an API for distributing RSA public key:

{ "key": "MIIBIjANB......QAB", }

The public key is then used by the client mobile app to encrypt credit card information, such as the 16-digit credit card number, CVV and expiration month/year.

When the end user decides to make the payment, this precious information will not be sent as plain-text, but will be encrypted additionally by the RSA public key:

Here is what it looks like on the wire with Charles Proxy as man-in-the-middle:

Because the CVV number is a 3-digit number, had the eCommerce app used raw RSA encryption, without any random padding, such as this scheme, the encrypted output would be the same for the same 3-digit CVV number: OAEP: Optimal Asymmetric Encryption Padding | SpringerLink.

This would lead to known-plaintext attack, that is, the attacker can build a dictionary of all the 10x10x10 possible CVV numbers and their encrypted strings. And the end user’s CVV can be discerned via looking up such a dictionary.

Interestingly, a known-plaintext attack model also came into play during Alan Turing’s cracking of the Enigma code: Known-plaintext attack - Wikipedia

Back in the dark days of World War II, “Heil Hitler” was a known phrase which helped Alan Turing to accelerate his cracking of the Enigma machine’s configuration. In this example of today’s hyperconnected eCommerce, the 3-digit known pattern of CVV is the modern day “known-plaintext” that we are trying to protect its confidentiality during internet transmission.

Thankfully, this eCommerce online service is using RSA encryption with padding, so the encrypted string would be different every time, imagine my credit card’s CVV is the number “777”:

echo -n 777 | openssl rsautl -inkey public_key.pem -pubin -pkcs -encrypt | base64 HxsNoslY+w4PH/WSSq0ObHYwCIgEpaOUn8aTeI1ger+ZKBOban1pWLN6xPJTT2ROCCIycGupdUcuOCjUU/ZyVnZ38AOZQYLkZMnJLmOkWasynjZAQi1iXr5L94HbbE9YCUWclNzEdnpWLqYY1HmaBt90AeXIVi/ff7xSX2fCc0l19UP/jZYHqJrvMdTYexwmYdKoOc+LAZrY0wpC4cpGeUXSmbE6e69uNKs6/FuovOAcv4ElmWkYAyB7Bv3vm2BGjz53sn11/nW2eew+UnDkklEOm3EWr4sU2qSh/WChDbkAfLJGvCTDIzvARi78WKhXcr6qCfF+P2/d0WOXcyieNQ==

echo -n 777 | openssl rsautl -inkey public_key.pem -pubin -pkcs -encrypt | base64 QQpNRWsPxB6hwZ1WSzpN5pujkEebh9nBwiDrframigr7fU6/wqr2405Onok9iQO0hLlN5fcQm4HJMqSH2qjw5Md68vF9JZV2llTA1WT9hBSwRWdPbMDI6JfJbrkN4ZMkYIpFD8T/I1Hi2NbyiLJZxxElIyEPh7KUEzgxgHOdjFzN9ZW3vZuvSPH2es16Jw7g2BcoWoMOfRX1skB9YBLpdODUsTLPilGafmozQrQDBskUwCNPViw1tZs/ZAfUjEsc5MLAOxNSFYybj7tTqF5wtxPNmvFvsTYDCp6FKeiU2HMtFXQ21390fC9pKeJD2c3Tn7p3Z+qPTy5MCq+7aaQpOg==

echo -n 777 | openssl rsautl -inkey public_key.pem -pubin -pkcs -encrypt | base64 oIWBstBP4gwZJyeEsFb0wTUkVArO5XYQCAc8sInIdsuZTMBS1seTYuZL1wKb4+puTNHs8Iq/CDNo/p9iusr/mHRPZboqla3HWg+NLcsjCuMBc/8P7DW9bSEemEOgrSfUmQ8SZ1P0bMvtDNKdb6490oq9M0m2Z1bPbhMWF2wSu72u05v+QhTcaehiMISKzwMdoI3Er7p+izNomFloF7Kuz/z/JAJ1K5YVyHLvWDNX779EeqFbcxo+dBHMvnHlF2hBmB0a3cDaSlw6/+r2h1e0S6s851IEh5JmNElxrYUJfNRY9aDWYRjhrOAKYE/9vDPrkcEdZorK/MW+TfSfNR7JBQ==