travist / jsencrypt

A zero-dependency Javascript library to perform OpenSSL RSA Encryption, Decryption, and Key Generation.
http://www.travistidwell.com/jsencrypt
Other
6.65k stars 2.01k forks source link

Encrypt in js and decrypt in C# ,example? #256

Open glober1234 opened 2 years ago

glober1234 commented 2 years ago

I am creating RSA key pair in C# , and setting public key in hidden input field and storing private key in server session. On post i will encrypt in js and decrypt in C# on server side. But its not working its returning false on encrypt function. Does it only support PEM format keys? Is there any example which satisfies my goal.

milaabl commented 1 year ago

Yes, it's because JSEncrypt has bad compatibility with other libraries/OpenSSL, it's really hard (but possible) to make those work together.

I'd suggest moving to using subtle crypto API (native to JS, vanilla JS) instead of this laggy library.

I decided to migrate to using subtle crypto after the recent bug with their NPM package (#282 #209 #278 )

You could do something like:

const getRSAEncrypted = async (text : string) => {
if (!process.env.REACT_APP_PUBLIC_RSA_KEY) {
  throw new Error('No public key provided in the .env');
}
  const key =
  await importPublicKey("Your public key in a string format, with all of the spaces replaced by \n".replace(
"\n",
`
`));
  const encrypted = await encryptRSA(key, yourTextToEncrypt);
  return window.btoa(ab2str(encrypted));
}

const fromBase64 = (base64String : string) => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));

const getPkciDer = (pkciPem : string) => {
  console.log(pkciPem);
  pkciPem = pkciPem.replace(/[\r\n]+/gm, "");
  const pkciPemHeader = "-----BEGIN PUBLIC KEY-----";
  const pkciPemFooter = "-----END PUBLIC KEY-----";
  console.log(pkciPem);
  pkciPem = pkciPem.substring(pkciPemHeader.length, pkciPem.length - pkciPemFooter.length);
  console.log(pkciPem.replace(/[\r\n]+/gm, "").replace(/[\r\n]+/gm, ""));
  return fromBase64(pkciPem.replace(/[\r\n]+/gm, "").replace(/[\r\n]+/gm, ""));
}

const importPublicKey = async (pkciPem : string) => {
    return await window.crypto.subtle.importKey(
        "spki",
        getPkciDer(pkciPem),
        {
            name: "RSA-OAEP",
            hash: "SHA-1",
        },
        true,
        ["encrypt"]
    );
}

const encryptRSA = async (key : CryptoKey, text : string) => {
    const enc = new TextEncoder();
    const encrypted = await window.crypto.subtle.encrypt(
        {
            name: "RSA-OAEP"
        },
        key,
        enc.encode(text)
    );
    return encrypted;
}
const ab2str = (buf : ArrayBuffer) => {
  //@ts-ignore
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

This is a great working example of how you can encrypt RSA on frontend and then decrypt on backend. The encryption here implements a standard and doesn't add anything like JSEncrypt.

On the backend, I decrypt it like: this

openssl rsautl -decrypt -oaep -inkey private_key.pem -in cipheredtextthatyougotfromthersafunction.txt -out noncipheredtextdecryptedfromrsa.txt