Unraveling the mystery behind RSA encryption

For a better and more immersive experience, read this blog on my official blog - https://blog.atchyut.dev/blogpost/8b3ff3e755fd4624b7b9c7fff75a13b4

Hey there 👋🏼! Hope you're doing great. I'm super stoked today because we’ll be diving into RSA encryption and how you can implement it on your own front-end apps using the WebCrypto API. As you may know by now, I’m a full stack software engineer (with about 7 years of experience at the time of writing this). I’ve recently had the chance to work on and learn about RSA Encryption for a cool feature I was working on and I must say, I had a lot of fun working with it, so much so that I decided to create a demonstration of RSA that is hosted here (more on that soon). If you ever wanted to perform some kind of an asymmetric encryption on your front-end app this guide will help you accomplish that via the Subtle Crypto interface that the Web Crypto API provides, so, without wasting any time, let’s get into it.

What's the Buzz about RSA Encryption?

Alright, let's keep it real simple. RSA encryption is like the superhero of encryption. And it all boils down to using two keys – one for locking up your secrets (public key) and the other for letting them out (private key). It's like a high-tech lock and key, but for your secrets.

Where RSA Gets Its Groove On

RSA, is named after its inventors Ron Rivest, Adi Shamir, and Leonard Adleman, and is more than just a tech jargon; it’s everywhere you go online. Buying stuff? RSA's got your back. Sending secure messages? RSA's in action. It's like the silent guardian making sure your digital life stays, well, private and secure.

So, what’s different?

Unlike traditional symmetric-key algorithms, where a single key is used for both encryption and decryption, RSA employs a pair of keys: a public key and a private key. The public key is shared openly (it is not a secret), allowing anyone to encrypt messages, but only the possessor of the corresponding private key can decrypt them.

So, if you know the public key of a friend, you can use it to encrypt the message you want to send them. The encrypted message, even if intercepted, remains unreadable without the your friend’s private key. This asymmetric nature of RSA makes it particularly suited for secure communication over untrusted networks. The strength of RSA lies in the difficulty of factoring the product of two large prime numbers, forming the basis of the keys. If you’re interested in the math behind RSA, you can read more about it in this document by San Jose State University, California.

Understanding RSA encryption is fundamental for grasping the principles behind secure online communication, ensuring the confidentiality and integrity of sensitive information exchanged in the digital landscape.

Let's Play with RSA: The Demo

Now, here’s the fun part – the RSA Encryption Demo. It's not a boring lecture; it's a playground for you to mess around with RSA encryption. And guess what? No PhD in Cryptography required. It's made simple and friendly for curious minds like yours and if you’re code curious too, you can check it out in my GitHub repository.

Geek talk, the Web Crypto API

The demo uses something called the Web Crypto API. It's like the magic wand that makes cryptographic tricks happen right in your web browser. No need to install any external dependencies, you can just use it in your front-end code by referencing the window.crypto object. Also did I mention, it’s pretty fast? Here’s a StackOverflow threadbenchmarking the performance against Stanford JS Crypto Library and Forge.

The code

This wouldn’t be one of my blogs if it didn’t contain at least one code snippet, so here we are at the precipice of today’s code. tyAs we’ve already discussed, we’ll be using the WebCrypto API for this, so spin up your dev servers and follow along.

Generating a keypair

You can generate your public/private keypair in a multitude of ways, but for this one let’s do it using the generateKeyfunction from the Subtle Crypto interface.

const generateKeyPair = async () => {
        // 1. generate the crypto key pair via generateKey
    const keyPair: CryptoKeyPair = 
            await window.crypto.subtle.generateKey(
      {
                // length of the key in bits
        modulusLength: 4096,
                // algorithm
        name: "RSA-OAEP", 
                // exponent for generating the key
        publicExponent: new Uint8Array([1, 0, 1]), 
                // hashing algorithm
        hash: "SHA-256", 
      },
            //can key be extracted using exportKey or wrapKey functions
      true,
            // keys for encvryption and decryption
      ["encrypt", "decrypt"]
    );

    const [spkiBuffer, pkcs8Buffer] = await Promise.all([
      window.crypto.subtle.exportKey("spki", keyPair.publicKey),
      window.crypto.subtle.exportKey("pkcs8", keyPair.privateKey),
    ]);

    const publicKey = 
            btoa(String.fromCharCode(...new Uint8Array(spkiBuffer)));
    const privateKey = btoa(
      String.fromCharCode(...new Uint8Array(pkcs8Buffer))
    );

        /* Your logic to use the keys for encryption or decryption... */
 };

Encryption

const handleEncrypt = async () => {
    try {
            // Your public key from above
            const publicKey = your_crypto_key_object; 
      const encryptedData = await window.crypto.subtle.encrypt(
                // algorithm
        {
          name: "RSA-OAEP",
        },
        publicKey,
                // buffer from text you want to encrypt
        Buffer.from(plainText as string, "utf-8")
      );

            /* Your logic to use the encrypted data 
            i.e. sending it somewhere or simply storing it... */

    } catch (e) {
      console.error("An error has occurred while encrypting, ", e);
    }
  };

Decryption

const handleDecrypt = async () => {
    try {
            // Your private key from above
      const privateKey = your_private_key; 

        const decryptedData = await window.crypto.subtle
        .decrypt(
          "RSA-OAEP", // algorithm
          privateKey,
                    // message to decrypt
          Uint8Array.from(atob(encryptedMessage as string), 
                    c => c.charCodeAt(0))
            .buffer
        );

                /* Your logic to use the decrypted data... */

    } catch (e) {
      console.error("An error has occurred while decrypting, ", e);
    }
  };

That’s all folks

So there, that's the scoop! Check out the RSA Encryption Demo, play around, and if you're feeling adventurous, dive into the GitHub repo, it's your backstage pass.

Happy coding and dare I say, encrypting 🔒.