RSA encryption libraries exist on both the front and back ends, but are usually not universal. That is, the RSA library of the browser cannot be used in Node, and the RSA library of Node cannot be used in the browser. For RSA encryption communication between the front and back ends, the configuration of the libraries on both ends must match.

This article gives examples of jSENCRYPT library at the front end and native Crypto library at the back end to discuss the methods of RSA encryption communication at the back end.

methods

The back-end generates public and key

Let’s first set up a server:

import Express from 'express'
import Path from 'path'
import BodyParser from 'body-parser'

const cwd = globalThis.process.cwd()
const express = new Express()
const router = new Express.Router()

router.get('/'.async (req, res) => {
  res.sendFile(Path.resolve(cwd, './index.html'))
})
router.get('/jsencrypt.js'.(req, res) = > {
  res.sendFile(Path.resolve(cwd, './lib/jsencrypt.js'))
})

express.use(BodyParser.text())
express.use(router)

express.listen(8000)
Copy the code

The server provides index.html and jsencrypt.js files.

Next, use the crypto library to create the public key and key:

import Crypto from 'crypto'

const { publicKey, privateKey } = Crypto.generateKeyPairSync('rsa', {
  modulusLength: 1024.publicKeyEncoding: {
    type: 'spki'.format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs1'.format: 'pem'.cipher: 'aes-256-cbc'.passphrase: ' '}})Copy the code

Crypto. GenerateKeyPairSync document: nodejs. Cn/API/Crypto….

Because of the requirements of the JsENCRYPT library, the public and key configurations must be this way. Mainly 1024 public key length (modulusLength) and SPKI encoding mode.

Then configure a route to get the public key:

router.get('/key'.(req, res) = > {
  res.send(publicKey)
})
Copy the code

The front end gets the public key and encrypts the plaintext

On the browser side, we’ll start with jsencrypt:

<script src="/jsencrypt.js"></script>
Copy the code

Next get the public key:

let publicKey = await (await fetch('/key')).text()
Copy the code

Encrypt using jsencrypt:

const value = 'Hack the world'

let jsEncrypt = new JSEncrypt()
jsEncrypt.setPublicKey(publicKey)
let result = jsEncrypt.encrypt(value)
Copy the code

Send the encrypted text to the back end to see if the back end can decrypt it:

let res = await (
  await fetch('/encrypt', {
    method: 'POST'.body: result
  })
).text()
Copy the code

The back-end decryption

After receiving the ciphertext, the back end uses the key to decrypt it:

router.post('/encrypt'.(req, res) = > {
  let value = Crypto.privateDecrypt(
    {
      key: privateKey,
      passphrase: ' '.padding: Crypto.constants.RSA_PKCS1_PADDING
    },
    Buffer.from(req.body, 'base64')
  )

  res.send(value)
})
Copy the code

Note the configuration here:

  • padding: Crypto.constants.RSA_PKCS1_PADDING
  • Buffer.from(req.body, 'base64')

Again, it cannot be configured to other values for use with jsENCRYPT.

If the back end returns Hack the world, then the whole decryption process succeeded.

code

Sample code:

The back-end

import Express from 'express'
import Path from 'path'
import BodyParser from 'body-parser'
import Crypto from 'crypto'

const cwd = globalThis.process.cwd()
const express = new Express()
const router = new Express.Router()

const { publicKey, privateKey } = Crypto.generateKeyPairSync('rsa', {
  modulusLength: 1024.publicKeyEncoding: {
    type: 'spki'.format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs1'.format: 'pem'.cipher: 'aes-256-cbc'.passphrase: ' '}})console.log('> Private key')
console.log(privateKey)

router.get('/'.async (req, res) => {
  res.sendFile(Path.resolve(cwd, './index.html'))
})
router.get('/jsencrypt.js'.(req, res) = > {
  res.sendFile(Path.resolve(cwd, './lib/jsencrypt.js'))
})
router.get('/key'.(req, res) = > {
  res.send(publicKey)
})
router.post('/encrypt'.(req, res) = > {
  let value = Crypto.privateDecrypt(
    {
      key: privateKey,
      passphrase: ' '.padding: Crypto.constants.RSA_PKCS1_PADDING
    },
    Buffer.from(req.body, 'base64')
  )

  res.send(value)
})

express.use(BodyParser.text())
express.use(router)

express.listen(8000)

Copy the code

The front end

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>

    <script src="/jsencrypt.js"></script>
    <script type="module">
      const value = 'Hack the world'

      console.log('> Text')
      console.log(value)

      let publicKey = await (await fetch('/key')).text()

      console.log('> Public key')
      console.log(publicKey)

      let jsEncrypt = new JSEncrypt()
      jsEncrypt.setPublicKey(publicKey)
      let result = jsEncrypt.encrypt(value)
      console.log('> Encrypted text')
      console.log(result)

      let res = await (
        await fetch('/encrypt', {
          method: 'POST'.body: result
        })
      ).text()

      console.log('> Decrypted text')
      console.log(res)
    </script>
  </head>
  <body> </body>
</html>

Copy the code