Skip to content
Advertisement

PHP OpenSSL encrypt with DES-ECB algorithm unexpected output

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!

enter image description here

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.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement