JS端AES加密内容无法被PHP端解密的问题排查及可行对称加密实现方案请求
Goal
I am doing a proof of concept of a symmetric key encryption. A JavaScript code will send an AES encrypted string, which I want to decrypt via PHP.
Attempt
Client-side Code
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js" integrity="sha512-a+SUDuwNzXDvz4XrIcXHuCf089/iJAoN4lmrXJg18XnduKK6YlDHNRalv4yd1N40OKI80tFidF+rqTFKGPoWFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/aes.min.js" integrity="sha512-UOtWWEXoMk1WLeC873Gmrkb2/dZMwvN1ViM9C1mNvNmQSeXpEr8sRzXLmUSha1X4x5V892uFmEjiZzUsYiHYiw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/enc-base64.min.js" integrity="sha512-m/shICarVhgGKyAmv7SlfXVinPq1eNVh4aPdBpGw6lqT3lh/hYtZJ+HaX6DuxjN8o7giM9mfpZQf314bErdGUg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> function encryptFlag(flag, sessionKey) { // Encrypt the flag using AES-128-ECB with the session key and no padding const hash = CryptoJS.SHA256(sessionKey); const encrypted = CryptoJS.AES.encrypt(flag, hash, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding // No padding }); console.log("hash", hash); // Return the encrypted flag in hex format return encrypted.toString(); } const encryptedFlag = encryptFlag(flag, key); axios.post('/my-end-point', { command: 'login_current_device', encrypted_flag: encryptedFlag, user: username }).then(response => { console.log('Server response:', response.data); if (response.data.success) { window.location.href = "/collab-apex/dashboard"; // Redirect to dashboard if login successful } else { alert('decoding failed!'); } }).catch(error => { console.error('Error during request:', error); }); </script>
Server-side Code
$decryptedFlag = decryptFlag($encryptedFlag, hash('sha256',$sessionKey)); function decryptFlag($encryptedFlag, $sessionKey) { // Decrypt using AES-128-ECB and the session key $decrypted = openssl_decrypt( base64_decode($encryptedFlag), 'AES-128-ECB', // AES encryption mode $sessionKey, // Session key as the secret key OPENSSL_RAW_DATA ); return $decrypted; }
Exact problem
The PHP is returning an empty string. It has the correct session key there. The encrypted flag is also correct.
Attempt to solution
First, I check with an online AES encryption/decryption tool.
This is my flag: n/ghZub%h/gh3678 (it can be any alphanumeric + symbols string, no control char).
The JavaScript, using AES 128, ECB, no padding with key PPEGFtHt9+n6z]1p gives the result:
tjjg2Sfi0D7c5Oxjb4sJ7cmbXrpic+lknjNLI3ojeO0=
But the online tool returns: JQE/sqMZCNegPJIric+RUA==, which can be decrypted by the same tool. (Un)surprisingly, the JavaScript output can't be decoded to the correct result.
If I specifically set return encrypted.toString(CryptoJS.enc.Base64); I get error :
Error during request: TypeError: r.clamp is not a function stringify https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/enc-base64.min.js:1 toString https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js:1
If I do not include the base64 JS file from CDNJS, then the error is:
Error during request: TypeError: wordArray.clamp is not a function stringify https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.js:1311 toString https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.js:3998
If I set return encrypted.toString(CryptoJS.enc.Hex);, the result in JavaScript is an empty string.
Back at PHP side, it is an empty string in any case; even if I use :
$decrypted = openssl_decrypt( $encryptedFlag, // I removed the base64decode here 'AES-128-ECB', // AES encryption mode $sessionKey, // Session key as the secret key OPENSSL_RAW_DATA );
I looked at a Stack Overflow question - and that is how I came to the idea of using a hash. Even without hashing the session key, PHP is always returning an empty string.
Session key is 16 chars long, which is 128 bit.
Question
How can I resolve this situation, so that a symmetric key cryptographic exchange works between JS and PHP?
I would like to find what is wrong in my implementation; but I am open to a different symmetric key algorithm if you provide the full code for implementation. The requirements are that
- it has to be symmetric key, and
- it has to work between JS and PHP.
Thank you.
备注:内容来源于stack exchange,提问作者Sean

