Example of decoding Ecwid payment request using Web Cryptography API / SublteCrypto. https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var bodyData = 'ECWID PAYLOAD'; | |
var clientId = 'YOUR CLIENT SECRET'; | |
// Added required padding to make the payload a multiple of 4. We can do this using a repeat or a simple while. | |
// var paddingLength = 4 - (bodyData.length % 4); | |
// if (paddingLength !== 4) { | |
// bodyData + '='.repeat(paddingLength); | |
// } | |
while (bodyData.length % 4 !== 0) { | |
bodyData += '='; | |
} | |
var originalBase64 = bodyData.replace(/-/g, "+").replace(/_/g, "/"); | |
var decodedBase64 = atob(originalBase64); | |
var iv = str2ab(decodedBase64.substring(0, 16)); | |
var cipherOrder = b642ab(originalBase64); | |
var keyData = str2ab(clientId.substring(0, 16)); | |
async function decryptOrder() { | |
var key = await importKey(); | |
try { | |
return await crypto.subtle.decrypt( | |
{ name: "AES-CBC", iv: iv }, | |
key, | |
cipherOrder | |
); | |
} catch (exception) { | |
console.error( | |
"An error occurred, Name: ", | |
exception.name, | |
", Message: ", | |
exception.message | |
); | |
} | |
} | |
async function importKey() { | |
var key = await crypto.subtle.importKey( | |
"raw", | |
keyData, | |
{ name: "AES-CBC" }, | |
true, | |
["decrypt"] | |
); | |
return key; | |
} | |
// Concept from https://stackoverflow.com/a/11058858. Convert String to Array Buffer | |
function str2ab(str) { | |
const buf = new ArrayBuffer(str.length); | |
const bufView = new Uint8Array(buf); | |
for (let i = 0, strLen = str.length; i < strLen; i++) { | |
bufView[i] = str.charCodeAt(i); | |
} | |
return buf; | |
} | |
// Concept from https://stackoverflow.com/a/21797381/9014097 Convert Base64 to Array Buffer. | |
function b642ab(base64) { | |
var binary_string = window.atob(base64); | |
var len = binary_string.length; | |
var bytes = new Uint8Array(len); | |
for (var i = 0; i < len; i++) { | |
bytes[i] = binary_string.charCodeAt(i); | |
} | |
return bytes.buffer; | |
} | |
(async () => { | |
var decrypted = await decryptOrder(); | |
var decryptedStr = new TextDecoder().decode(decrypted); | |
console.log(decryptedStr.substring(16)); | |
})(); |
@parasdaryanani Thats a good solution! I saw the problem with 15/16 bytes but haven't had time to check why it happens.
@parasdaryanani Hey! I’ve modified the gist to include the required padding to make the payload multiple of 4, that should solve the issue with 15/16 bytes.
@manuelfdo brilliant, thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@manuelfdo, thank you for putting this together!
I've noticed that the Ecwid payload can sometimes start after an arbitrary number of bytes.
Usually 15 or 16, but it's not consistent, due to which I think it may be worth tweaking the algorithm slightly.
Examples:
Working with 15 OR 16 bytes, sometimes it just works.
My solution (which may or may not be correct):