I’ve tried to encrypt the value with DES-ECB via PHP 7.4 (Laravel) and OpenSSL, and I try the online tool https://emvlab.org/descalc/ to encrypt value, the result was the expected.
key: 96187BBAB2BD19ACF899B74FB4E37972
Input Data: F01DCCE40F8C365ADE0A7DC03BC11DDE
The encrypted data is 355A627E977D8ECF4953C98D801E472F
on online tool.
https://emvlab.org/descalc/?key=96187BBAB2BD19ACF899B74FB4E37972&iv=0000000000000000&input=f01dcce40f8c365ade0a7dc03bc11dde&mode=ecb&action=Encrypt&output=D5131A2B35766D371420F679F15969FF
When the next code written in PHP I can’t replicate the result:
$data = "F01DCCE40F8C365ADE0A7DC03BC11DDE"; $key = "96187BBAB2BD19ACF899B74FB4E37972"; $encrypted = openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING); echo base64_encode($encrypted); // KV8Vie63pG2ZyjW7U5NRJUwOrbsEt+lnG1hNyS331Yk=
Is there a way to get the same string that the online tool? Thank you!
Advertisement
Answer
What must be considered for the website?
The website allows encryption with DES and TripleDES in 2TDEA variant (double length keys). The algorithm is determined by the key size: For an 8 bytes key DES is used, for a 16 bytes key TripleDES/2TDEA. The supported modes are ECB and CBC.
Key, IV (in case of CBC mode), plaintext and ciphertext have to be entered hex encoded on the website. Zero padding is applied (the variant that does not pad if the plaintext length is already an integer multiple of the DES/TripleDES block size of 8 bytes).
What does this mean for the posted data?
Since the posted hex encoded key 96187BBAB2BD19ACF899B74FB4E37972
has a size of 16 bytes, TripleDES/2TDEA is used (in ECB mode).
The hex encoded plaintext F01DCCE40F8C365ADE0A7DC03BC11DDE
has a size of 16 bytes and is therefore not padded. The resulting hex encoded ciphertext 355A627E977D8ECF4953C98D801E472F
thus has the same length.
How can the PHP code be fixed?
The posted PHP code gives a different result because DES is used as algorithm (in ECB mode) and also the hex encoding/decoding is missing. Thus to produce the result of the website, the encoding/decoding has to be fixed and DES-EDE-ECB
has to be applied as algorithm (not to be confused with DES-EDE3-ECB
for 3TDEA/triple length keys):
$data = hex2bin("F01DCCE40F8C365ADE0A7DC03BC11DDE"); // hex decode the 16 bytes data $key = hex2bin("96187BBAB2BD19ACF899B74FB4E37972"); // hex decode the 16 bytes key key $encrypted = openssl_encrypt($data, 'DES-EDE-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); // apply DES-EDE-ECB; use OPENSSL_ZERO_PADDING echo bin2hex($encrypted); // 355a627e977d8ecf4953c98d801e472f // hex encode the 16 bytes ciphertext
with the output:
355a627e977d8ecf4953c98d801e472f
that is equal to the result of the web site, s. here
How can a consistent result be achieved for DES?
The current PHP code applies DES and therefore implicitly truncates the key to 8 bytes by using only the first 8 bytes. This can be easily verified by removing the last 8 bytes of the key. The result does not change.
If the shortened key is applied to the website, the results match again.
$data = hex2bin("F01DCCE40F8C365ADE0A7DC03BC11DDE"); // hex decode the 16 bytes data $key = hex2bin("96187BBAB2BD19AC"); // hex decode the 8 bytes key $encrypted = openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); // apply DES-ECB; use OPENSSL_ZERO_PADDING echo bin2hex($encrypted); // 692370230b8176f011760ddc07392a4f // hex encode the 16 bytes ciphertext
with the output:
692370230b8176f011760ddc07392a4f
that is equal to the result of the web site, s. here.