Skip to content

Instantly share code, notes, and snippets.

@QingpingMeng
Last active June 27, 2020 21:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save QingpingMeng/f3d83886f66efa75df577b6ed811c5ba to your computer and use it in GitHub Desktop.
Save QingpingMeng/f3d83886f66efa75df577b6ed811c5ba to your computer and use it in GitHub Desktop.
RSASHA256AESSHA256Encryption
function arrayBufferToBase64(buffer: ArrayBuffer): string {
  let binary = ''
  const bytes = new Uint8Array(buffer)
  const len = bytes.byteLength
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  return window.btoa(binary)
}

function base64UrlEncoded(input: ArrayBuffer): string {
  const base64Encoded = arrayBufferToBase64(input)
  return base64Encoded
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/\=+$/, '')
}

async function generateAESKey(): Promise<CryptoKey> {
  const aesKey = await window.crypto.subtle.generateKey(
    {
      name: 'AES-CBC',
      length: 256
    },
    true,
    ['encrypt', 'decrypt']
  )
  return aesKey
}

async function importPublicKey(jwk: JsonWebKey): Promise<CryptoKey> {
  var cryptoKey = await window.crypto.subtle
    .importKey(
      "jwk",
      jwk,
      {
        name: 'RSA-OAEP',
        hash: { name: 'sha-256' }
      },
      false,
      ["encrypt"]
    );
  return cryptoKey;
}

async function exportCryptoKey(key: CryptoKey): Promise<Uint8Array> {
  const keyBuffer = await window.crypto.subtle.exportKey('raw', key)
  return new Uint8Array(keyBuffer)
}

async function getEncryptedKeys(rsaPublicKey: CryptoKey, aesKey: CryptoKey): Promise<ArrayBuffer> {
  const exportedAESKey = await exportCryptoKey(aesKey)
  const keysBuffer = new Uint8Array(32)
  keysBuffer.set(exportedAESKey, 0)
  const encryptedKeys = await window.crypto.subtle.encrypt(
    {
      name: 'RSA-OAEP'
    },
    rsaPublicKey,
    keysBuffer
  )
  return encryptedKeys
}

const encryptMessage = async (data: string, jwk: JsonWebKey): Promise<string> => {
  const enc = new TextEncoder()
  const p = enc.encode(data)

  const aesKey = await generateAESKey()
  const rsaPublicKey = await importPublicKey(jwk)
  const iv = crypto.getRandomValues(new Uint8Array(16))
  const e = await window.crypto.subtle.encrypt(
    {
      name: 'AES-CBC',
      iv
    },
    aesKey,
    p
  )
  const encryptedKeys = await getEncryptedKeys(rsaPublicKey, aesKey)
  const finalResult =
    base64UrlEncoded(encryptedKeys) +
    base64UrlEncoded(iv) +
    base64UrlEncoded(e)
  return finalResult;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment