Creating a Simple JavaScript Tool for Text Encryption

in #security4 days ago

This publication continues a topic initiated in the Ukrainian community, where an example of the first version of a JavaScript web form for encrypting text data was presented. The script is fairly simple, perhaps even primitive, but its idea lies in creating a tool for the long-term storage of text data in encrypted form.

JavaScript Tool for Text Encryption

  • codeTable contains mappings of characters to numbers, which are used for text encoding.
  • decodeTable is automatically generated from codeTable by swapping keys and values, ensuring the reverse process—decoding.
  • Each character in the text is converted into a code based on codeTable.
  • If a password is set, an offset is applied, calculated based on the ASCII codes of the password's characters, for additional protection.
  • The generated code is formatted to a fixed length of four characters, ensuring uniform data representation.

When decoding the text, the user enters a password if it was used during encryption. The program processes the text by extracting every four characters (code) and applying the reverse offset calculated from the ASCII codes of the password characters. If, after applying the offset, the code matches a character from decodeTable, that character is added to the decoded text. If the code does not correspond to any entry in the decoding table, the process stops, and the user is shown an error message.

  • The password adds an additional layer of security by shifting the codes. If no password is provided, the offset is set to zero.
  • If the input text contains invalid codes or an incorrect password is entered, the decoding process is terminated.
  • Only characters listed in the codeTable are considered valid.

To improve encryption security, it is recommended to replace the standard character codes in codeTable with custom ones. However, it is crucial to ensure that the codes are unique and have no duplicates to avoid errors during decoding.

This script can be useful for storing information that needs to be encoded to ensure minimal protection or for converting text into a unique numerical format.

Potential uses:

  • Storing texts that should not be immediately readable.
  • Hiding data from casual observation.
  • Suitable only for lightweight encoding where strong cryptography is not required.

The full script with minimal web form design:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Encoding and Decoding</title>
<style>
    body {
        background: linear-gradient(to right, #f2f2f2, #d9d9d9);
        font-family: Arial, sans-serif;
        color: #333;
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
    }

    #main {
        margin: 5px auto;
        padding: 30px;
        width: 600px;
        background: #fff;
        border-radius: 10px;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        text-align: center;
    }

    h2 {
        color: #444;
        font-size: 24px;
        margin-bottom: 20px;
    }

    #password {
        width: 90%;
        padding: 12px;
        margin: 10px 0;
        border: 1px solid #ddd;
        border-radius: 8px;
        font-size: 16px;
        transition: border-color 0.3s ease;
        box-sizing: border-box;
    }
    #password:focus {
        border-color: #007bff;
        outline: none;
        box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
    }

    textarea {
        width: 90%;
        height: 150px;
        padding: 15px;
        border: 1px solid #ddd;
        border-radius: 8px;
        font-size: 16px;
        resize: vertical;
        transition: border-color 0.3s ease;
    }
    textarea:focus {
        border-color: #007bff;
        outline: none;
    }

    button {
        background-color: #007bff;
        color: #fff;
        border: none;
        border-radius: 8px;
        padding: 10px 20px;
        font-size: 16px;
        cursor: pointer;
        transition: background-color 0.3s ease;
        margin-top: 10px;
    }

    button:hover {
        background-color: #0056b3;
    }

    hr {
        border: 0;
        height: 1px;
        background: #ddd;
        margin: 20px 0;
    }

    div {
        text-align: left;
        font-size: 14px;
        color: #666;
    }

    @media (max-width: 768px) {
        #main {
            width: 90%;
            padding: 20px;
            box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
        }
    }

    @media (max-width: 480px) {
        #main {
            padding: 15px;
        }
    }
</style>
</head>

<body>

    <div id="main">

    <h2>Text Encoding</h2>
    <textarea id="encode" placeholder="Enter text for encoding"></textarea>
    <button onclick="encodeText()">Encode</button>

    <hr size="1">
    <input type="password" id="password" placeholder="Enter password" />
    <hr size="1">

    <h2>Text Decoding</h2>
    <textarea id="decode" placeholder="Enter encoded text"></textarea>
    <button onclick="decodeText()">Decode</button>

        <div>
        <br /><br />
        <b><u>Valid characters for use</u>:</b><br /><br />
            &bull; English letters;<br />
            &bull; numbers;<br />
            &bull; !@#$%^&*()_+-=`~'";:<>[]{}/\|,.<br />
            &bull; space, line break.
        </div>

    </div>

<script>
    // Encoding table
    const codeTable = {
        'A': 342, 'B': 126, 'C': 615, 'D': 943, 'E': 208, 'F': 375, 'G': 691, 'H': 462, 'I': 653, 'J': 832,
        'K': 504, 'L': 215, 'M': 348, 'N': 728, 'O': 156, 'P': 101, 'Q': 237, 'R': 409, 'S': 516, 'T': 721,
        'U': 154, 'V': 664, 'W': 307, 'X': 930, 'Y': 578, 'Z': 287, 'a': 731, 'b': 293, 'c': 587, 'd': 645,
        'e': 190, 'f': 458, 'g': 803, 'h': 324, 'i': 567, 'j': 412, 'k': 185, 'l': 934, 'm': 209, 'n': 572,
        'o': 252, 'p': 384, 'q': 617, 'r': 850, 's': 456, 't': 139, 'u': 445, 'v': 299, 'w': 740, 'x': 732,
        'y': 345, 'z': 859, '0': 193, '1': 574, '2': 806, '3': 259, '4': 437, '5': 618, '6': 920, '7': 134,
        '8': 752, '9': 463, '!': 370, '@': 519, '#': 603, '$': 658, '%': 312, '^': 107, '&': 275, '*': 983,
        '(': 641, ')': 517, '_': 408, '+': 201, '-': 730, '=': 592, '`': 379, '~': 804, "'": 257, '"': 695,
        ';': 309, ':': 583, '<': 109, '>': 467, '[': 521, ']': 308, '{': 748, '}': 925, '/': 136, '\\': 807,
        '|': 529, '.': 746, '’': 706, '”': 741, ',': 387, ' ': 911, '\t': 922, '\n': 933
    };

    const decodeTable = Object.fromEntries(
        Object.entries(codeTable).map(([char, code]) => [code, char])
    );

    function encodeText() {
        const inputText = document.getElementById('encode').value;
        const password = document.getElementById('password').value;

        const encodedText = inputText
            .split('')
            .map((char, i) => {
                const passwordChar = password ? password[i % password.length] : '';
                const passwordShift = passwordChar ? passwordChar.charCodeAt(0) : 0; // Shift 0 if no password
                return codeTable[char]
                    ? (codeTable[char] + passwordShift).toString().padStart(4, '0') // Use 4 characters for accuracy
                    : char; // Apply shift
            })
            .join('');
        document.getElementById('decode').value = encodedText;
    }

    function decodeText() {
        const inputText = document.getElementById('decode').value;
        const password = document.getElementById('password').value;

        let decodedText = '';
        let correctDecode = true;

        for (let i = 0; i < inputText.length; i += 4) { // Step by 4 characters for decoding
            const passwordChar = password ? password[(i / 4) % password.length] : '';
            const passwordShift = passwordChar ? passwordChar.charCodeAt(0) : 0; // Shift 0 if no password
            const code = parseInt(inputText.slice(i, i + 4)) - passwordShift; // Subtract shift

            if (decodeTable[code]) {
                decodedText += decodeTable[code]; // Restore character
            } else {
                correctDecode = false;
                break; // Stop decoding if the code is invalid
            }
        }

        if (correctDecode) {
            document.getElementById('encode').value = decodedText;
        } else {
            alert("Invalid password or corrupted encoded text.");
        }
    }

</script>

</body>

</html>

I hope the provided example proves useful to you and helps simplify the resolution of certain issues related to data storage. Please note that the use of this script is at your own risk, so it is advisable to thoroughly test it before applying it in real-world scenarios.