Skip to content

Commit

Permalink
feat: RSA cryptosystem signature project (freeCodeCamp#184)
Browse files Browse the repository at this point in the history
* feat: RSA cryptosystem signature project

* fix: Large primes and message text

- Fixes issue with large primes
- Default message revised to fix minor typos
- Revised success and failure messages

* feat: Break into test decriptions (Part 1)

* fix: Improved and added more test decriptions

* fix: Revise and add test descriptions

* fix: Revise and add more test descriptions

* fix: Update and add more test descriptions

* fix: Improve and add more descriptions

- Added a diagram to explain the signing process
- Revised all the test descriptions
- Added some descriptions to illustrate hash collision

To Do: Explain the internals of encryption and decryption equations
  • Loading branch information
vkWeb authored and SomeDer committed Aug 26, 2019
1 parent 0ea43cd commit 8dc5901
Show file tree
Hide file tree
Showing 59 changed files with 2,572 additions and 0 deletions.
Binary file added index51.js
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions rsa-cryptosystem-signature/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>RSA Digital Signature System</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
72 changes: 72 additions & 0 deletions rsa-cryptosystem-signature/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const firstPrime = 2;
const secondPrime = 5;
const N = firstPrime * secondPrime;
const phiOfN = (firstPrime - 1) * (secondPrime - 1);
let publicKey = 0;

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue % N;
}

function isCoPrime(smallerNum, largerNum) {
for (let i = 2; i <= smallerNum; ++i) {
if (smallerNum % i === 0 && largerNum % i === 0) {
return false;
}
}
return true;
}

function generatePrivateKey() {
for (let privateKey = 2; privateKey < phiOfN; ++privateKey) {
if (isCoPrime(privateKey, N) && isCoPrime(privateKey, phiOfN)) {
return privateKey;
}
}

console.log("Private key can't be generated.");
return 0;
}

function generatePublicKey(privateKey) {
while (privateKey) {
if ((publicKey * privateKey) % phiOfN === 1 && privateKey !== publicKey) {
return;
}
++publicKey;
}

console.log("Public key can't be generated.");
}

function generateSignature(hashValue, privateKey) {
return Math.pow(hashValue, privateKey) % N;
}

function decryptSignature(digitalSignature) {
return Math.pow(digitalSignature, publicKey) % N;
}

function sendMsgToBob(message) {
const privateKey = generatePrivateKey();
generatePublicKey(privateKey);
const hashValue = hashTheMessage(message);
const generatedSignature = generateSignature(hashValue, privateKey);
sendAndVerify(generatedSignature, message);
}

function sendAndVerify(digitalSignature, message) {
const hashValue = hashTheMessage(message);
const decryptedSignature = decryptSignature(digitalSignature);
if (hashValue === decryptedSignature) {
console.log("Success! Data is intact and signature is verified.");
} else {
console.log("Failure! There's something wrong with data or signature.");
}
}

sendMsgToBob("Hey Bob, I'm Alice here. Bob, Buy 300 shares of TSLA!");
10 changes: 10 additions & 0 deletions rsa-cryptosystem-signature/index01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Cryptography is a mathematical art of protecting information from an unauthorized access.
Digital signature is a way to verify the authenticity and integrity of documents and messages.
First we hash our message, which is a method to transform a document into a fixed-size value.
Create an empty function `hashTheMessage()` with `message` as a parameter.
Functions which hash the data are called hash functions.
*/
9 changes: 9 additions & 0 deletions rsa-cryptosystem-signature/index02.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function hashTheMessage(message) {
/*
There are two types of hash functions -- cryptographic and non-cryptographic. Cryptographic hash functions are used for password management and non-cryptographic ones are used for database management.
The basics are same for both the types. The fixed-size value returned by a hash function is referred to as a hash value or hash.
Create a variable `hashValue` and set it to 0.
*/
}
10 changes: 10 additions & 0 deletions rsa-cryptosystem-signature/index03.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function hashTheMessage(message) {
let hashValue = 0;
/*
A slight change in `message` should output a different hash value. This is called an avalanche effect.
So hash functions ideally use all of the data passed to it for hashing.
Create a `for` loop to iterate over all the characters of `message`.
*/
}
12 changes: 12 additions & 0 deletions rsa-cryptosystem-signature/index04.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; i++) {
/*
Hash functions are one way functions, which means you can’t figure out the `message` if you only know the hash value.
We will represent our hash value as an integer.
Add the ASCII value of characters to `hashValue`.
Use `charCodeAt(index)` to find the ASCII value of each character in `message`.
*/
}
}
10 changes: 10 additions & 0 deletions rsa-cryptosystem-signature/index05.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; i++) {
hashValue += message.charCodeAt(i);
}
/*
Hash functions are deterministic, which means they return the same hash value when the same message is passed.
Return `hashValue`.
*/
}
17 changes: 17 additions & 0 deletions rsa-cryptosystem-signature/index06.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; i++) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

/*
In `ROT13` cipher, a modern version of the Caesar Cipher, the value of each letter is shifted by 13 places. So, 13 is called the key in `ROT13`.
13 is a key that is used both for encryption and decryption. Thus, `ROT13` cipher is a type of symmetric key cryptography.
In asymmetric key cryptography, each user has a public and a private key. The public key can be shared with anyone.
Create an empty function `generatePublicKey()`.
*/
15 changes: 15 additions & 0 deletions rsa-cryptosystem-signature/index07.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; i++) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePublicKey() {}

/*
However the private key must be kept secret.
Create an empty function `generatePrivateKey()`.
*/
19 changes: 19 additions & 0 deletions rsa-cryptosystem-signature/index08.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
If `publicKey` is used for encryption then only the matching `privateKey` can decrypt it.
Keep in mind that the opposite is also true. Therefore, they are referred to as key pairs.
Create a variable called `publicKey` and set it to 0.
*/

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}
21 changes: 21 additions & 0 deletions rsa-cryptosystem-signature/index09.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
let publicKey = 0;

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

/*
Suppose Alice sends an encrypted message to Bob using a symmetric key like the number 13 in `ROT13`. There's no way for Bob to verify that the sender is really Alice because anyone with access to that key can send Bob a message and claim to be Alice.
A digital signature solves this problem. By encrypting the hash value of the message with her private key Alice creates a unique signature.
Create an empty function called `generateSignature()`.
*/
27 changes: 27 additions & 0 deletions rsa-cryptosystem-signature/index10.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
let publicKey = 0;

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

/*
![Diagram of RSA digital signing process](RSA signing process diagram.png)
Alice sends her unique signature along with the message to Bob.
Bob then does two things -- first, he decrypts the signature using Alice's public key. Next, he uses Alice's hash function to generate a hash value of the received message.
If the hash value of the received message and the decrypted signature match, then the data is intact and message is really from Alice.
Create an empty function `decryptSignature()`.
*/
25 changes: 25 additions & 0 deletions rsa-cryptosystem-signature/index11.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
let publicKey = 0;

/*
We'll use the RSA asymmetric cryptographic algorithm to generate key pairs, to encrypt and decrypt data.
RSA is based on the fact that finding prime factors of a large number is difficult.
Create a constant named `firstPrime` and set it to 2.
*/

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

function decryptSignature() {}
25 changes: 25 additions & 0 deletions rsa-cryptosystem-signature/index12.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const firstPrime = 2;
let publicKey = 0;

/*
Prime numbers are only divisible by 1 and by the number itself.
The first few prime numbers are 2, 3, 5, 7, and 11.
Create a constant `secondPrime` and set it to 5.
*/

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

function decryptSignature() {}
29 changes: 29 additions & 0 deletions rsa-cryptosystem-signature/index13.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const firstPrime = 2;
const secondPrime = 5;
let publicKey = 0;

/*
Create a constant `N` and set it as `firstPrime * secondPrime`.
`N` will be used to generate both private and public keys.
Here, `N = 10`. So, it's easy to find the prime factors: 2 and 5.
But in real world usage `N` is around 600 digits long, which makes prime factorization almost impossible.
Our implementation is insecure, and is just to teach you about the fundamentals of asymmetric cryptography.
*/

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

function decryptSignature() {}
28 changes: 28 additions & 0 deletions rsa-cryptosystem-signature/index14.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const firstPrime = 3;
const secondPrime = 5;
const N = firstPrime * secondPrime;
let publicKey = 0;

/*
Private key must be between 1 and `Φ(N)` or `1 < privateKey < Φ(N)`.
`Φ(N)` pronounced as phi of N is called Euler's totient function. It outputs number of integers up to `N` that are coprime with `N`.
Create a constant `phiOfN` and set it to 0.
*/

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

function decryptSignature() {}
30 changes: 30 additions & 0 deletions rsa-cryptosystem-signature/index15.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const firstPrime = 2;
const secondPrime = 5;
const N = firstPrime * secondPrime;
const phiOfN = 0;
let publicKey = 0;

function hashTheMessage(message) {
let hashValue = 0;
for (let i = 0, msgLength = message.length; i < msgLength; ++i) {
hashValue += message.charCodeAt(i);
}
return hashValue;
}

/*
Two integers are coprime if the only positive integer that divides both of them simultaneously is 1.
For example, 10 can be divided evenly by 2 and 5. But 7 can't be divided evenly by 2 and 5.
10 and 7 both are only divisible by 1. Hence, 10 and 7 are coprime.
Create an empty function named `isCoPrime` with `smallerNum` and `largerNum` as parameters.
*/

function generatePrivateKey() {}

function generatePublicKey() {}

function generateSignature() {}

function decryptSignature() {}
Loading

0 comments on commit 8dc5901

Please sign in to comment.