Definitions

Cryptography
From the Greek meaning 'hidden writing'
Cipher
A secret or disguised way of writing something
Code
A system of symbols or words used to represent other meanings. Sometimes used for the purposes of secrecy
Encryption
Turning something communicable information into gibberish. Comes from latin meaning 'hidden'
Decryption
Turning gibberish into meaning
Ciphers
Symmetric, Asymmetric, Quantum
Symmetric cipher
This is where the key is used on both sides of encryption/decryption
Quantum cipher
Weird physics stuff
Asymmetric cipher
'Public key' cryptography, where a message is encoded with a public key, but can only be decoded with another private key. Ideal for transferring over a distance
Keys
Any data used to encrypt something, the more complex the better
Passwords
Can be a memorable word or phrase or random string, used as a key
Entropy
Measuring the effectiveness of a key, measured in bits
Hashing
Reducing something into a unique value, usually one way reduction. An essential process of encryption
Digital signing/digital signature
If you sign a document you basically take the document, encrypt it with your **private key** which creates a hash. Document + signature hash = signed document. To prove the signature, take original document hash, take the signed document, decrypt with persons public key, if the document hash match, then it has been signed. See nonrepudiation.
Cryptoanalysis
The process of trying to discover a codes algorithm or vulnerabilities and using that to break the code
Nonce
A word, number, expression created and used only once
Nonrepudiation
From latin meaning 'cast off' or 'divorce’. Meaning that once you sign/authorise something, you cannot at a later date say you didn't do it
AES encryption
Advanced Encryption Standard
IV
Initialisation Vector - a random number used with a secret key for data encryption. Also called a nonce - one time use

We have a message that we want to make secret. We will pass it through an encryption algorithm called a cypher. That produces cypher text. The cypher algorithm usually takes a key as a parameter. The decryption will take the cypher text and convert it back to the original message.

An analogy for encryption/decryption is the lock and key. Whatever the lock protects is the secret. We may know the inner workings of the lock generally, but we must have the right key so we can get in and prevent others from getting in. The lock can be opened or closed using the key - this is enciphering (encoding) and deciphering (decoding). The lock would be the cypher, and the key is, well, the key. The secret would be the opened door, the closed door would be the cyphertext.

Codes

A code is like a puzzle, it just takes time to solve it. No system is 100% foolproof. Time is a factor in many ways. How clever/complicated a code is to crack means it will take years for a normal computer hack. Also, for a code to be useful in encoding/decoding it needs to be a useful speed. For example, logging into a website does not have to be instantaneous (this makes things tougher for a brute force attack) but also needs to be fast enough for the user to not be perturbed.

Symmetric Cipher

Symmetric as in 'exactly similar parts facing each other'. So basically the cipher for input is the opposite of the cypher for output. A simple example could be a 'substitution cipher', where characters are substituted:

a b c d e f g h i j k l m n o p q r s t u v w x y z

The key:

w g m u p b l y a r i q v k f n d t c o x e z j s h
const key = { a: 'w', b: 'g', c: 'm', d: 'u', e: 'p', f: 'b', g: 'l', h: 'y', i: 'a', j: 'r', k: 'i', l: 'q', m: 'v', n: 'k', o: 'f', p: 'n', q: 'd', r: 't', s: 'c', t: 'o', u: 'x', v: 'e', w: 'z', x: 'j', y: 's', z: 'h', };

const decodeKey = (() => Object.keys(key).reduce((curr, next) => {
    curr[key[next]] = next;
    return curr;
  }, {}))();

function encipher(plaintext) {
  return plaintext.split('').map(char => key[char] || '*').join('');
}

function decipher(plaintext) {
  return plaintext.split('').map(char => decodeKey[char] || ' ').join('');
}

So using the key to cipher the 'plaintext' string 'i am a little teapot' would return a*wv*w*qaooqp*opwnfo. As you can see, they key is the thing used to encode/decode a message. You can see the problem with this method though - both parties need to have the same key.

Asymmetric Cipher

The asymmetric cypher has two keys - private and public. The private key is used to encode, the public key is used to decode. This makes transfer from one party to another possible. Alice wants to send a message to Bob without anyone seeing. Alice has a private and public key, as does Bob. Alice uses Bob's public key and encrypts a message using it. Alice cannot decrypt that message even though she is the one who encrypted it. Bob gets a cipher, he uses his private key to decrypt it. He reads the message. Taking our simple substitution cypher we can create an asymmetric cypher:

const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];

// as a user, generate a public/private key pair
function generate () {
  
  const privateKey = {};
  const publicKey = {};

  const privateSource = letters.slice();
  const publicSource = letters.slice();

  let index = 0;

  while (privateSource.length > 0) {
    const privateIndex = Math.floor(Math.random() * privateSource.length);
    const privateLetter = privateSource.splice(privateIndex, 1);

    const publicIndex = Math.floor(Math.random() * publicSource.length);
    const publicLetter = publicSource.splice(publicIndex, 1);

    publicKey[letters[index]] = publicLetter[0];
    privateKey[publicLetter[0]] = letters[index];
    index++;
  }

  return {
    privateKey,
    publicKey,
  };
}

function encode (message, key) {
  let result = '';
  for (let i = 0; i < message.length; i++) {
    result += key[message[i]] || '*';
  }
  return result;
}

function decode(message, key) {
  return encode(message, key).replace(/\*/g, ' ');
}

So we can create two users:

const alice = generate();
const bob = generate();

And a discussion would go like this:

// alice encodes a message with bobs public key
const aliceToBobMessage = 'hello bob i like cheese';
const aliceCodeFromBobPublicKey = encode(aliceToBobMessage, bob.publicKey);
console.log(aliceCodeFromBobPublicKey); // kjzzq*yqy*a*zaej*lkjjbj

const bobDecodeFromAliceWithPrivateKey = decode(aliceCodeFromBobPublicKey, bob.privateKey);
console.log(bobDecodeFromAliceWithPrivateKey); // hello bob i like cheese

// alice cannot decode using her private key
console.log(decode(aliceCodeFromBobPublicKey, alice.privateKey)); //cbkkg mgm q kqrb zcbbob

So we can see that bob is the only one who can decrypt the message encrypted with his public key.

EOR - Exclusive OR

You may have noticed from the above that we have a message that gets encrypted, then decrypted. Essentially what we have is a number of bits that get 'flipped' from one state to another. This is where the EOR operator comes in.

Truth table:

A B Output
0 0 0
1 0 1
0 1 1
1 1 0

Other examples

Libraries

References