2
\$\begingroup\$

I am participating in a funny crypto contest with my friends. This time, we raised the bar quite a bit.

The code below is my take for the constraints we set. Note that on my machine, the code works perfectly.

Constraints:

  • The message M is made of random numbers
  • M1 is 200 bytes at most.
  • Packet P is 1024 bytes long.
  • At most 2 exchanges between Bob and Alice (Bob sends one packet and Alice can answer one packet as well). More and they both burn.
  • P could be showed publicly for a very long time that it would not be an issue with current hardware.
  • Use javascript not to mess the reading (subjective) and prevent any tricks.

Context:

The details of what is going on outside this scope is of 0 importance here (we don't care about the logic of existence of this code in the first place, we want to play). We just decided that game with those constraints.

Questions:

  • Is this implementation solid enough overall?
  • Do you see blatant logic failures?

Edit:

I've updated the code because I could attack my protocol by a side channel: the last message (in MKL_encrypt_receiver) was not protected by a mac and, with knowledge of the algorithm, I could prevent Bob and Alice from communicating. Not anymore. At least, not without Bob knowing something wrong is happening here.

Code:

//Design: MKL

/* Globals */

var great_power = 1024

// obtained by physical exchange. Can be anything
var shared_secret1 = 25626n
var shared_secret2 = 17553n

// message
var str_buf
var initial_message_len

// debug -> to be removed before real use
var save_out_message

// simulate the machines
var obj_bob_machine
var obj_alice_machine
/* Deps */
const crypto = require('crypto');
let bigbuf = require('bigint-buffer')

/* Code */

/* ----- Common Code */

/* adjusts the variables we got from the two shared secrets */
function adjusted_huge_number(data_obj) {

    let strength = 301n

    /* rule out even values: they severely bias the bits dispersion */
    if ((data_obj.shared_secret1 & 1n) === 0n) {
        data_obj.shared_secret1++
    }
    if ((data_obj.shared_secret2 & 1n) === 0n) {
        data_obj.shared_secret2++
    }
    let buff_mess_len = data_obj.incoming_message.length + 150

    let adj = BigInt((48 + great_power) << 3)
    let min = 2n ** adj
    let multiple1, multiple2
    upper_while:
    while (1) {

        multiple1 = (data_obj.shared_secret1 + (18n * data_obj.shared_secret2)) ** strength
        multiple2 = (data_obj.shared_secret2 + (24n * data_obj.shared_secret1)) ** strength

        /*let res1 = bigbuf.toBufferLE(multiple1, 560) /* 48 + 512*
        let res2 = bigbuf.toBufferLE(multiple2, 560)*/

        if (multiple2 <= min) {
            if (multiple2 <= min) {
                strength += 50n
                continue
            }
            while (1) {
                strength += 50n
                multiple2 = data_obj.shared_secret2 ** strength

                if (multiple2 <= min) continue
                break upper_while
            }
        }
        if (multiple1 <= min) {

            while (1) {
                strength += 50n
                multiple1 = data_obj.shared_secret1 ** strength

                if (multiple1 <= min) continue
                break upper_while
            }
        }
        else break upper_while
    }

    data_obj.multiple1 = multiple1
    data_obj.multiple2 = multiple2

    /* take the end of the buffers because repetitions occur at the beginning of the buffer, for every powers tested.
    This could help an attacker if the message doesn't have a lot of bits set at the beginning.
    We don't need a deep copy */
    /* edit: start at 48, we are now mixing values; we want at least a number composed of 512 bytes*/
    let res1 = bigbuf.toBufferLE(multiple1, 48 + great_power) /* 48 + 512*/
    let res2 = bigbuf.toBufferLE(multiple2, 48 + great_power)

    let new_buff1 = new Buffer(great_power)
    let new_buff2 = new Buffer(great_power)
    let new_buff3 = new Buffer(great_power)

    //let res1_tmp = res1.slice(48,560)
    res1.copy(new_buff1, 0, 48, 48 + great_power)
    res2.copy(new_buff2, 0, 48, 48 + great_power)

    for (let x = 0, xl = great_power; x < xl; x++) {
        new_buff3[x] = new_buff1[x] ^ new_buff2[x]
    }

    data_obj.end_arr1 = new_buff1
    data_obj.end_arr2 = new_buff2
    data_obj.end_arr3 = new_buff3

    // prevent that information to be kept in registers/memory for too long
    strength = 0

}
/* sets fake data  and possibibly the message */
function prepare_data(data_obj, is_encrypt) {

    let size_head_bits = parseInt((data_obj.shared_secret1 * 7n + data_obj.shared_secret2 * 5n) & 511n)

    let num_bytes_head = size_head_bits >> 3
    let diff_head = size_head_bits - (num_bytes_head << 3)

    data_obj.final_swap1 = diff_head

    data_obj.pre_data = new Buffer((num_bytes_head))

    let size_tail_bits = parseInt((data_obj.shared_secret1 * 11n + data_obj.shared_secret2 * 13n) & BigInt(((great_power << 3) - 1)))
    let num_bytes_tail = size_tail_bits >> 3

    let message_len = (num_bytes_head & 15) + 64

    if (is_encrypt) {
        // generate message
        generate_random_message(data_obj, message_len)
    }

    // TODO: adjust for our mac system
    let fill = great_power - num_bytes_head - num_bytes_tail - message_len - 4 - 4 /* for  the macs*/

    if (fill < 0) {
        fill = 0
    }

    data_obj.final_swap2 = size_tail_bits - (num_bytes_tail << 3)
    num_bytes_tail += fill
    data_obj.post_data = new Buffer(num_bytes_tail)

    if (is_encrypt) {
        /* this randomization will prevent any attacker from bruteforcing the two secrets and only have to check for a match in post/pre fake data*/
        let randomize = crypto.randomBytes(num_bytes_tail + num_bytes_head)
        let randomize_counter = 0

        let r = parseInt((data_obj.shared_secret1 * 3n) & 255n)
        for (let x = 0, xl = (num_bytes_head + 1), q = num_bytes_head; x < xl; x++ , q++) {
            // overflow are ignored -> don't care
            data_obj.pre_data[x] = ((r * q * 11) ^ 0xB9) + randomize[randomize_counter++]
        }

        r = parseInt((data_obj.shared_secret2 * 13n) & 255n)

        for (let x = 0, xl = num_bytes_tail, q = (xl + data_obj.incoming_message.length); x < xl; x++ , q++) {

            data_obj.post_data[x] = ((r * q * 3) ^ 0x35) + randomize[randomize_counter++]
        }
    }
}
/* Prepare the substitution table */
function apply_table_transformations(table, array_transf) {

    let tmp_buff = new Buffer(16)

    for (let x = 0, xl = array_transf.length; x < xl; x++) {

        let is_row = array_transf[x][0]
        let num_slides = array_transf[x][2]
        let line = array_transf[x][1]
        if (is_row) { // we slide a row

            let first_idx = line << 4

            // save the bytes
            let last_idx = first_idx + (16 - num_slides)
            for (let y = 0, yl = 16; y < yl; y++) {
                tmp_buff[y] = table[first_idx + y]
            }
            let yu2 = 16 - num_slides
            for (let y = 0, yl = 16; y < yl; y++) {
                let yu = first_idx + y
                table[yu] = tmp_buff[(yu2 + y) & 15]
            }

            let debug

        }
        else { // column

            // save the bytes
            for (let y = 0, yl = 16, q = 0; y < yl; y++ , q += 16) {
                tmp_buff[y] = table[line + q]
            }
            let yu = 16 - num_slides
            for (let y = 0, yl = 16, q = line; y < yl; y++ , q += 16) {

                table[q] = tmp_buff[(yu + y) & 15]
            }

            let debug

        }
    }
}
function prevent_bit_manipulation(data_obj) {
    /* this function will be replaced by one of our mac
    but it cannot be put here right now; So, dummy macs*/
    data_obj.mac1 = 0x01020304
    data_obj.mac2 = 0xfffefdfc
}
function detect_errors(data_obj) {
    // here will be our mac verification function
    return false
}
function adjust_value_table(table, value) {

    if (table[value] === 0) {
        table[value] = 1
        return value
    }

    for (let x = 0, q = value; x < 256; x++ , q++) {
        let p = q & 255
        if (table[p] === 0) {
            table[p] = 1
            return p
        }
    }
}
function erase_footsteps(data_obj) {

    // with javascript won't be enough but in C we can make sure to zero out memory
    data_obj.incoming_message = ""
    data_obj.shared_secret1 = 0
    data_obj.shared_secret2 = 0
    data_obj.total_length = 0
    data_obj.final_swap1 = 0
    data_obj.final_swap2 = 0
    data_obj.pre_data = ""
    data_obj.post_data = ""
    data_obj.multiple1 = 0
    data_obj.multiple2 = 0
    data_obj.end_arr1 = 0
    data_obj.end_arr2 = 0
    data_obj.end_arr3 = 0
    data_obj.mac1 = 0
    data_obj.mac2 = 0

}
function create_initial_table(modulation_array, start_row, start_column) {

    let table = new Buffer(256)

    // mirror effect
    let direction_row = modulation_array[0] & 1 // left -> right if 1
    let direction_col = modulation_array[0] & 2 // up -> down if 1
    let corner_choice = (modulation_array[0] & 12) >> 2

    // remove after test
    direction_col = 0
    direction_row = 0
    corner_choice = 0
    start_column = 2
    start_row = 2

    let start
    let current_value = 0

    let begin_this_line
    let start_offset
    let grand_counter = 0

    switch (corner_choice) {
        case 0: // upper left
            start = (start_row << 4) + start_column
            begin_this_line = start_column
            start_offset = start_row << 4
            break;
        case 1: // upper right
            start = (start_row << 4) + (16 - start_column)
            begin_this_line = 15 - start_column
            start_offset = start_row << 4
            break;
        case 2: // lower left
            start = (240 - (start_row << 4)) + start_column
            begin_this_line = start_column
            start_offset = (240 - (start_row << 4))
            break;
        case 3: // lower right
            start = (240 - (start_row << 4)) + (16 - start_column)
            begin_this_line = 15 - start_column
            start_offset = (240 - (start_row << 4))
            break;
    }

    let already_set = new Buffer(256)
    if (direction_row) {

        if (direction_col) {

            for (let x = 0; x < 256; x++) {
                let value = current_value++ ^ modulation_array[grand_counter++]
                let suitable_value = adjust_value_table(already_set, value)
                table[start++] = suitable_value //current_value++
                start = (start & 255)
            }
        }
        else {

            /*let begin_this_line = (0 - (16 - first_line_diff)) & 255
            let start_offset = start_row << 4*/
            let begin_this_line_cpy = begin_this_line
            for (let x = 0; x < 16; x++) {
                for (let y = 0; y < 16; y++) {
                    begin_this_line_cpy &= 255
                    let value = begin_this_line_cpy++ ^ modulation_array[grand_counter++]
                    let suitable_value = adjust_value_table(already_set, value)
                    table[start_offset++] = suitable_value //begin_this_line_cpy++
                    start_offset &= 255
                }
                begin_this_line -= 16
                begin_this_line_cpy = begin_this_line
                start_offset &= 255
            }
        }
    }
    else {
        if (direction_col) {

            let begin_this_line_cpy = begin_this_line
            for (let x = 0; x < 16; x++) {
                for (let y = 0; y < 16; y++) {
                    begin_this_line_cpy &= 255
                    let value = begin_this_line_cpy++ ^ modulation_array[grand_counter++]
                    let suitable_value = adjust_value_table(already_set, value)
                    table[start_offset++] = suitable_value//begin_this_line_cpy--
                    start_offset &= 255
                }
                begin_this_line += 16
                begin_this_line_cpy = begin_this_line
                start_offset &= 255
            }
        }
        else {
            let yu
            for (let x = 0; x < 256; x++) {
                let value = current_value++ ^ modulation_array[grand_counter++]
                let suitable_value = adjust_value_table(already_set, value)
                table[start--] = suitable_value // current_value++
                start = (start & 255)
            }
        }
    }

    return table
}

/* ----- Encryption sender */
async function MKL_encrypt_sender(shared_secret1 /*BigInt*/, shared_secret2 /*BigInt*/) {

    let data_obj = {
        incoming_message: "",
        output_message: "",
        offset_message: 0,
        shared_secret1: shared_secret1,
        shared_secret2: shared_secret2,
        total_length: 0,
        final_swap1: 0,
        final_swap2: 0,
        pre_data: "",
        post_data: "",
        multiple1: 0,
        multiple2: 0,
        end_arr1: 0,
        end_arr2: 0,
        end_arr3: 0,
        mac1: 0,
        mac2: 0
    }

    await prepare_data(data_obj, 1)
    await adjusted_huge_number(data_obj)
    await prevent_bit_manipulation(data_obj)
    await concatenate_all_data(data_obj)
    let tabl = await create_initial_table(data_obj.end_arr3, data_obj.final_swap1, data_obj.final_swap2)

    await mix(data_obj, tabl)

    erase_footsteps(data_obj)

    // simulate machine memory 
    obj_bob_machine = data_obj
    return data_obj.output_message
}
/* Messages we send with that protocol are random numbers */
function generate_random_message(data_obj, len) {

    let buff = crypto.randomBytes(len)

    // TODO: remove this line in production
    str_buf = new Buffer.from(buff) /* for debug purposes */

    initial_message_len = len
    data_obj.incoming_message = buff
}
function concatenate_all_data(data_obj) {

    let send_buffer = new Buffer(great_power)

    /* 
    make it dependent of the middle six bytes of that modulation array:
    if the same idx is selected, add one and keep going
    */

    let len = (data_obj.end_arr2.length) >> 2
    let order_arr = new Buffer(5) /* value must != 0; 1: prefake, 2: mac1, 3: message, 4: mac2, 5: postfake*/
    let alternate = (data_obj.end_arr2[(len >> 2)] >> 4) & 1

    let what = (data_obj.end_arr3[(len >> 2) - 5]) & 7

    if (what > 5) {
        what = 7 - what
    }
    let set = 0
    for (let x = 0; x < 5; x++) {

        if (set >= 5) break
        let which_offset
        if (alternate) {
            which_offset = (data_obj.end_arr2[(len >> 2) + x]) & 7
        }
        else {
            which_offset = (data_obj.end_arr1[(len >> 2) + x]) & 7
        }
        alternate ^= alternate

        if (which_offset > 5) {
            which_offset = 7 - which_offset
        }
        if (order_arr[which_offset] === 0) {
            if (++what > 5) { // cannot overlap
                what = 1
            }
            order_arr[which_offset] = what

            set++
            continue
        }
        else {

            for (let y = 0; y < 5; y++) {
                if (which_offset > 5) {
                    which_offset = 0
                }
                if (order_arr[which_offset] === 0) {
                    if (++what > 5) { // cannot overlap
                        what = 1
                    }
                    order_arr[which_offset] = what

                    set++
                    continue
                }
                else {
                    which_offset++
                }
            }
        }
    }

    //console.log(order_arr)
    let offset = 0

    for (let x = 0; x < 5; x++) {
        switch (order_arr[x]) {
            case 1:
                //console.log("concat: in offset pre", offset)
                for (let x = 0, xl = data_obj.pre_data.length; x < xl; offset++ , x++) {
                    // overflow are ignored -> don't care
                    send_buffer[offset] = data_obj.pre_data[x] ^ data_obj.end_arr3[offset]
                }
                //console.log("concat: out offset pre", offset)
                break;
            case 2:
                // mac 
                //console.log("concat: in offset mac1", offset)
                data_obj.offset_mac1 = offset
                send_buffer[offset] = (data_obj.mac1 >> 24) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac1 >> 16) & 0xFF) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac1 >> 8) & 0xFF) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac1) & 0xFF) ^ data_obj.end_arr3[offset++]
                //console.log("concat: out offset mac1", offset)
                break;
            case 3:
                data_obj.offset_message = offset
                //console.log("concat: in offset mess", offset)
                for (let x = 0, xl = data_obj.incoming_message.length; x < xl; offset++ , x++) {

                    //console.log(data_obj.incoming_message[x], data_obj.end_arr3[offset])
                    send_buffer[offset] = data_obj.incoming_message[x] ^ data_obj.end_arr3[offset]
                }
                //console.log("concat: out offset mess", offset)
                break;
            case 4:
                //console.log("concat: in offset mac2", offset)
                data_obj.offset_mac2 = offset
                send_buffer[offset] = (data_obj.mac2 >> 24) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac2 >> 16) & 0xFF) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac2 >> 8) & 0xFF) ^ data_obj.end_arr3[offset++]
                send_buffer[offset] = ((data_obj.mac2) & 0xFF) ^ data_obj.end_arr3[offset++]
                //console.log("concat: out offset mac2", offset)
                break;
            case 5:
                //console.log("concat: in offset post", offset)
                for (let x = 0, xl = data_obj.post_data.length; x < xl; offset++ , x++) {
                    send_buffer[offset] = data_obj.post_data[x] ^ data_obj.end_arr3[offset]
                }
                //console.log("concat: out offset post", offset)
                break;
        }
    }

    data_obj.output_message = send_buffer
    //save_out_message = new Buffer(send_buffer)

}
function mix(data_obj, table) {

    global_in_of_mix_message = new Buffer(data_obj.output_message)
    let len = great_power - 1
    let arr = []

    // table backup
    let table_play_with = new Buffer(256)
    table.copy(table_play_with)
    // which array will we select?
    let f = data_obj.final_swap1
    for (let x = 0; x < 4; x++) {
        arr[x] = (f++) & 3
    }
    // we do 16 table modifications per byte, reading a non overlapping 16-byte block, changing between end_arrs, and direction

    let counter_array = 0

    let q = 0
    swap(data_obj, arr)

    zz:

    for (let x = 0, xl = len /*q = 0*/; x <= xl; x++ , q += 17) {


        q = q & len

        /* do table modification.  */

        let array_modifs = []

        for (let y = 0, yl = 16; y < yl; y++) {

            let data_pointer
            switch (arr[counter_array++]) {
                case 0:
                    data_pointer = data_obj.end_arr1
                    break
                case 1:
                    data_pointer = data_obj.end_arr2
                    break
                case 2:
                    data_pointer = data_obj.end_arr3
                    break;
                case 3:
                    data_pointer = data_obj.end_arr1
                    break;
            }

            let u = q + y // real offset

            let is_row = data_pointer[u] & 0x80
            /* default direction : 
                row = left->right
                col = up->down*/
            let is_reverse_direction = data_pointer[u] & 0x40
            let is_reverse_direction2 = data_pointer[u] & 0x20
            let line = data_pointer[u] >> 4
            let move = data_pointer[u] & 15
            if (is_reverse_direction) {
                if (is_reverse_direction2) {
                    for (let z = 0, zl = move; z < zl; z++) {

                        array_modifs.push([is_row, (line - z) & 15, ((move - z) & 15)])

                        last_op = is_row
                    }
                }
                else {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line + z) & 15, ((move - z) & 15)])
                    }
                }

            }
            else {
                if (is_reverse_direction2) {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line - z) & 15, ((move + z) & 15)])
                    }
                }
                else {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line + z) & 15, ((move + z) & 15)])
                    }
                }
            }
            counter_array = counter_array & 3

        }
        apply_table_transformations(table_play_with, array_modifs)
        let offset_in_table = data_obj.output_message[x]
        let retrieve_value = table_play_with[offset_in_table]
        data_obj.output_message[x] = retrieve_value
        // reset_table
        // not that efficient but I don't have a better way for now
        table.copy(table_play_with)
        counter_array = 0

    }


    global_out_of_mix_message = new Buffer(data_obj.output_message)
    //compare_mix_unmix.pop()

}
function swap(data_obj, arr) {

    let counter_array = 0
    let len = great_power - 1

    // swap some bytes.
    for (let x = 0, xl = len, q = 0; x <= xl; x++ , q++) {

        let data_pointer
        switch (arr[counter_array]) {
            case 0:
                data_pointer = data_obj.end_arr1
                break
            case 1:
                data_pointer = data_obj.end_arr2
                break
            case 2:
                data_pointer = data_obj.end_arr3
                break;
            case 3:
                data_pointer = data_obj.end_arr1
                break;
        }

        q = q & len

        let is_leave_alone = data_pointer[q] & 0x20
        let is_exchange_look_back = data_pointer[q] & 0x8
        let value_exchange_gap = (data_pointer[q] & 0x7) >>> 0

        let w
        if (is_leave_alone) {

            counter_array++
            counter_array = counter_array & 3
            continue
        }

        if (is_exchange_look_back) {
            w = x - value_exchange_gap
            if (w < 0) {
                w = (xl + w)
                value_exchange_gap = w

            }
            else {
                value_exchange_gap = w

            }
        }
        else {
            w = x + value_exchange_gap
            if (w >= (xl)) {
                w = (w - xl)
                value_exchange_gap = w

            }
            else {
                value_exchange_gap = w

            }

        }

        counter_array++
        counter_array = counter_array & 3
        let retrieve_value = data_obj.output_message[value_exchange_gap]
        let this_value = data_obj.output_message[x]
        data_obj.output_message[value_exchange_gap] = this_value
        data_obj.output_message[x] = retrieve_value
        //console.log("from ",x," to ",value_exchange_gap)

    }
}

/* ----- Decryption sender */

async function MKL_decrypt_sender(result) {
    // simulate different machines on network
    let data_obj = obj_bob_machine

    if (result[data_obj.offset_message] > 127) {
        console.log("The peer received the message you sent properly")
    }
    else {
        console.log("The peer had an error with the received message")
    }

    console.log("end of the game")
}

/* ----- Encryption receiver */

async function MKL_encrypt_receiver(data_obj) {

    if (detect_errors(data_obj)) {
        send_back_to_sender(data_obj, false)
    }
    else {
        send_back_to_sender(data_obj, true)
    }
    erase_footsteps(data_obj)
    /* for the simulation we return the output_message this way */
    return data_obj.output_message
}

function send_back_to_sender(data_obj, answer) {

    let send_buffer = crypto.randomBytes(data_obj.output_message.length)
    /* don't use the shared secrets. That would add some information. About the data structure
    Yet, use the original message offset to send the answer (1 byte) */

    if (answer) {
        if (send_buffer[data_obj.offset_message] < 128) {
            send_buffer[data_obj.offset_message] -= 128
        }
    }
    else {
        if (send_buffer[data_obj.offset_message] > 127) {
            send_buffer[data_obj.offset_message] += 128
        }
    }

    //Make sure nobody tampered the answer
    add_mac(data_obj, send_buffer)
    // send
    data_obj.output_message = send_buffer

}
function add_mac(data_obj, send_buffer) {

    // TODO: use our mac function here. Just use dummy results for now
    send_buffer[data_obj.offset_mac1] = 0x01
    send_buffer[data_obj.offset_mac1 + 1] = 0x02
    send_buffer[data_obj.offset_mac1 + 2] = 0x03
    send_buffer[data_obj.offset_mac1 + 3] = 0x04

    send_buffer[data_obj.offset_mac2] = 0xFA
    send_buffer[data_obj.offset_mac2 + 1] = 0xFB
    send_buffer[data_obj.offset_mac2 + 2] = 0xFC
    send_buffer[data_obj.offset_mac2 + 3] = 0xFD

}

/* ----- Decryption receiver */

async function MKL_decrypt_receiver(cypher_text /*Buffer*/, shared_secret1 /*BigInt*/, shared_secret2 /*Bigint*/) {

    let data_obj = {
        incoming_message: cypher_text,
        output_message: "",
        shared_secret1: shared_secret1,
        shared_secret2: shared_secret2,
        offset_message: 0,
        final_swap1: 0,
        final_swap2: 0,
        pre_data: "",
        post_data: "",
        multiple1: 0,
        multiple2: 0,
        end_arr1: 0,
        end_arr2: 0,
        end_arr3: 0,
        mac1: 0,
        mac2: 0
    }

    await prepare_data(data_obj, 0)
    await adjusted_huge_number(data_obj)
    let tabl = await create_initial_table(data_obj.end_arr3, data_obj.final_swap1, data_obj.final_swap2)

    await unmix(data_obj, tabl)
    await deconcatenate_all_data(data_obj)
    if (detect_errors()) {
        data_obj.output_message = ""
    }

    // TODO: remove this when out of debug phase
    // check
    for (let x = 0, xl = initial_message_len; x < xl; x++) {
        if (str_buf[x] != data_obj.output_message[x]) {
            console.log("error: differing message at offset" + x)
        }
    }

    return data_obj
}
function unswap(data_obj, arr) {

    let len = great_power - 1
    let start_q = len
    let counter_array = len & 3

    for (let x = len, xl = 0, q = start_q; x >= xl; x-- , q--) {

        let data_pointer
        switch (arr[counter_array]) {
            case 0:
                data_pointer = data_obj.end_arr1
                break
            case 1:
                data_pointer = data_obj.end_arr2
                break
            case 2:
                data_pointer = data_obj.end_arr3
                break;
            case 3:
                data_pointer = data_obj.end_arr1
                break;
        }

        q = q & len

        let is_leave_alone = data_pointer[q] & 0x20
        let is_exchange_look_back = data_pointer[q] & 0x8
        let value_exchange_gap = (data_pointer[q] & 0x7) >>> 0

        if (is_leave_alone) {

            counter_array--
            counter_array = counter_array & 3
            continue
        }
        if (is_exchange_look_back) {
            w = x - value_exchange_gap
            if (w < 0) {
                w = (len + w)
                value_exchange_gap = w
            }
            else {
                value_exchange_gap = w
            }

        }
        else {
            w = x + value_exchange_gap
            if (w >= (len)) {
                w = (w - len)
                value_exchange_gap = w
            }
            else {
                value_exchange_gap = w
            }
        }
        counter_array--
        counter_array = counter_array & 3
        let retrieve_value = data_obj.incoming_message[value_exchange_gap]
        let this_value = data_obj.incoming_message[x]
        data_obj.incoming_message[value_exchange_gap] = this_value
        data_obj.incoming_message[x] = retrieve_value

    }
}
function unmix(data_obj, table) {

    for (let x = 0, xl = data_obj.incoming_message.length; x < xl; x++) {
        if (data_obj.incoming_message[x] != global_out_of_mix_message[x]) {
            console.log("error")
        }
    }
    let len = great_power - 1
    let arr = []

    // table backup
    let table_play_with = new Buffer(256)
    table.copy(table_play_with)
    // which array will we select?
    let f = data_obj.final_swap1
    for (let x = 0; x < 4; x++) {
        arr[x] = (f++) & 3
    }
    // we do 16 table modifications per byte, reading a non overlapping 16-byte block, changing between end_arrs, and direction

    //let max_block_bytes = len >> 4 // 16 bytes


    let q = (len * 17) & len
    //let x = len

    // avoids a division, since great power is not that high (1024 max)
    /*while (x < (great_power - 1)) {
        x += len
    }*/

    let x = len

    let counter_array = 0 //x & 3

    zz:
    for (let xl = 0 /*q = last_q*/; x >= xl; x-- , q -= 17) {

        q = q & len

        /* do table modification.  */
        //let offset_in_table = data_obj.incoming_message[x]
        let array_modifs = []

        for (let y = 0, yl = 16; y < yl; y++) {

            let data_pointer
            switch (arr[counter_array++]) {
                case 0:
                    data_pointer = data_obj.end_arr1
                    break
                case 1:
                    data_pointer = data_obj.end_arr2
                    break
                case 2:
                    data_pointer = data_obj.end_arr3
                    break;
                case 3:
                    data_pointer = data_obj.end_arr1
                    break;
            }

            let u = q + y// real offset

            let is_row = data_pointer[u] & 0x80
            /* default direction : 
                row = left->right
                col = up->down*/
            let is_reverse_direction = data_pointer[u] & 0x40
            let is_reverse_direction2 = data_pointer[u] & 0x20
            let line = data_pointer[u] >> 4
            let move = data_pointer[u] & 15

            counter_array &= 3
            if (move === 0) {
                continue
            }

            if (is_reverse_direction) {
                if (is_reverse_direction2) {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line - z) & 15, ((move - z) & 15)])
                    }
                }
                else {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line + z) & 15, ((move - z) & 15)])
                    }
                }

            }
            else {
                if (is_reverse_direction2) {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line - z) & 15, ((move + z) & 15)])
                    }
                }
                else {
                    for (let z = 0, zl = move; z < zl; z++) {
                        array_modifs.push([is_row, (line + z) & 15, ((move + z) & 15)])
                    }
                }
            }


        }
        apply_table_transformations(table_play_with, array_modifs)
        let retrieve_value = data_obj.incoming_message[x]
        for (let y = 0; y < 256; y++) {
            if (table_play_with[y] === retrieve_value) {

                /*if (compare_mix_unmix[x][1] != retrieve_value) {
                    console.log("error", x)
                    return ""
                }
                if (compare_mix_unmix[x][0] != y) {
                    console.log("error2", x)
                    return ""
                }
                if (compare_mix_unmix[x][2] != q) {
                    console.log("error3", x)
                    return ""
                }
                if (compare_mix_unmix[x][3] != counter_array) {
                    console.log("error4", x)
                    return ""
                }*/
                data_obj.incoming_message[x] = y
                break
            }
        }

        // reset_table
        table.copy(table_play_with)
        counter_array = 0
    }

    unswap(data_obj, arr)

    for (let x = 0, xl = data_obj.incoming_message.length; x < xl; x++) {
        if (data_obj.incoming_message[x] != global_in_of_mix_message[x]) {
            console.log("error")
        }
    }

}
function deconcatenate_all_data(data_obj) {

    /*for (let x = 0, xl = data_obj.incoming_message.length; x < xl; x++) {
        if (data_obj.incoming_message[x] != save_out_message[x]) {
            console.log("error")
        }
    }*/

    /* 
    make it dependent of the middle six bytes of that modulation array:
    if the same idx is selected, add one and keep going
    */

    let len = (data_obj.end_arr2.length) >> 2
    let order_arr = new Buffer(5) /* value must != 0; 1: prefake, 2: mac1, 3: message, 4: mac2, 5: postfake*/
    let alternate = (data_obj.end_arr2[(len >> 2)] >> 4) & 1

    let what = (data_obj.end_arr3[(len >> 2) - 5]) & 7
    if (what > 5) {
        what = 7 - what
    }
    let set = 0
    for (let x = 0; x < 5; x++) {

        if (set >= 5) break
        let which_offset
        if (alternate) {
            which_offset = (data_obj.end_arr2[(len >> 2) + x]) & 7
        }
        else {
            which_offset = (data_obj.end_arr1[(len >> 2) + x]) & 7
        }
        alternate ^= alternate

        if (which_offset > 5) {
            which_offset = 7 - which_offset
        }
        if (order_arr[which_offset] === 0) {
            if (++what > 5) { // cannot overlap
                what = 1
            }
            order_arr[which_offset] = what

            set++
            continue
        }
        else {

            for (let y = 0; y < 5; y++) {
                if (which_offset > 5) {
                    which_offset = 0
                }
                if (order_arr[which_offset] === 0) {
                    if (++what > 5) { // cannot overlap
                        what = 1
                    }
                    order_arr[which_offset] = what

                    set++
                    continue
                }
                else {
                    which_offset++
                }
            }
        }
    }

    //console.log(order_arr)
    let offset = 0

    // length
    let pre_data_length = data_obj.pre_data.length
    let post_data_length = data_obj.post_data.length
    let macs_length_total = 8
    let message_length = data_obj.incoming_message.length - pre_data_length - post_data_length - macs_length_total
    let send_buffer = new Buffer(message_length)

    for (let x = 0; x < 5; x++) {
        switch (order_arr[x]) {
            case 1:
                //don't care
                //console.log("deconcat: in offset pre", offset)
                offset += pre_data_length
                //console.log("deconcat: out offset pre", offset)
                break;
            case 2:
                //console.log("deconcat: in offset mac1", offset)
                // mac 
                data_obj.offset_mac1 = offset
                data_obj.mac1 = 0
                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac1 |= (yu << 24)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac1 |= (yu << 16)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac1 |= (yu << 8)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac1 |= yu
                data_obj.mac1 >>>= 0
                //console.log("deconcat: out offset mac1", offset)
                break;
            case 3:
                data_obj.offset_message = offset
                //console.log("deconcat: in offset mess", offset)
                for (let x = 0, xl = message_length; x < xl; offset++ , x++) {
                    // overflow -> don't care
                    //console.log(data_obj.incoming_message[offset], data_obj.end_arr3[offset])
                    send_buffer[x] = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset]
                }
                //console.log("deconcat: out offset mess", offset)
                break;
            case 4:
                //console.log("deconcat: in offset mac2", offset)
                data_obj.offset_mac2 = offset
                data_obj.mac2 = 0
                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac2 |= (yu << 24)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac2 |= (yu << 16)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac2 |= (yu << 8)

                yu = data_obj.incoming_message[offset] ^ data_obj.end_arr3[offset++]
                data_obj.mac2 |= yu
                data_obj.mac2 >>>= 0
                //console.log("deconcat: out offset mac2", offset)
                break;
            case 5:
                //don't care
                //console.log("deconcat: in offset post2", offset)
                offset += post_data_length
                //console.log("deconcat: out offset post2", offset)
                break;
        }
    }

    data_obj.output_message = send_buffer
}

async function main() {
    /* Bob and Alice have exchanged their initial shared secret by hands
    There are 2 exchanges that are completely unrelated. Bob takes the initiative to contact Alice.
    */
    // from Bob..
    let cypher = await MKL_encrypt_sender(shared_secret1, shared_secret2)
    //..Network..
    //.. to Alice
    let result_object = await MKL_decrypt_receiver(cypher, shared_secret1, shared_secret2)
    let cypher_back = await MKL_encrypt_receiver(result_object)
    //..Network..
    //.. back to Bob
    await MKL_decrypt_sender(cypher_back)


    console.log("done")
}
main()
\$\endgroup\$
  • \$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. Please post a follow-up question instead. \$\endgroup\$ – Mast Feb 8 at 15:08
  • 1
    \$\begingroup\$ Ok sorry, will keep that in mind \$\endgroup\$ – MKL Feb 8 at 15:09
2
\$\begingroup\$

Too long

That is a lot of code, and I don't have a clue what is should be doing. But then neither does the machine you run it on.

  • It is full of repeated and redundant code.

    Removing comments and whitespaces trimmed 200+ lines.

    Compacting code by removing needless line breaks, using ternary operators, using functions to do repeated code, removing switch statement in favour of array lookups, I was down to 600 lines and there was a lot left to cut out.

    You basically have more than half the content (1200 lines in the question snippet) that contributes nothing to the functionality. I estimate that the whole thing can be written in less than 400 lines, be easier to read and maintain, and run more efficiently.

  • Don't declare length variables in for loops, that optimization became history a decade ago.

  • Use for of loops in favour of for ; ; loops
  • Remove useless code. You have labels and variable declarations that are never used.
  • JavaScript requires semicolons, use them unless you know every edge case where ASI can catch you out. if you don't know what ASI is then use semicolons!
  • Some bad (evil) coder one day missed the old spaghetti days when goto was all the rage. But goto had such a bad reputation nobody would accept its use anymore. So he came up with continue and labels and thus goto 10 became continue label

    continue is a hack, a goto in disguise, a hard to see break in flow. I have written a zillion lines of code and have never needed to use continue or declare a label in released code.

  • If a function is more than a page long, its too long.

  • Use const for variable that do not (and thus should not) change.
  • Removing code via comments is a bad habit. Good code does not have any code inside comments. (Granted there is reason during testing and development to temp out code with comments, but when done it should be removed)
  • JavaScript uses camelCase and if you write JS so should you.
  • Sign that an array is in order. If you have variables named end_arr1, end_arr2, end_arr3 it's a sure sign that it should be an array.

    The following code

data_obj.shared_secret1 = 0
data_obj.shared_secret2 = 0
data_obj.final_swap1 = 0
data_obj.final_swap2 = 0
data_obj.multiple1 = 0
data_obj.multiple2 = 0
data_obj.mac1 = 0
data_obj.mac2 = 0

is repeated again and again. So much code can be removed if you used an array and indexed the 1,2

\$\endgroup\$
  • \$\begingroup\$ One more rather minor thing - there is a bunch of async and await statements but I don't think any of the code is actually asynchronous. \$\endgroup\$ – VLAZ Feb 9 at 10:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.