Goal
I am doing a proof of concept of a symmetric key encryption. A javascript code will send a AES encrypted string, which i want to decrypt via php.
Attempt
ON the client side, we have:
<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>
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);
});
On the server, we have:
$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 this page.
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 webpage linked returns: JQE/sqMZCNegPJIric+RUA==, which can be decrypted by the same site. (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 this SO question – and that is how I came to the idea of hash. Even without hashing the session key, php is always returning empty string.
Session key is 16 chars long, which is 128 bit.
Question
How can I resolve the situation, 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 tell me 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.
