Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add RSA encryption and decryption algorithm
  • Loading branch information
QuantumSoham committed Apr 28, 2025
commit d69172b5bf4de89ab168ff75153bee5d67546e9f
106 changes: 106 additions & 0 deletions Ciphers/RSAAlgorithm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// RSAAlgorithm.js

/**
* Generates the greatest common divisor of two numbers.
* @param {number} a - First number.
* @param {number} b - Second number.
* @returns {number} - The GCD of a and b.
*/
export function gcd(a, b) {
if (b === 0) {
return a
}
return gcd(b, a % b)
}

/**
* Calculates modular inverse using Extended Euclidean Algorithm.
* @param {number} e - The number to find inverse for.
* @param {number} phi - The modulus.
* @returns {number} - The modular inverse of e mod phi.
*/
export function modInverse(e, phi) {
let [m0, x0, x1] = [phi, 0, 1]

if (phi === 1) {
return 0
}

while (e > 1) {
let q = Math.floor(e / phi)
;[e, phi] = [phi, e % phi]
;[x0, x1] = [x1 - q * x0, x0]
}

if (x1 < 0) {
x1 += m0
}

return x1
}

/**
* Performs modular exponentiation.
* @param {number} base - Base number.
* @param {number} exponent - Exponent.
* @param {number} modulus - Modulus.
* @returns {number} - (base^exponent) % modulus.
*/
export function modPow(base, exponent, modulus) {
if (modulus === 1) return 0
let result = 1
base = base % modulus

while (exponent > 0) {
if (exponent % 2 === 1) {
result = (result * base) % modulus
}
exponent = Math.floor(exponent / 2)
base = (base * base) % modulus
}

return result
}

/**
* Generates RSA keys.
* @param {number} p - A prime number.
* @param {number} q - A prime number.
* @returns {{publicKey: {e: number, n: number}, privateKey: {d: number, n: number}}}
*/
export function generateKeys(p, q) {
const n = p * q
const phi = (p - 1) * (q - 1)

let e = 2
while (e < phi && gcd(e, phi) !== 1) {
e++
}

const d = modInverse(e, phi)

return {
publicKey: { e, n },
privateKey: { d, n }
}
}

/**
* Encrypts a message with a public key.
* @param {number} message - The message to encrypt (as a number).
* @param {{e: number, n: number}} publicKey - The public key.
* @returns {number} - The encrypted message.
*/
export function encrypt(message, publicKey) {
return modPow(message, publicKey.e, publicKey.n)
}

/**
* Decrypts a cipher with a private key.
* @param {number} cipher - The encrypted message (cipher).
* @param {{d: number, n: number}} privateKey - The private key.
* @returns {number} - The decrypted message.
*/
export function decrypt(cipher, privateKey) {
return modPow(cipher, privateKey.d, privateKey.n)
}
14 changes: 14 additions & 0 deletions Ciphers/test/RSAAlgorithm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RSAAlgorithm.test.js
import { describe, it, expect } from 'vitest'
import { generateKeys, encrypt, decrypt } from '../RSAAlgorithm.js'

describe('RSA Algorithm', () => {
it('should encrypt and decrypt correctly', () => {
const { publicKey, privateKey } = generateKeys(61, 53) // two primes
const message = 65
const cipher = encrypt(message, publicKey)
const decrypted = decrypt(cipher, privateKey)

expect(decrypted).toBe(message)
})
})
Loading
Oops, something went wrong.