Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node vs Browser implementations incompatibility? #81

Open
fredeno opened this issue Nov 4, 2021 · 3 comments
Open

Node vs Browser implementations incompatibility? #81

fredeno opened this issue Nov 4, 2021 · 3 comments

Comments

@fredeno
Copy link

fredeno commented Nov 4, 2021

We are opening this new issue following this question on Bad MAC errors occurring sometimes when decrypting data : #63

Indeed we are facing this problem in our application. Sometimes data encrypted in the browser can't be decrypted in Node.js, sometimes data encrypted in Node.js can't be decrypted by the browser. This happens around once for 300 occurrences.

In our case, eccrypto is used classically in a Node.js backend application and also used in a React web application with the help of browserify and Node Buffer API for browser (https://github.com/feross/buffer) so that the same code can run on both environments.

We are reaching the step where we think it is an eccrypto incompatibility between browser and Node implementations but that still may be in the way we use it…

We managed to reproduce the behavior with this code :

const key = {
    privateKey: '507e1910e86cb57f66a36ae55660c66c130b60de4c2016a4d548357d054ca1a5',
    publicKey: '0499d72de2a4ac8e980ca664110d295bde3d83c122d07ac4fb6f9f34413e06b0cf20022672373968c0c19956af82864b1799141935965da8fb196348174c95bc1a'
}
const value = 'This is just a string to encrypt'
const iv = "1cb7e5a8f77f19535226730204ca6ef0"

const multipleEncrypt = async (n) => {
    const arrayOfEncrypted = []
    for (let i = 0; i < n; i++) {
        const encrypted = await eccrypto.encrypt(Buffer.from(key.publicKey, "hex"), Buffer.from(value), { iv: Buffer.from(iv, "hex") })
        const result = Buffer.from(encrypted.ephemPublicKey).toString("base64").concat(Buffer.from(encrypted.mac).toString("base64"), Buffer.from(encrypted.ciphertext).toString("base64"))
        arrayOfEncrypted.push(result)
    }
    console.log("array of encrypted values: ")
    const util = require('util')
    console.log(util.inspect(arrayOfEncrypted, { maxArrayLength: null }))
}

const multipleDecrypt = async (encrypted) => {
    for (let i = 0; i < encrypted.length; i++) {
        try {
            const ephemPublicKey = encrypted[i].substr(0, 88)
            const mac = encrypted[i].substr(88, 44)
            const ciphertext = encrypted[i].substr(132, encrypted.length)
            const data = {
                iv: Buffer.from(iv, "hex"),
                ephemPublicKey: Buffer.from(ephemPublicKey, "base64"),
                ciphertext: Buffer.from(ciphertext, "base64"),
                mac: Buffer.from(mac, "base64")
            };
            const result = await eccrypto.decrypt(Buffer.from(key.privateKey, "hex"), data)
            console.log("'" + encrypted[i] + "' decrypted => " + result.toString())
        } catch (e) {
            console.error("Cannot decrypt '" + encrypted[i] + "'", e)
        }
    }
}

First we execute multipleEncrypt(300) in Node.js which encrypts 300 times the same data with the same key and parameters.

Then we inject the resulting array of values in this code to execute it in the web application:

const arrayOfEncrypted = [
        'BIg5dEMKeM8iOm3r0Y0hgdpVRhCLl7pWQp5Rd5FV4uZKd7DMpPPpRMvyKrP7iVOhr7/6EsOvOQi0tO15nHRIap4=/ug6ZlyN07kVgpweJfy7lKKq5dDlxbfNuJ97cfD8ad8=PRG9x9R7ZOHIyLOiA9K0DgkzK7TUyHaKIb63r2PiCHjVMsUBNfFh96cItLgV97Jx',
        'BPKGILr53DScAxO/+LX6dSmDanSwtZtkskKx9MUyu3FG391glc4HUzyfKc+CTM3/jqui8Q+Pj2/nzXq2YtobOUM=NGuVEwasLdMWEQD+4B7FapCbOW2XTworwd7Oih1al4E=luxDF4Sc71d42DBfZaap+gaB3iAsa0LHZOULOaeN6lfEgtRogbGVBnsz98kYmQcE',
        // and 298 other occurrences...
        ]
multipleDecrypt(arrayOfEncrypted)

When run in the browser, all values are decrypted except one (the second one in this example) for which we get a "Bad MAC" error.

We have the same behavior when encrypting in browser and decrypting in Node.js. But when we force to use the eccrypto browser implementation in Node.js, that works perfectly! This is an interesting workaround but not very satisfying and this alternative is only available on Node anyway…

Is there something to fix in eccrypto or in the way we use it?
Thanks in advance for your help.

@ArjunRajJain
Copy link

@fredeno did you ever find a solution to this?

@fredeno
Copy link
Author

fredeno commented Jul 28, 2022

@fredeno did you ever find a solution to this?

@ArjunRajJain No news about this problem unfortunately.
The only solution is the workaround I described and we've been living with it up to now: if decryption fails in Node.js, we try again forcing the browser implementation.
It is not a clean solution because performance is bad on this case but it is OK for our goal as it happens around once every 300 decryption attempts. By chance, we have no need yet to proceed the other way round (encryption in Node and decryption in browser).

@mystiko0x1
Copy link

@fredeno We found the possible root cause of this issue, please refer to PR #96 for more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants