javascript – Different behaviour for same code in different languages-ThrowExceptions

Exception or error:

I am trying to decrypt Block TEA in Javascript (Node.js). I have tried to do the same thing in C++ and it works as expected:

#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

#define CRYPT_WORDS (64-4)/4
#define CRYPT_OFFSET 1

void btea_decrypt(uint32_t *v, int n, int base_rounds, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;

    /* Decoding Part */
    rounds = base_rounds + 52/n;
    sum = rounds*DELTA;
    y = v[0];

    do {
        e = (sum >> 2) & 3;
        for (p=n-1; p>0; p--) {
            z = v[p-1];
            y = v[p] -= MX;
        }

        z = v[n-1];
        y = v[0] -= MX;
        sum -= DELTA;
    } while (--rounds);
}

int main()
{
    static const uint32_t key[4] = {0x875bcc51, 0xa7637a66, 0x50960967, 0xf8536c51};
    uint32_t buf[64] = {16,  23, 163, 242, 214, 213, 125,  48, 167,  44, 232,
        23, 160, 192, 244, 116,  38, 255, 200,  38,  43,  57,
        18, 235, 206, 103, 161, 210, 187, 164,  42, 227, 139,
        248, 141, 205,  51, 132, 115, 233,  39,  53, 136, 207,
        238, 190, 111,  57, 117, 233,  67, 133, 165,  84, 154,
        161, 165, 173,  76, 115, 108,   0,   0,  71};
    uint32_t cryptpart[CRYPT_WORDS];

    // Decrypt encrypted portion
    for (int i = 0; i < CRYPT_WORDS; i++) {
        cryptpart[i] =
            ((uint32_t)buf[CRYPT_OFFSET+4*i  ]) << 0  |
            ((uint32_t)buf[CRYPT_OFFSET+4*i+1]) << 8  |
            ((uint32_t)buf[CRYPT_OFFSET+4*i+2]) << 16 |
            ((uint32_t)buf[CRYPT_OFFSET+4*i+3]) << 24;
    }

    btea_decrypt(cryptpart, CRYPT_WORDS, 1, key);

    for (int i = 0; i < CRYPT_WORDS; i++) {
        buf[CRYPT_OFFSET+4*i  ] = cryptpart[i] >> 0;
        buf[CRYPT_OFFSET+4*i+1] = cryptpart[i] >> 8;
        buf[CRYPT_OFFSET+4*i+2] = cryptpart[i] >> 16;
        buf[CRYPT_OFFSET+4*i+3] = cryptpart[i] >> 24;
    }

    for (const auto& e : buf) {
        std::cout << e << ", ";
    }
}

And it outputs:

16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65280, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3561881601, 13913600, 54350, 212, 393407394, 1536747, 6002, 23, 3612094810, 14109745, 55116, 215, 589329, 2302, 8, 0, 5439472, 21247, 82, 0, 0, 0, 71,

But using the same code (ported) in Node.js:

function btea_decrypt(v, n, base_rounds, key)
{
    let y, z, sum;
    let p, rounds, e;

    /* Decoding Part */
    rounds = base_rounds + 52/n;
    sum = rounds*0x9e3779b9;
    y = v[0];

    do {
        e = (sum >> 2) & 3;
        for (p=n-1; p>0; p--) {
            z = v[p-1];
            y = v[p] -= (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
        }

        z = v[n-1];
        y = v[0] -= (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
        sum -= 0x9e3779b9;
    } while (--rounds);
    return v;
}

function main() {
    let key = [0x875bcc51, 0xa7637a66, 0x50960967, 0xf8536c51];
    let buf = [16,  23, 163, 242, 214, 213, 125,  48, 167,  44, 232,
   23, 160, 192, 244, 116,  38, 255, 200,  38,  43,  57,
   18, 235, 206, 103, 161, 210, 187, 164,  42, 227, 139,
  248, 141, 205,  51, 132, 115, 233,  39,  53, 136, 207,
  238, 190, 111,  57, 117, 233,  67, 133, 165,  84, 154,
  161, 165, 173,  76, 115, 108,   0,   0,  71];
    let cryptpart = [];

    // Decrypt encrypted portion
    for (let i = 0; i < (64-4)/4; i++) {
    cryptpart[i] =
        (buf[1+4*i  ]) << 0  |
        (buf[1+4*i+1]) << 8  |
        (buf[1+4*i+2]) << 16 |
        (buf[1+4*i+3]) << 24;
    }

    cryptpart = btea_decrypt(cryptpart, (64-4)/4, 1, key);

    for (let i = 0; i < (64-4)/4; i++) {
        buf[1+4*i  ] = cryptpart[i] >> 0;
        buf[1+4*i+1] = cryptpart[i] >> 8;
        buf[1+4*i+2] = cryptpart[i] >> 16;
        buf[1+4*i+3] = cryptpart[i] >> 24;
    }

    console.log(buf)
}

It remains stuck in do ... while loop forever.

I figured out, that Javascript and C++ handle 0x9e3779b9 differently, because 0x9e3779b9 * 15 in JS equals 39816536535 and 1161830871 in C++. What is wrong with math in C++ and how to realize this in JS?

Sorry if my English isn’t the best.

How to solve:

Your issue is caused by an integer overflow. A unint32_t is an integer of fixed size 2^32 bits. 0x9e3779b9 * 15 is 39816536535 which is approx 2^35.

This means you get an overflow as the memory location is simply not big enough to hold your number. Javascript does not have this problem as its not statically typed and the size allocated in memory will increase dynamically to hold it.

Use a larger datatype for C++, like an unsigned long or size_t (alias for unsigned long on most systems). Preferably use auto to let the compiler decide for you:

auto sum = rounds*0x9e3779b9;

This will fix your issue and ensure sum is large enough to hold the number

Side notes: There is quite a lot of C in your C++, in C++ we try and avoid #defines and declare variables when we first use them, not at the top of the scope. When writing C++ code prefer const auto x instead of #define x (possibly constexpr if its a basic type)

Leave a Reply

Your email address will not be published. Required fields are marked *