Skip to content

Commit d69172b

Browse files
committed
feat: add RSA encryption and decryption algorithm
1 parent 1d252d7 commit d69172b

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

Ciphers/RSAAlgorithm.js

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RSAAlgorithm.js
2+
3+
/**
4+
* Generates the greatest common divisor of two numbers.
5+
* @param {number} a - First number.
6+
* @param {number} b - Second number.
7+
* @returns {number} - The GCD of a and b.
8+
*/
9+
export function gcd(a, b) {
10+
if (b === 0) {
11+
return a
12+
}
13+
return gcd(b, a % b)
14+
}
15+
16+
/**
17+
* Calculates modular inverse using Extended Euclidean Algorithm.
18+
* @param {number} e - The number to find inverse for.
19+
* @param {number} phi - The modulus.
20+
* @returns {number} - The modular inverse of e mod phi.
21+
*/
22+
export function modInverse(e, phi) {
23+
let [m0, x0, x1] = [phi, 0, 1]
24+
25+
if (phi === 1) {
26+
return 0
27+
}
28+
29+
while (e > 1) {
30+
let q = Math.floor(e / phi)
31+
;[e, phi] = [phi, e % phi]
32+
;[x0, x1] = [x1 - q * x0, x0]
33+
}
34+
35+
if (x1 < 0) {
36+
x1 += m0
37+
}
38+
39+
return x1
40+
}
41+
42+
/**
43+
* Performs modular exponentiation.
44+
* @param {number} base - Base number.
45+
* @param {number} exponent - Exponent.
46+
* @param {number} modulus - Modulus.
47+
* @returns {number} - (base^exponent) % modulus.
48+
*/
49+
export function modPow(base, exponent, modulus) {
50+
if (modulus === 1) return 0
51+
let result = 1
52+
base = base % modulus
53+
54+
while (exponent > 0) {
55+
if (exponent % 2 === 1) {
56+
result = (result * base) % modulus
57+
}
58+
exponent = Math.floor(exponent / 2)
59+
base = (base * base) % modulus
60+
}
61+
62+
return result
63+
}
64+
65+
/**
66+
* Generates RSA keys.
67+
* @param {number} p - A prime number.
68+
* @param {number} q - A prime number.
69+
* @returns {{publicKey: {e: number, n: number}, privateKey: {d: number, n: number}}}
70+
*/
71+
export function generateKeys(p, q) {
72+
const n = p * q
73+
const phi = (p - 1) * (q - 1)
74+
75+
let e = 2
76+
while (e < phi && gcd(e, phi) !== 1) {
77+
e++
78+
}
79+
80+
const d = modInverse(e, phi)
81+
82+
return {
83+
publicKey: { e, n },
84+
privateKey: { d, n }
85+
}
86+
}
87+
88+
/**
89+
* Encrypts a message with a public key.
90+
* @param {number} message - The message to encrypt (as a number).
91+
* @param {{e: number, n: number}} publicKey - The public key.
92+
* @returns {number} - The encrypted message.
93+
*/
94+
export function encrypt(message, publicKey) {
95+
return modPow(message, publicKey.e, publicKey.n)
96+
}
97+
98+
/**
99+
* Decrypts a cipher with a private key.
100+
* @param {number} cipher - The encrypted message (cipher).
101+
* @param {{d: number, n: number}} privateKey - The private key.
102+
* @returns {number} - The decrypted message.
103+
*/
104+
export function decrypt(cipher, privateKey) {
105+
return modPow(cipher, privateKey.d, privateKey.n)
106+
}

Ciphers/test/RSAAlgorithm.test.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RSAAlgorithm.test.js
2+
import { describe, it, expect } from 'vitest'
3+
import { generateKeys, encrypt, decrypt } from '../RSAAlgorithm.js'
4+
5+
describe('RSA Algorithm', () => {
6+
it('should encrypt and decrypt correctly', () => {
7+
const { publicKey, privateKey } = generateKeys(61, 53) // two primes
8+
const message = 65
9+
const cipher = encrypt(message, publicKey)
10+
const decrypted = decrypt(cipher, privateKey)
11+
12+
expect(decrypted).toBe(message)
13+
})
14+
})

0 commit comments

Comments
 (0)