Skip to content

Instantly share code, notes, and snippets.

@mpmckenna8
Last active March 13, 2017 02:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpmckenna8/10f9a52991d2b86b9677d4346748beac to your computer and use it in GitHub Desktop.
Save mpmckenna8/10f9a52991d2b86b9677d4346748beac to your computer and use it in GitHub Desktop.

Diffie Hellman Key exchange example in javascript

Goal: To make a fairly simple website so people can grok what's going on with this public key exchange to generate a private key thing which is supposed to be pretty important for modern encrypted communication.

This example isn't great because I'm not using anything special to deal with when you start using numbers which are too big for Javascript to handle without starting to round stuff. It will tell you when it probably messed up though.

The library I ended up using to deal with pretty big integers is a bigint library https://github.com/peterolson/BigInteger.js

// this has code to make the diffie-hellman example
// biggest possible number until js math starts messing up 9223372036854775807
var maxnum = Number.MAX_SAFE_INTEGER;
// I think with the bigint library max is:
// 9007199254740992
// the input for p
var pinput = d3.select('#pinput');
var p = pinput.property('value');
// the input for g
var ginput = d3.select('#priminput');
var g = ginput.property('value');
var ainput = d3.select('#ainput')
var a = ainput.property('value');
var binput = d3.select('#binput')
var b = binput.property('value');
pinput.on('keyup',updateInputs);
ginput.on('keyup',updateInputs);
ainput.on('keyup',updateInputs);
binput.on('keyup',updateInputs);
var A;
var B;
var secA, secB;
function calclower(person){
console.log('start calculating', person)
updateInputs();
if(person === 'a'){
A = upperCalc(a)
if(A >= 0){
let capA = d3.select('#aequation').text(A)
d3.select('#Avalq').text(A)
capA.append('svg').attr('class', 'aslidein')
}
else{
d3.select('#aequation').text('Math got too big for js, try new seed numbers')
d3.select('#Avalq').text('math got too big for js, try new numbers')
}
}
else if(person === 'b'){
B = upperCalc(b);
if(B >= 0 ){
console.log('should happen', B)
var capB = d3.select('#bequation').text(B)
d3.select('#Bvalq').text(B);
capB.append('svg').attr('class', 'bslidein')
}
else{
d3.select('#bequation').text('Math got too big for js, try new seed number')
d3.select('#Bvalq').text('Math got too big for js, try new seed number')
}
}
}
// returns the value for the capital letter given an a or b
function upperCalc(lower){
var uppie = -1;
console.log(lower)
if(Math.pow(g, lower)>= Number.MAX_SAFE_INTEGER){
console.log('shit is too big')
uppie = bigInt(g).modPow(lower, p);
uppie = uppie.valueOf;
}
else{
uppie = Math.pow(g,lower)%p;
}
return uppie
}
function updateInputs(){
p = parseInt(pinput.property('value') );
g = parseInt(ginput.property('value') );
a = parseInt(ainput.property('value') );
b = parseInt(binput.property('value') );
// logvars();
}
function calcSecret(person){
if(person === 'b'){
if(Math.pow(A, b)> Number.MAX_SAFE_INTEGER){
console.log('shit is too big')
secB = bigInt(A).modPow(b, p).valueOf();
/*
d3.select("#secliB").style('background-color', 'red')
.append('span').attr('class', 'errmsgB').text('It probably did not work because the math got too big')
*/
d3.select("#secretValueB").text(secB)
}
else{
d3.selectAll(".errmsgB").remove();
d3.select("#secliB").style('background-color', 'transparent');
}
logvars();
secB = Math.pow(A, b) % p;
d3.select("#secretValueB").text(secB)
}
else if(person === 'a'){
if( Math.pow(B, a) > maxnum ){
// console.log('shit is too big')
var errmsgs = d3.selectAll('.errmsgA');
// console.log(errmsgs)
// d3.select("#secliA").style('background-color', 'red').append('span') .text('It probably did not work because the math got too big') .attr('class', 'errmsgA')
}
else{
d3.selectAll('.errmsgA').remove()
d3.select("#secliA").style('background-color', 'transparent')
}
secA = bigInt(B).modPow(a,p).valueOf(); //Math.pow(B, a) % p;
let secretA = d3.select("#secretValueA").text(secA);
}
}
function logvars(){
console.log("p = ", p, "g = ",g, ", a = ", a, ", b = ",
b, ", A = ", A, ", B = ", B);
}
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<link href="style.css" rel="stylesheet">
<style>
</style>
</head>
<body>
<h1>Diffie-Hellman Key Exchange</h1>
<p>
Goal: To exchange cryptographic keys over a public channel.
</br>
Then we can encrypt all future communication!
</p>
<p>
<b>Prereqs:</b>
</br>
<ul>
<li>
A prime number greater than 2, <span class="primer">p</span>.
</li>
<li>
A <a href="https://en.wikipedia.org/wiki/Primitive_root_modulo_n">
primitive root modulo</a> of p which we'll call <span class="primmod">g</span>.
</li>
<li>
A secret integer for each party generating the secret key: a and b.
<ul>
<li>value muse be less than p but greater than 1.</li>
</ul>
</li>
</ul>
<b>Operations:</b>
<ul>
<li>Person with a calculates A and sends the result publicly to b while b does the same for B.
</li>
<li>Each person can use the capital letter variables and some fancy
exponent and modulo math to calculate a shared secret key (s below) which will be super difficult
for a third party to figure out given only the publicly available variables
p, g, A, B.
</li>
</ul>
</p>
<div id="givens">
Establish givens which will be public
</br>
<form action="none" method="get" class="givenform">
<span><label>p =<div class="givmid"> prime number </div>= <input type="text" id="pinput" value="31"></label></span></br>
<span><label><span class="primmod">g</span> =<span class="givmid"> primitive root modulo </span>= <input id="priminput" type="text" value="3">
</label></span>
</form>
</div>
<div id="people">
<div id="allie" class="person">
<h3>Allie</h3>
<p>
Choose a secret integer for Allie
<form action="javascript:void(0);">
<ul>
<li>
<span><label>a = Secret integer choosen by Allie =
<input type="text" id="ainput" value='9'></label></span>
</li>
</ul>
</form>
</br>
Calculations:
<ul>
<li>
A = g<sup>a</sup> modulo p = <span id="aequation"></span>
</li>
<button onclick="calclower('a')">Calculate</button>
</ul>
Then we send A over to the other person. This will be assumed to be publicly accessible.
Wait for B to be sent from the other person to calculate the secret.
<ul>
<li>
B = <span id="Bvalq">?</span>
</li>
</ul>
Once we have B we can calculate the secret.
<ul>
<li id="secliA">
S = B<sup>a</sup> modulo p = <span id="secretValueA">?</span>
</li>
<button onclick="calcSecret('a')">Calculate</button>
</ul>
</p>
</br>
</div>
<div id="butch" class="person">
<h3>Butch</h3>
<p>
Choose a secret integer for Butch
<form action="javascript:void(0);">
<ul>
<li>
<span><label>b = Secret integer choosen by Butch =
<input type="text" id="binput" value='2'></label></span>
</li>
</ul>
</form>
</br>
Calculations:
<ul>
<li>
B = g<sup>b</sup> modulo p = <span id="bequation"></span>
</li>
<button onclick="calclower('b')">Calculate</button>
</ul>
Then we send B over to the other person. This will be assumed to be publicly accessible.
Wait for A to be sent from the other person to calculate the secret.
<ul>
<li>
A = <span id="Avalq">?</span>
</li>
</ul>
Once we have A we can calculate the secret.
<ul>
<li id="secliB">
S = A<sup>b</sup> modulo p = <span id="secretValueB">?</span>
</li>
<button onclick="calcSecret('b')">Calculate</button>
</ul>
</p>
</br>
</div>
</div>
</br>
<footer>
<div>
Learn more about <a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">diffie-hellman key exchange on wikipedia</a>
<div>
Styling is a lot from Tufte.css see: <a href="https://edwardtufte.github.io/tufte-css/">https://edwardtufte.github.io/tufte-css/</a>
</div>
</footer>
<script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="diffiel.js"></script>
</body>
</html>
.infoText {
stroke: #999;
stroke-opacity: 0.6;
}
.aslidein {
animation-duration: 2s;
animation-name: slidein;
animation-iteration-count: 1;
animation-direction: alternate;
position:absolute;
background-color: green;
height:25px;
z-index: 10;
width:3%;
opacity: .35;
margin-left: -3%;
}
@keyframes slidein {
from {
margin-left:-3%;
width:4%;
}
to {
margin-left:22%;
width:10%;
margin-top:160px
}
}
.bslidein {
animation-duration: 2s;
animation-name: slideleft;
animation-iteration-count: 1;
animation-direction: alternate;
position:absolute;
background-color: green;
height:25px;
z-index: 10;
width:4%;
opacity: .35;
margin-left: -4%;
}
@keyframes slideleft {
from {
margin-left:-4%;
width:4%;
margin-top:0px
}
to {
margin-left:-63%;
width:10%;
margin-top:160px
}
}
#mainsvg {
background-color: grey;
}
.primer {
color: green;
}
.primmod {
color: #1e4f4b;
}
.givenform {
align-content: center;
display:inline-block;
}
.givmid{
display:inline-block;
width:180px;
text-align:center;
}
.person{
width:49%;
display:inline-block;
}
.givmid {
}
#butch {
background-color: #e9d9f7;
}
#allie {
background-color: #fffcd3
}
// stolen from https://github.com/edwardtufte/tufte-css/blob/gh-pages/tufte.css
@charset "UTF-8";
/* Import ET Book styles
adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */
/* Tufte CSS styles */
html { font-size: 15px; }
body { width: 87.5%;
margin-left: auto;
margin-right: auto;
padding-left: 12.5%;
font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
background-color: #fffff8;
color: #111;
max-width: 1400px;
counter-reset: sidenote-counter; }
h1 { font-weight: 400;
margin-top: 4rem;
margin-bottom: 1.5rem;
font-size: 3.2rem;
line-height: 1; }
h2 { font-style: italic;
font-weight: 400;
margin-top: 2.1rem;
margin-bottom: 0;
font-size: 2.2rem;
line-height: 1; }
h3 { font-style: italic;
font-weight: 400;
font-size: 1.7rem;
margin-top: 2rem;
margin-bottom: 0;
line-height: 1; }
hr { display: block;
height: 1px;
width: 55%;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0; }
p.subtitle { font-style: italic;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1.8rem;
display: block;
line-height: 1; }
.numeral { font-family: et-book-roman-old-style; }
.danger { color: red; }
article { position: relative;
padding: 5rem 0rem; }
section { padding-top: 1rem;
padding-bottom: 1rem; }
p, ol, ul { font-size: 1.4rem; }
p { line-height: 2rem;
margin-top: 1.4rem;
margin-bottom: 1.4rem;
padding-right: 0;
vertical-align: baseline; }
/* Chapter Epigraphs */
div.epigraph { margin: 5em 0; }
div.epigraph > blockquote { margin-top: 3em;
margin-bottom: 3em; }
div.epigraph > blockquote, div.epigraph > blockquote > p { font-style: italic; }
div.epigraph > blockquote > footer { font-style: normal; }
div.epigraph > blockquote > footer > cite { font-style: italic; }
/* end chapter epigraphs styles */
blockquote { font-size: 1.4rem; }
blockquote p { width: 55%;
margin-right: 40px; }
blockquote footer { width: 55%;
font-size: 1.1rem;
text-align: right; }
section>ol, section>ul { width: 45%;
-webkit-padding-start: 5%;
-webkit-padding-end: 5%; }
li { padding: 0.5rem 0; }
figure { padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
max-width: 55%;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
margin: 0 0 3em 0; }
figcaption { float: right;
clear: right;
margin-top: 0;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.6;
vertical-align: baseline;
position: relative;
max-width: 40%; }
figure.fullwidth figcaption { margin-right: 24%; }
/* Links: replicate underline that clears descenders */
a:link, a:visited { color: inherit; }
a:link { text-decoration: none;
background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#333, #333);
background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(#333, #333);
-webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
-moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
background-repeat: no-repeat, no-repeat, repeat-x;
text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8;
background-position: 0% 93%, 100% 93%, 0% 93%; }
@media screen and (-webkit-min-device-pixel-ratio: 0) { a:link { background-position-y: 87%, 87%, 87%; } }
a:link::selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe;
background: #b4d5fe; }
a:link::-moz-selection { text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe;
background: #b4d5fe; }
/* Sidenotes, margin notes, figures, captions */
img { max-width: 100%; }
.sidenote, .marginnote { float: right;
clear: right;
margin-right: -60%;
width: 50%;
margin-top: 0;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.3;
vertical-align: baseline;
position: relative; }
.sidenote-number { counter-increment: sidenote-counter; }
.sidenote-number:after, .sidenote:before { content: counter(sidenote-counter) " ";
font-family: et-book-roman-old-style;
position: relative;
vertical-align: baseline; }
.sidenote-number:after { content: counter(sidenote-counter);
font-size: 1rem;
top: -0.5rem;
left: 0.1rem; }
.sidenote:before { content: counter(sidenote-counter) " ";
top: -0.5rem; }
blockquote .sidenote, blockquote .marginnote { margin-right: -82%;
min-width: 59%;
text-align: left; }
p, footer, table { width: 55%; }
div.fullwidth, table.fullwidth { width: 100%; }
div.table-wrapper { overflow-x: auto;
font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif; }
.sans { font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
letter-spacing: .03em; }
code { font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 1.0rem;
line-height: 1.42; }
.sans > code { font-size: 1.2rem; }
h1 > code, h2 > code, h3 > code { font-size: 0.80em; }
.marginnote > code, .sidenote > code { font-size: 1rem; }
pre.code { font-size: 0.9rem;
width: 52.5%;
margin-left: 2.5%;
overflow-x: auto; }
pre.code.fullwidth { width: 90%; }
.fullwidth { max-width: 90%;
clear:both; }
span.newthought { font-variant: small-caps;
font-size: 1.2em; }
input.margin-toggle { display: none; }
label.sidenote-number { display: inline; }
label.margin-toggle:not(.sidenote-number) { display: none; }
@media (max-width: 760px) { body { width: 84%;
padding-left: 8%;
padding-right: 8%; }
p, footer { width: 100%; }
pre.code { width: 97%; }
ul { width: 85%; }
figure { max-width: 90%; }
figcaption, figure.fullwidth figcaption { margin-right: 0%;
max-width: none; }
blockquote { margin-left: 1.5em;
margin-right: 0em; }
blockquote p, blockquote footer { width: 100%; }
label.margin-toggle:not(.sidenote-number) { display: inline; }
.sidenote, .marginnote { display: none; }
.margin-toggle:checked + .sidenote,
.margin-toggle:checked + .marginnote { display: block;
float: left;
left: 1rem;
clear: both;
width: 95%;
margin: 1rem 2.5%;
vertical-align: baseline;
position: relative; }
label { cursor: pointer; }
div.table-wrapper, table { width: 85%; }
img { width: 100%; } }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment