2

I am trying to run an encryption algorithm that takes an input message, breaks it up into blocks of four characters, moves "x" bits from the front to the back, and then converts it back into four scrambled characters. I believe that this is called a block-shift cipher, although I am not quite sure. The program can encrypt and decrypt perfectly fine when running in Python. However, after converting the code, by hand, into JavaScript, I was getting some strange results from the String.fromCharCode method. To put it quite simply, the JavaScript method is returning more characters, specifically "" characters, than Python is, even when the message and key are being kept the same. I would appreciate any help for how to solve this problem and what exactly the problem is.

This code is for a tool that I am developing, and I need to get it completed as fast as possible. I have already tried converting the JavaScript character encodings into "UTF-8" using the utf8 module from the Node Package Manager, to no avail. I double-checked my code several times, and, other than the character converting, the Python and JavaScript code are doing the same thing, and are producing the same numbers and values. In the below code, the problems I am mentioning are originating from the "reconstructMsg" function in the JavaScript code.

// JavaScript:
import integerBitLength from 'integer-bit-length';

// Function to break message into chunks
function chunkMsg(message, chunkSize = 4) {
  // Create an array to store the chunks
  let msgChunks = [];
  // Control
  let chunk = 0,
    chunkCount = Math.floor(message.length / chunkSize) + 1;

  // Iterate through the message
  for (let num of [
    ...Array(chunkCount * chunkSize).keys()
  ]) {
    // Make room for the next chunk's number
    chunk = chunk << 8;
    // Make sure that 'num' is within the length of 'message'
    if (num < message.length) chunk += message[num].charCodeAt(0);
    // Check if there are the ascii values of four characters in the chunk
    if (integerBitLength(chunk) > (chunkSize - 1) * 8) {
      // Append chunk
      msgChunks.push(chunk);
      // Reset chunk
      chunk = 0;
    }
  }

  // Return the chunk array
  return msgChunks;
}

// Function to reconstruct message
function reconstructMsg(chunks, chunkSize = 4) {
  // Empty message
  let msg = '';
  // Iterate through all of the chunks
  for (let i = 0; i < chunks.length; i++) {
    let chunk = chunks[i];
    // Loop through each chunk
    for (let j = 0; j < chunkSize; j++) {
      // NOTES on the below code
      // (8 * (chunk_size - 1 - j)) is the number of bits to chop off of the end
      // (chunk >> <above_code>) chops the number of bits above off of the chunk
      // <above_code> % 2 ** 8 takes only the first 8 bits from the above code
      // because 2 ** 8 = 256
      // the modulo function (x % y) can have a max value of "y - 1" and 8 bits can have a max value of 255
      // In other words, because everything above the 8th bit is a multiple of 256, we ignore them
      let number = (chunk >>> (8 * (chunkSize - 1 - j))) % 2 ** 8;
      // Add the character with the above keycode to the message
      msg += String.fromCharCode(number);
    }
  }
  // Return the message
  return msg;
}

// Function to encrypt chunks in a message
function encryptMsg(chunks, key, chunkSize = 4) {
  // List of encrypted chunks
  let cipherList = [];
  // Set the maximum amount of bits
  let bitCount = chunkSize * 8;
  // Iterate through the chunks
  for (let i of [
    ...Array(chunks.length).keys()
  ]) {
    // Set chunk
    let chunk = chunks[i];
    // Set the bits to carry
    let carry = chunk % 2 ** key;
    // Make room for the remaining bits to be places at the end
    carry = (carry << (bitCount - key)) >>> 0;
    // Combine the shifted characters
    let cipher = (chunk >>> key) + carry;
    // Add cipher
    cipherList.push(cipher);
  }
  // Return the cipher list
  return cipherList;
}
# Python:
# Function to chunk message into sets of 32-bits
def chunk_msg(msg, chunk_size=4):
    # Create a list to store the chunks
    msg_chunks = []

    # Control variables
    chunk = 0
    chunk_count = len(msg) // chunk_size + 1

    # Iterate through the message
    for i in range(chunk_count * chunk_size):
        # Make room for the next character's number
        chunk = chunk << 8
        # Make sure that i is within the length of the function
        if i < len(msg):
            chunk += ord(msg[i])
        # If the chunk has 4 characters in their ascii encoding, save the chunk
        if chunk.bit_length() > (chunk_size - 1) * 8:
            msg_chunks.append(chunk)
            chunk = 0
    # Return the chunks
    return msg_chunks


# Function to reconstruct message
def reconstruct_msg(chunks, chunk_size=4):
    # Empty message
    msg = ""
    # Iterate through all of the chunks
    for i in range(len(chunks)):
        chunk = chunks[i]
        # Loop through each chunk
        for j in range(chunk_size):
            # NOTES on the below code
            # (8 * (chunk_size - 1 - j)) is the number of bits to chop off of the end
            # (chunk >> <above_code>) chops the number of bits above off of the chunk
            # <above_code> % 2 ** 8 takes only the first 8 bits from the above code
            # because 2 ** 8 = 256
            # the modulo function (x % y) can have a max value of "y - 1" and 8 bits can have a max value of 255
            # In other words, because everything above the 8th bit is a multiple of 256, we ignore them
            number = (chunk >> (8 * (chunk_size - 1 - j))) % 2**8
            print(number)
            # Add the character with the above keycode to the message
            msg += chr(number)
            print(f"\n\n{chr(number)}")

    # Return the message
    return msg


# Function to encrypt chunks
def apply_rotate(msg_list, key, chunk_size=4):
    cipher_list = []
    # Set the maximum amount of bits
    bit_count = chunk_size * 8
    # Iterate through each message chunk
    for i in range(len(msg_list)):
        # Set chunk
        chunk = msg_list[i]
        print(chunk)
        # Set the bits to carry
        carry = chunk % (2**key)
        # Make room for the remaining bits to be placed on the end
        carry = carry << (bit_count - key)
        # Combine the shifted characters into a variable
        cipher = (chunk >> key) + carry
        # Add the encoded chunk to the list
        cipher_list.append(cipher)
    print(cipher_list)
    # Return the cipher list
    return cipher_list

When the above functions are run in the order: chunkMsg, encryptMsg, and reconstructMsg, with a message of "Hello" and a key of 12, Python produces the correct string, "ÆÄV ð", while JavaScript produces, the incorrect string, "ÆÄVð" (There are undefined characters between the Ä and the V, the V and the ð, and the ð and the end of the message. They may not show up in the question once it is posted).

Once again, I would deeply appreciate any help in this matter and apologize if the question is a little lengthy.

NightOwl
  • 21
  • 4
  • 1
    First thing to note is that JavaScript uses UTF-16 internally for strings; each character is 16 bits, not 8. – Pointy Aug 06 '19 at 16:44
  • Yes, that is why I tried using the utf8 npm module, but I was unable to make it work successfully. Some of the numbers causing an issue when being put through the two different number to character conversions are 134, 0, and 6. – NightOwl Aug 06 '19 at 16:47
  • Not all bit patterns and byte sequences are valid character encoding code units. So, encryption algorithms usually just operator on bytes and bits. If someone feeds in text then it has to be with some character encoding and the receiver has to be given that information. Similarly, if you Base64 encode the output in order to get data that can be handled as text, the receiver has to be told that, too. – Tom Blodget Aug 06 '19 at 20:21
  • I am sorry @TomBlodget, but I do not quite understand how this relates to the problem that I am having. – NightOwl Aug 06 '19 at 20:52
  • In Python, you are processing text strings. I suggest you use byte strings or arrays. – Tom Blodget Aug 06 '19 at 20:58
  • What would that look like, for my case specifically? I have never used byte strings or arrays before. – NightOwl Aug 06 '19 at 21:59

0 Answers0