Introduction

Welcome to the first lesson of our course, "Foundations of Encryption for TLS". In this lesson, we will explore the fascinating world of encryption, starting with the basics and gradually moving towards more advanced techniques. Encryption is a crucial aspect of securing data, ensuring that sensitive information remains confidential and protected from unauthorized access. By the end of this lesson, you will have a solid understanding of different encryption methods and how they are applied in real-world scenarios.

The Basics of Encryption

Let's begin with the fundamentals of encryption. Encryption is the process of converting plain text into a coded format, known as ciphertext, to prevent unauthorized access. One of the simplest and oldest encryption techniques is the Caesar cipher. The Caesar cipher involves shifting the letters of the alphabet by a fixed number of positions. For example, with a shift of 3, 'A' becomes 'D', 'B' becomes 'E', and so on.

To encrypt a message using the Caesar cipher, each letter in the plaintext is shifted by the specified number of positions. To decrypt, the process is reversed by shifting the letters back by the same number of positions. Here's a quick example in TypeScript:

const SHIFT: number = 3;

function encrypt(text: string): string {
  return text
    .split('')
    .map(char => {
      const code = char.charCodeAt(0);
      return String.fromCharCode(code + SHIFT);
    })
    .join('');
}

function decrypt(encryptedText: string): string {
  return encryptedText
    .split('')
    .map(char => {
      const code = char.charCodeAt(0);
      return String.fromCharCode(code - SHIFT);
    })
    .join('');
}

const message: string = 'Hello, World!';
const encrypted: string = encrypt(message);
console.log('Encrypted:', encrypted); // Output: Khoor/#Zruog$
const decrypted: string = decrypt(encrypted);
console.log('Decrypted:', decrypted); // Output: Hello, World!

This simple example demonstrates how a message can be encrypted and decrypted using a shift key. Depending on the implementation, it is generally preferred to use the modulo operator, similar to the Vigenère table, to handle wrap-around in the alphabet. However, since all characters in software are assigned sequential numeric values, it is possible to skip this modulo operation for our simplification purposes.

While the Caesar cipher is easy to understand, it is not secure for modern applications. The main weakness of the Caesar cipher lies in its predictability. Since there are only 25 possible shifts (excluding shift 0, which leaves the text unchanged), an attacker can easily brute-force decrypt the message by trying all possible shifts. Additionally, letter frequency analysis can quickly reveal patterns, as common letters in English (e.g., 'E' and 'T') will still appear frequently in the encrypted text. These weaknesses make the Caesar cipher unsuitable for securing sensitive information.

Introducing XOR Encryption

Next, we'll explore XOR encryption. Before diving into the details, let's understand the core concept of this encryption method. XOR encryption is based on a straightforward property: WORD ⊕ KEY ⊕ KEY = WORD. This implies that if two parties share a secret key KEY, they can use it to both encrypt and decrypt messages. It's a reversible operation where applying the same key twice returns you to the original message. This property facilitates secure communication between parties using the shared key.

As a refresher, XOR, also called exclusive or, is the boolean operator with the following truth table:

ABA ⊕ B
000
011
101
110

To perform the most basic XOR encryption, we use a key and the plaintext in bytes, and XOR them together. Let's illustrate this using the string "Hello" and the numeric key 3 (00000011).

We take the first character, which is 72 in ASCII. Bitwise XOR'ing 72 with 3 gives us 01001000 ⊕ 00000011 = 01001011 = 75. This is calculated by adding the values of the bits that are set to 1: 2^6 + 2^3 + 2^1 + 2^0 = 64 + 8 + 2 + 1 = 75.

75 in ASCII is K, giving us our first encrypted character. Performing the same action for the remaining characters gives us the following result:

CharacterASCII ValueXOR with Key (3)Resulting ASCIIResulting Character
'H'7272 ⊕ 3 = 7575'K'
'e'101101 ⊕ 3 = 102102'f'
'l'108108 ⊕ 3 = 111111'o'
'l'108108 ⊕ 3 = 111111'o'
'o'111111 ⊕ 3 = 108108'l'

The encrypted cipher is therefore Kfool.

Say we have two people, Alice and Bob, using this basic XOR encryption to talk to each other. You, as an eavesdropper listening to their conversation, pick up on the following messages:

  1. Kfool#Boj`f"
  2. Kfool#Ala"

Those with a keen eye might be able to pick out the original meaning:

  1. In both of the messages, we can see that Kfool is followed by a #, presumably corresponding to a space character. Additionally, both messages end with a ", which presumably is some kind of punctuation.
  2. We know that l -> o and e -> f, so the first message ends with an e, and the second message ends with a three-letter word containing o.

Following clues like these, we can rather clearly point out that the messages say:

  1. Hello Alice!
  2. Hello Bob!

However, we're not done yet. Those with an even keener eye might have noticed the symmetry in the two messages - for example, that the A from Alice has turned into a B, and vice versa. The ls in Hello have been turned into o, and vice versa. This is not by sheer accident, and is in fact a property of XOR itself. No matter which 2 columns you have, you can get the third simply by XORing. Consequently, it's more correct to say that l <-> o and e <-> f. Feel free to try it out by covering one of the columns in the truth table!

This characteristic is what makes XOR encryption useful in scenarios where both parties have a shared private key, as it allows for simple and efficient encryption and decryption.

However, seeing as we just cracked the code, plainly XORing the key and plaintext is insufficient for secure encryption. We would need to include some more advanced additional encryption methods on top of the XOR to make it safer. To summarize, XOR encryption is more secure than the Caesar cipher but still has its limitations. Here's how it works in TypeScript:

const SECRET_KEY: number = 0x55; // XOR key

function processXOR(text: string, encoding: BufferEncoding = 'utf8'): string {
  const buffer = Buffer.from(text, encoding);
  for (let i = 0; i < buffer.length; i++) {
    buffer[i] = buffer[i] ^ SECRET_KEY;
  }
  return buffer.toString(encoding);
}

const messageXOR: string = 'Hello, World!';
const encryptedXOR: string = processXOR(messageXOR, 'utf8');
console.log('Encrypted:', encryptedXOR); // Output: Encrypted text
const decryptedXOR: string = processXOR(encryptedXOR, 'utf8');
console.log('Decrypted:', decryptedXOR); // Output: Hello, World!
Transitioning to Modern AES Encryption
Conclusion

In this lesson, we have covered the basics of encryption, starting with simple techniques like the Caesar cipher and XOR encryption, and progressing to modern methods like AES. Understanding these concepts is essential for anyone interested in securing data and communications. As you move on to the practice section, you'll have the opportunity to implement these encryption techniques and solidify your understanding. Let's get started!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal