-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRSA.ts
More file actions
155 lines (138 loc) · 5.11 KB
/
RSA.ts
File metadata and controls
155 lines (138 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import chalk from "@/shared/chalk";
import euclidean from "@/algorithms/euclidean";
import extendedEuclidean from "@/algorithms/extended-euclidean";
import fastModularExponentiation from "@/algorithms/fast-modular-exponentiation";
import pollardP1Factorization from "@/algorithms/pollard-p-1-factorization";
import { EActors } from "@/shared/constants";
import { log, inquire, wrap } from "@/shared/utilities";
export async function prompt() {
try {
console.log("There are three people in this RSA encryption process:");
console.log(
`\t${EActors.Alice} - Receiver\n\t${EActors.Bob} - Sender\n\t${EActors.Eve} - Eavesdropper`,
);
const [p, q, n, r] = await inquire.continue(
`${EActors.Alice} is going to pick prime numbers P and Q, and then generate n with P * Q, r with (P - 1) * (Q - 1):`,
() => {
const [p, q] = wrap.randomize(16, 8, 2);
const n = p * q;
const r = (p - BigInt(1)) * (q - BigInt(1));
log.list([
{ name: "P", value: p },
{ name: "Q", value: q },
{ name: "n", value: n },
{ name: "r ((P - 1) * (Q - 1))", value: r },
]);
return [p, q, n, r];
},
);
const [e, d] = await inquire.continue(
`${EActors.Alice} selects the public exponent e and computes private exponent d from e * d % r = 1:`,
() => {
const commonExponents = [65537n, 257n, 17n, 5n, 3n];
const e = commonExponents.find((value) => euclidean(value, r) === 1n);
if (!e) {
throw new Error("Unable to select a valid public exponent e.");
}
const [gcd, coefficient] = extendedEuclidean(e, r);
if (gcd !== 1n) {
throw new Error("Unable to compute private key exponent d.");
}
const d = ((coefficient % r) + r) % r;
log.list([
{ name: "e", value: e },
{ name: "d", value: d },
]);
return [e, d];
},
);
await inquire.continue(
`${EActors.Alice} sends e and n as the public key to ${EActors.Bob} and ${EActors.Eve}.`,
() => {
console.log(`\t${EActors.Alice} has the following numbers:`);
log.list([
{ name: "P", value: p },
{ name: "Q", value: q },
{ name: "n", value: n },
{ name: "r", value: r },
{ name: "e", value: e },
{ name: "d", value: d },
]);
},
);
const message = "This is a hardcoded secret message.";
const arrayOfEncryptedCode = await inquire.continue(
`${EActors.Bob} encrypts the message and sends it back to ${EActors.Alice} (while ${EActors.Eve} is eavesdropping).`,
() => {
const arrayOfEncryptedCode = wrap.encrypt(message, (code) => {
return fastModularExponentiation(BigInt(code), e, n);
});
console.log(`\tEncrypted message: ${chalk.gray(arrayOfEncryptedCode)}`);
const messageDecrypted = wrap.decrypt(
arrayOfEncryptedCode,
(codeEncrypted) => {
return fastModularExponentiation(codeEncrypted, d, n);
},
);
console.log(
`\n\t${
EActors.Alice
} can decrypt the message since she has the private key ${chalk.bold.bgCyan(
"(d, n)",
)}.\n\tDecrypted message: ${chalk.gray(messageDecrypted)}\n\t${
EActors.Alice
} verifies the message with ${EActors.Bob} privately.`,
);
return arrayOfEncryptedCode;
},
);
await inquire.continue(
`${EActors.Eve} is going to decrypt the secret message.`,
() => {
console.log(`\tNow ${EActors.Eve} has the following stuff:`);
log.list([
{ name: "n", value: n },
{ name: "e", value: e },
{ name: "secret message", value: arrayOfEncryptedCode },
]);
console.log(
`\n\t${
EActors.Eve
} is going to factor n and derive private key d from the public key ${chalk.bold.bgCyan(
"(e, n)",
)} and other information.`,
);
const factors = pollardP1Factorization(n);
if (factors.length < 2) {
throw new Error("Eve failed to factor n.");
}
const primeP = BigInt(factors[0]);
const primeQ = n / primeP;
const phi = (primeP - 1n) * (primeQ - 1n);
const [gcd, coefficient] = extendedEuclidean(e, phi);
if (gcd !== 1n) {
throw new Error("Eve failed to derive d from factors.");
}
const dEavesdropped = ((coefficient % phi) + phi) % phi;
console.log(
`\tPrivate key ${chalk.bold.bgCyan("(d, n)")}: ${chalk.gray(
`(${dEavesdropped}, ${n})`,
)}`,
);
const messageEavesdropped = wrap.decrypt(
arrayOfEncryptedCode,
(codeEncrypted) => {
return fastModularExponentiation(codeEncrypted, dEavesdropped, n);
},
);
console.log(
`\tDecrypted message: ${chalk.gray(messageEavesdropped)}\n\t${
EActors.Eve
} verifies the message with ${EActors.Bob}.`,
);
},
);
} catch (error) {
throw error;
}
}