javascriptcaesar-ciphertranscription

Decryption and encryption algoritms funky


I made a little script for custom encryption and decryption algorithms, which are based on Caesar cipher and transcription cipher.

First a little bit of background for explanation on how it should work. Assume a message you want to encrypt before sending. You apply Caesar cipher to it, which is shift each letter by 3 positions in alphabet to right. Then you take that encrypted text and divide it to sections by number of letters your key has. Let's say your message has n letters, and your key has m letters. Then your message should be broken up to n/m sections (rounding up or ceiling), each one of m letters. If the message length isn't divisible by the number of letters in key, then it has to be padded to fill in missing letters by letter A. Then given by the key, you transpose the columns based on the position of that particular letter of key corresponding to column number in alphabet. So if your key is let's say LEAK, then columns have to be transposed based on the position as follows: 3241, because 1234 corresponds to AEKL (sorted by alphabetical order). Then this transposed matrix is then concatenated back to the corresponding string, which then can be sent. Decipher is basically the same process reversed in order → You receive a message, and you know the key. You parcel it to columns and then transpose the columns in order to correspond to alphabetical order of the letters from key, concatenate it back, and then run through reverse Caesar cipher (shift letters by 3 positions in alphabet to the left). You may get a few X letters at the end, that doesn't actually matter.

Now to my issue: I wrote a little Javascript program for it, it is in fact a module, and I also have a test script for it to see how it works. But it doesn't work correcly. The transposition is wrong, which results in deciphered text being malformed. I know the deciphered text as I've done this algorithm manually before writing that script and I know the outcome it should have.

This is the module:

module.exports = {
    decrypt: (message, key) => {
        if(message.length % key.length != 0) {
            throw new Error(`Lenght of message is not divisible by lenght of the key! ${message.length} is not divisible by ${key.length}!`);
        }
        
        let key_array_unsorted = key.split('');
        let key_array_sorted = key.split('').sort();

        let message_matrix = [];
        for(i = 0; i < message.length / key.length; ++i) {
            let quartet = [];

            for(j = 0; j < key.length; ++j) {
                quartet.push(message.charAt(i*key.length + j));
            }

            message_matrix.push(quartet);
        }

        let message_matrix_shuffled = [];
        message_matrix.forEach(quartet => {
            let quartet_shuffled = [];

            for(i = 0; i < key.length; ++i) {
                for(j = 0; j < key.length; ++j) {
                    if(key_array_unsorted[i] == key_array_sorted[j]) {
                        quartet_shuffled.push(quartet[j]);
                    }
                }
            }

            message_matrix_shuffled.push(quartet_shuffled);
        });

        let message_quartets = [];
        message_matrix_shuffled.forEach(quartet => {message_quartets.push(quartet.join(''))});

        let message_caesar = message_quartets.join('');

        let message_deciphered = "";
        for(i = 0; i < message_caesar.length; ++i) {
            let charcode = message_caesar.charCodeAt(i);
            let alphanum = charcode - 65;

            let alphanum_new = (alphanum + 23) % 26;
            let charcode_new = alphanum_new + 65;

            message_deciphered += String.fromCharCode(charcode_new);
        }

        return message_deciphered;
    },

    encrypt: (message, key) => {
        let message_caesar = "";

        for(i = 0; i < message.length; ++i) {
            let charcode = message.charCodeAt(i);
            let alphanum = charcode - 65;

            let alphanum_new = (alphanum + 3) % 26;
            let charcode_new = alphanum_new + 65;

            message_caesar += String.fromCharCode(charcode_new);
        }

        for(i = 0; i <= Math.ceil(message_caesar.length / key.length) * key.length - message_caesar.length; ++i) {
            message_caesar += "A";
        }

        let key_array_unsorted = key.split('');
        let key_array_sorted = key.split('').sort();

        let message_matrix = [];
        for(i = 0; i < message_caesar.length / key.length; ++i) {
            let quartet = [];

            for(j = 0; j < key.length; ++j) {
                quartet.push(message_caesar.charAt(i*key.length + j));
            }

            message_matrix.push(quartet);
        }

        let message_matrix_shuffled = [];
        message_matrix.forEach(quartet => {
            let quartet_shuffled = [];

            for(i = 0; i < key.length; ++i) {
                for(j = 0; j < key.length; ++j) {
                    if(key_array_sorted[i] == key_array_unsorted[j]) {
                        quartet_shuffled.push(quartet[j]);
                    }
                }
            }

            message_matrix_shuffled.push(quartet_shuffled);
        });

        let message_quartets = [];
        message_matrix_shuffled.forEach(quartet => {message_quartets.push(quartet.join(''))});

        let message_ciphered = message_quartets.join('');
        return message_ciphered;
    }
}

And this is the test script:

const cipher = require('./cipher');

let message = "HGYRDGQCREGLDYQROXRHABAK";
let key = "OMYL";

console.log(`Received message: ${message}`);
console.log(`Known passphrase: ${key}`);

let message_deciphered = cipher.decrypt(message, key);
console.log(`Deciphered message: ${message_deciphered}`);

let message_encrypted = cipher.encrypt(message_deciphered, key);
console.log(`Control encryption: ${message_encrypted}`);

The module and the test scripts are in the same folder.

This is how the output should have been:

Received message: HGYRDGQCREGLDYQROXRHABAK
Known passphrase: OMYL
Deciphered message: ODEVZDANIBODOVANEULOHYXX
Control encryption: HGYRDGQCREGLDYQROXRHABAK

And this is current output:

Received message: HGYRDGQCREGLDYQROXRHABAK
Known passphrase: OMYL
Deciphered message: VDOENDZADBIONVOAOUELXYHX
Control encryption: HGYRDGQCREGLDYQROXRHABAK

Now, I know for sure that the key's letters are sorted correctly and that's not the cause of the incorrect transcription, I actually looked for the key's letters being sorted correctly and it's okay. OMYL does in fact sort correctly to LMOY.

The issue has to be in the transcription itself, where it doesn't correspond to the alphabetical order of the key. The thing is, I can't for some reason spot a mistake, if there is any. I guess Javascript isn't really much good language to use for such thing, but it is fairly easy and doesn't require compilation. All I wanted to do is make myself a gadget or tool to make quick solver for my assignment, which I get in Monday and I already know the topic for that assignment, which is that cipher.

Maybe I am doing it wrong, maybe I shouldn't actually use the key letters to be compared and instead build a sort of shuffle map for the transcription based on the alphabetical order of the key letters (and of course the order of steps - encryption or decryption). Which is something I don't know how to do, unfortunately :(


Solution

  • Based on the algorithm given by the OP in the chat, the code word sequencing is wrong

    Compare sorted sequence with unsorted sequence instead of the other way

    Replace key_array_unsorted[i] == key_array_sorted[j] with key_array_sorted[i] == key_array_unsorted[j]