Skip to content

Commit b9c5d92

Browse files
author
BrandynTucknott
committed
CS 499 HW 2
1 parent aff6fa2 commit b9c5d92

10 files changed

Lines changed: 820 additions & 245 deletions

File tree

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,100 @@
11
function addEventListeners() {
2-
document.getElementById("gen-choice-btn").addEventListener("click", () => {
3-
const p = parseInt(document.getElementById("prime1").value);
4-
const q = parseInt(document.getElementById("prime2").value);
52

6-
if (isNaN(p) || isNaN(q)) {
7-
console.error("p, q must be prime integers. ");
8-
return;
3+
// listen for button press to generate possible public key choices
4+
document.getElementById("gen-choice-btn").addEventListener("click", () => {
5+
const err_box = document.getElementById('gen-public-key-err-box');
6+
if (p == null || q == null) {
7+
err_box.textContent = 'Both p and q must be chosen before private keys can be generated.';
8+
return;
99
}
10-
10+
err_box.textContent = '';
11+
12+
// get and print a list of possible values for public key based on p,q
1113
const possiblePublicKeys = getPossiblePublicKeys(p, q);
12-
document.getElementById("possible-public-keys").textContent = `${arrayToStr(possiblePublicKeys)}`;
14+
if (possiblePublicKeys == null) {
15+
console.warn(`WARNING: In listener for Generate Public Key Choices: returned keys are null.`)
16+
document.getElementById("possible-public-keys").textContent = '';
17+
return;
18+
}
19+
20+
const array_str = arrayToStr(possiblePublicKeys);
21+
if (array_str == null) {
22+
console.warn(`WARNING: In listener for Generate Public Key Choices: returned array string is null.`)
23+
document.getElementById("possible-public-keys").textContent = '';
24+
return;
25+
}
26+
27+
document.getElementById("possible-public-keys").textContent = `${array_str}`;
1328
});
29+
30+
// listen for changes in public key
31+
document.getElementById('public-key').addEventListener('change', () => {
32+
const err_box = document.getElementById('public-key-err-box');
33+
34+
// if insufficient info, let user know
35+
if (p == null || q == null) {
36+
public_key = null; // invalid p,q --> invalid public key
37+
private_key = null;
38+
err_box.textContent = 'Both p and q must be valid primes.';
39+
return;
40+
}
41+
42+
// input is an integer?
43+
temp_key = document.getElementById('public-key').value
44+
if (temp_key == '') {
45+
public_key = null;
46+
private_key = null;
47+
err_box.textContent = 'Public key cannot be empty.';
48+
private_key_box.textContent = '';
49+
return;
50+
}
51+
try {
52+
temp_key = parseInt(temp_key);
53+
} catch (e) {
54+
err_box.textContent = 'Invalid public key. Remember it must be an integer.'
55+
public_key = null;
56+
private_key = null;
57+
return;
58+
}
59+
60+
// input works as a valid key?
61+
inv = verifyKey(temp_key);
62+
if (inv == null) { // prob a bug somewhere in my code
63+
public_key = null;
64+
private_key = null;
65+
private_key_box.textContent = '';
66+
err_box.textContent = 'There is a bug on my end, maybe try a different public key?';
67+
return;
68+
}
69+
else if (inv == -1) {
70+
public_key = null;
71+
private_key = null;
72+
private_key_box.textContent = '';
73+
err_box.textContent = `public key ${temp_key} is not multiplicatively invertible mod ${(p - 1) * (q - 1)}.`;
74+
return;
75+
}
76+
else if (inv == -2) {
77+
public_key = temp_key
78+
private_key = public_key;
79+
private_key_box.textContent = `${private_key}`;
80+
err_box.textContent = `public key ${temp_key} is its own multiplicative inverse mod ${(p - 1) * (q - 1)}, and probably a bad choice.`;
81+
return;
82+
}
83+
84+
// inv is actually the inverse of public key
85+
// update info
86+
err_box.textContent = '';
87+
public_key = temp_key
88+
private_key = inv;
89+
private_key_box.textContent = `${private_key}`;
90+
});
91+
92+
// listen for changes in either p or q
93+
prime1.addEventListener("change", () => {
94+
updateP();
95+
})
96+
97+
prime2.addEventListener("change", () => {
98+
updateQ();
99+
})
14100
}

math_projects/rsa/functions.js

Lines changed: 13 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,61 +9,10 @@ function swapIndicies(array, i, j) {
99
return array;
1010
}
1111

12-
/*
13-
* Extended Euclidean Algorithm
14-
* Input: a, b positive integers
15-
* Output: [s, t, d] where
16-
* as + bt = gcd(a, b) = d
17-
*/
18-
function EEA(a, b) {
19-
if (a > b)
20-
return _EEA(a, b, 1, 0, 0, 1);
21-
else
22-
return swapIndicies(_EEA(b, a, 1, 0, 0, 1), 0, 1);
23-
}
24-
25-
/*
26-
* Helper function for EEA(). Assumes a > b
27-
*/
28-
function _EEA(a, b, s1, s2, t1, t2) {
29-
const q = Math.floor(a / b);
30-
const r = a % b;
31-
const s = s1 - s2 * q;
32-
const t = t1 - t2 * q;
33-
34-
// break condition for algorithm
35-
if (r == 0) {
36-
return [s2, t2, b];
37-
}
38-
return _EEA(b, r, s2, s, t2, t);
39-
}
40-
41-
/*
42-
* Euclidean algorithm to find the gcd. Does not include s,t such that as + bt = gcd
43-
* Input: a, b positive integers
44-
* Output: gcd
45-
*/
46-
function GCD(a, b) {
47-
if (b > a)
48-
return _GCD(b, a);
49-
return _GCD(a, b);
50-
}
51-
52-
/*
53-
* Helper function for gcd. Assumes a > b
54-
*/
55-
function _GCD(a, b) {
56-
const r = a % b;
57-
58-
if (r == 0)
59-
return b;
60-
return _GCD(b, r);
61-
}
62-
6312
/*
6413
* given two primes p, q, lists up to MAX_LISTED_KEYS possible public keys to use
6514
*/
66-
function getPossiblePublicKeys(p, q) {
15+
function getPossiblePublicKeys() {
6716
const phi_n = (p - 1) * (q - 1);
6817

6918
let possibleKeys = []; // list of all possible public keys (keeps up to MAX_LISTED_KEYS keys)
@@ -108,6 +57,11 @@ function getPossiblePublicKeys(p, q) {
10857
break;
10958

11059
key += 2;
60+
61+
if (i > MAX_ITER) {
62+
console.error(`ERROR: getPossibleKeys(${p}, ${q}): MAX_ITER exceeded.`);
63+
return null
64+
}
11165
}
11266

11367
console.log(`Checked keys where they are their own inverse mod ${phi_n}: ${ownInverse}`);
@@ -119,8 +73,14 @@ function arrayToStr(array) {
11973
return "";
12074

12175
let str = `${array[0]}`;
122-
for (let i = 1; i < array.length; i++)
76+
for (let i = 1; i < array.length; i++) {
12377
str += `, ${array[i]}`;
12478

79+
if (i > MAX_ITER) { // should never trigger
80+
console.error(`ERROR: arrayToStr(${array}): MAX_ITER exceeded`);
81+
return null;
82+
}
83+
}
84+
12585
return str;
12686
}

math_projects/rsa/index.html

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<link rel="stylesheet" href="style.css" />
99
<script defer src="functions.js"></script>
1010
<script defer src="eventListeners.js"></script>
11+
<script defer src="update.js"></script>
12+
<script defer src="math.js"></script>
1113
<script defer src="main.js"></script>
1214
</head>
1315
<body>
@@ -17,11 +19,14 @@ <h1>RSA Key Generator</h1>
1719
<section id="input-section">
1820
<label for="prime1">Prime p:</label>
1921
<input type="number" id="prime1" />
22+
<div><p id="prime1-err-box" class="error-box"></p></div>
2023

2124
<label for="prime2">Prime q:</label>
2225
<input type="number" id="prime2" />
26+
<div><p id="prime2-err-box" class="error-box"></p></div>
2327

24-
<button id="gen-choice-btn">Generate Public Key Choices</button>
28+
<button id="gen-choice-btn">Display Some Public Key Choices</button>
29+
<div><p id="gen-public-key-err-box" class="error-box"></p></div>
2530

2631
<div>
2732
<p>Some possible choices include: </p>
@@ -30,14 +35,14 @@ <h1>RSA Key Generator</h1>
3035

3136
<label for="public-key">Public Key</label>
3237
<input type="number" id="public-key">
33-
</section>
38+
<div><p id="public-key-err-box" class="error-box"></p></div>
39+
40+
<div>
41+
<label for="private-key">Private Key</label>
42+
<p id="private-key">None</p>
43+
</div>
3444

35-
<section id="output-section">
36-
<h2>Public Key</h2>
37-
<p id="public-key"></p>
3845

39-
<h2>Private Key</h2>
40-
<p id="private-key"></p>
4146
</section>
4247
</div>
4348
</body>

math_projects/rsa/main.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,16 @@ document.addEventListener("DOMContentLoaded", () => {
44
console.log('Listeners added.');
55
});
66

7+
let p = null
8+
let q = null
9+
let public_key = null
10+
let private_key = null
711

8-
const MAX_LISTED_KEYS = 20; // maximum number of printed possible public keys
12+
const MAX_LISTED_KEYS = 20; // maximum number of printed possible public keys
13+
const MAX_ITER = 50_000; // max number of iterations for any loop
14+
15+
// declared here for convenience b/c they are referenced multiple times
16+
const prime1 = document.getElementById('prime1');
17+
const prime2 = document.getElementById('prime2');
18+
const public_key_box = document.getElementById('public-key');
19+
const private_key_box = document.getElementById('private-key');

math_projects/rsa/math.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Extended Euclidean Algorithm
3+
* Input: a, b positive integers
4+
* Output: [s, t, d] where
5+
* as + bt = gcd(a, b) = d
6+
*/
7+
function EEA(a, b) {
8+
if (a > b)
9+
return _EEA(a, b, 1, 0, 0, 1);
10+
else
11+
return swapIndicies(_EEA(b, a, 1, 0, 0, 1), 0, 1);
12+
}
13+
14+
/*
15+
* Helper function for EEA(). Assumes a > b
16+
*/
17+
function _EEA(a, b, s1, s2, t1, t2) {
18+
const q = Math.floor(a / b);
19+
const r = a % b;
20+
const s = s1 - s2 * q;
21+
const t = t1 - t2 * q;
22+
23+
// break condition for algorithm
24+
if (r == 0) {
25+
return [s2, t2, b];
26+
}
27+
return _EEA(b, r, s2, s, t2, t);
28+
}
29+
30+
/*
31+
* Euclidean algorithm to find the gcd. Does not include s,t such that as + bt = gcd
32+
* Input: a, b positive integers
33+
* Output: gcd
34+
*/
35+
function GCD(a, b) {
36+
if (b > a)
37+
return _GCD(b, a);
38+
return _GCD(a, b);
39+
}
40+
41+
/*
42+
* Helper function for gcd. Assumes a > b
43+
*/
44+
function _GCD(a, b) {
45+
const r = a % b;
46+
47+
if (r == 0)
48+
return b;
49+
return _GCD(b, r);
50+
}
51+
52+
/*
53+
* Returns true if input is prime, false otherwise
54+
* Input: integer
55+
* Output: [bool, factor]
56+
* - If num is prime: bool=true, factor=null
57+
* - If num is not prime: bool=false, factor='A x B'
58+
where num = AB
59+
*/
60+
function isPrime(num) {
61+
if (num == 1)
62+
return [false, '1 x 1']
63+
64+
// check for i = 2, ..., sqrt(num). If i divides num, then num is not prime
65+
for (let i = 2; i <= Math.sqrt(num); i++) {
66+
if (num % i == 0)
67+
return [false, `${num / i} x ${i}`]
68+
}
69+
return [true, null]
70+
}
71+
72+
/*
73+
* Verify that the given key is a valid key mod phi_n. Returns true if key has multiplicative inverse
74+
* mod phi_n and that it is not it's own inverse (implies that it can work as a public key)
75+
* Note: - phi_n = (p - 1)(q - 1)
76+
- This function will never be called with invalid p,q
77+
* Input: key (int), phi_n (int)
78+
* Output: integer
79+
* -- null: error on my part, there is a bug somewhere
80+
* -- > 0: all good, key has a good multiplicative inverse mod phi_n [this is the inverse]
81+
* -- -1: bad, key is not invertible
82+
* -- -2: bad, key is it's own inverse mod phi_n
83+
*/
84+
function verifyKey(key) {
85+
if (p == null || q == null) {
86+
console.error(`ERROR: verifyKey(${key}): function was called when p,q were invalid.`);
87+
return null;
88+
}
89+
90+
const phi_n = (p - 1) * (q - 1);
91+
results = EEA(key, phi_n);
92+
inverse = results[0];
93+
gcd = results[2];
94+
95+
// doesn't have an inverse
96+
if (gcd != 1)
97+
return -1;
98+
// is its own inverse
99+
else if (key**2 % phi_n == 1)
100+
return -2;
101+
102+
// all good, return the inverse
103+
if (inverse < 0) // don't return a negative number, this will be interpretted as an error
104+
inverse += phi_n;
105+
106+
return inverse;
107+
}

math_projects/rsa/style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ body {
2121
width: 100%;
2222
font-size: 1em;
2323
}
24+
25+
.error-box {
26+
color: red;
27+
}
2428

0 commit comments

Comments
 (0)