To securely transmit sensitive data over the internet, such as passwords for login, it's crucial to encrypt or hash the data. HTTPS alone may not be enough. The process involves generating a key pair on the server backend, consisting of a public key and a private key. The server keeps the private key secure and sends the public key to the client as a cookie. On the client side, the public key is used to encrypt data, such as passwords, before sending it to the server. When the server receives the encrypted data, it decrypts it using the private key to obtain the original plain text. If the backend can access the hashed password of the user, there's no need to decrypt it, just compare the hash. However, if external API calls are needed to check the validity of the username and password, encryption on the client side and decryption on the server side after secure transmission over the internet is necessary. Util functions in typescriptimport { KeyPairSyncResult, generateKeyPairSync, privateDecrypt, constants, publicEncrypt } from 'crypto'; import { Request, Response } from 'express'; import { RSA_OAEP_KEY_COOKIE } from './types'; let RSA_OAEP_KEY_PAIR: KeyPairSyncResult<string, string>; export function generateKeyPair() { if (!RSA_OAEP_KEY_PAIR) { RSA_OAEP_KEY_PAIR = generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); } } export function setPublicKeyCookie(req: Request, res: Response) { res.cookie(RSA_OAEP_KEY_COOKIE, RSA_OAEP_KEY_PAIR.publicKey, { secure: req.secure }); } export function getPublicKey() { return RSA_OAEP_KEY_PAIR.publicKey; } export function getPrivateKey() { return RSA_OAEP_KEY_PAIR.privateKey; } export function decrypt(encryptedText: string): string { const buffer = Buffer.from(encryptedText, 'base64'); const decrypted = privateDecrypt({ key: RSA_OAEP_KEY_PAIR.privateKey, padding: constants.RSA_PKCS1_OAEP_PADDING, passphrase: '' // Only needed if the private key is encrypted }, buffer); return decrypted.toString(); } export function encrypt(plainText: string): string { const buffer = Buffer.from(plainText); const decrypted = publicEncrypt({ key: RSA_OAEP_KEY_PAIR.privateKey, padding: constants.RSA_PKCS1_OAEP_PADDING, passphrase: '' // Only needed if the private key is encrypted }, buffer); return decrypted.toString('base64'); }
Unit Testsimport { generateKeyPair, encrypt, decrypt } from "."; describe("rsaoaep", () => { it("should generate RSA-OAEP key pair", () => { // Test that the RSA-OAEP key pair is generated generateKeyPair(); const plain_text = "lengerrong"; const encrypted_text = encrypt(plain_text); console.log("encrypted_text", encrypted_text); const decrypted_text = decrypt(encrypted_text); console.log("decrypted_text", decrypted_text); expect(decrypted_text).toEqual(plain_text); }); });
you should see the test pass. console.log encrypted_text I+b8qYByZXHcOENeMoX3mUXS51TSixUMNsC2aujQOaeVwzInftY1yYhqIwlyxgRQlWKZRYBvTrZzwj1ur2/qb1w3q9VBnmurRWCPy3uFTvX73CxdO2Wvqx0V73YyJW6UMLbVVlNBkqgVmwSY25+TzNNPv5Fgd4TY+paLrkNrVEBkMa4upzJI6aIMiU9AfWkWwQu04yBn4JoXj/6k7tCYPeJxDnzI5M4vQdxBxiyyCV1SEo0xTL/Pb2tfzS7MKv6C9fd2if+TH3TxcKcZgmB8+Z0NZY0pawUcR2KFOnionUQedfjpsTIrPpRmyZ9Iistoxo/OTvG1oqdwMuAb80Y0eg== at Object.<anonymous> (middleware/rsaoaep/index.test.ts:9:17) console.log decrypted_text lengerrong at Object.<anonymous> (middleware/rsaoaep/index.test.ts:11:17) (node:73433) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. (Use `node --trace-deprecation ...` to show where the warning was created) PASS activate apps/activate/middleware/rsaoaep/index.test.ts rsaoaep ✓ should generate RSA-OAEP key pair (306 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 12.288 s |