Merge branch 'master' of https://github.com/StephanRichter/shamirs_secret_web_impleme...
authorStephan Richter <github@keawe.de>
Fri, 13 Oct 2017 13:42:51 +0000 (15:42 +0200)
committerStephan Richter <github@keawe.de>
Fri, 13 Oct 2017 13:42:51 +0000 (15:42 +0200)
src/secret.html [new file with mode: 0644]

diff --git a/src/secret.html b/src/secret.html
new file mode 100644 (file)
index 0000000..39bb322
--- /dev/null
@@ -0,0 +1,262 @@
+<html>
+<head>
+<style type="text/css">
+       @media print {
+               #pages > div{
+                       page-break-after: always;
+               }
+       
+               fieldset{
+                       display: none;
+               };
+       }
+       
+       @media screen {
+               #pages{
+                       display: none;
+               }
+       }       
+
+       td{
+               text-align: right;
+               padding: 10px;
+       }
+       td:nth-child(2n){
+               background:#ccc;
+       }
+       tr:nth-child(2) td{
+               border-width: 0 0 5px 0;
+               border-style: solid;
+               
+       }
+       .half{
+               border: 1px solid black;
+       }
+       .num{
+               width: 40px;
+       }
+       
+       #pages span {
+       border: 1px solid gray;
+       display: inline-block;
+       margin: 3px;
+       padding: 3px;
+       }
+       textarea{ 
+               width: 100%;
+               min-height: 150px;
+       }
+       
+       
+</style>
+<script type="text/javascript">
+var prime=257;
+function createElement(e,t){return '<'+e+'>'+t+'</'+e+'>';} // html element with content t
+function getElement(i){return document.getElementById(i);}
+function setHtmlOf(i,t){getElement(i).innerHTML=t};
+function valueOfField(i){return getElement(i).value;} // value of element with id
+
+function rand256(){
+       return Math.floor(Math.random() * 256);
+}
+
+/* Split number into the shares */
+function split(number, number_of_shares, needed) {
+    var coef = [number]; // first coefficient always equals the number itself.
+    var shares = [];
+    
+    for(var coef_index = 1; coef_index < needed; coef_index++) coef[coef_index] = rand256();    
+    for(var share_number = 1; share_number <= number_of_shares; share_number++) {
+       var sum = 0;
+       for (var coef_index =0; coef_index<needed; coef_index++) sum += coef[coef_index]*Math.pow(share_number,coef_index);
+       shares[share_number-1] = sum % prime; 
+    }
+    return shares;
+}
+
+function collect(){
+       var divs=document.getElementsByClassName('share');
+       var shares=[];
+       var string;
+       
+       // gather values from the input fields
+       for (var div_index=0; div_index<divs.length; div_index++){
+               var div=divs[div_index];
+               var inputs = div.getElementsByTagName('input');
+               var share_number=0;                     
+               for (var j=0; j<inputs.length;j++){
+                       var input = inputs[j];
+                       if (input.className == 'num') {
+                               share_number=input.value;
+                       } else {
+                               string=input.value;
+                               if (share_number>0 && string!='') {
+                                       var parts = string.split(' ');
+                                       shares[div_index] = { share_number, parts };
+                               }
+                       }
+               }
+       }       
+       
+       // the create new input fields on demand
+       if (string!=''){
+               var clone=div.cloneNode(true);
+               var inputs=clone.getElementsByTagName('input');
+               for (var j=0; j<inputs.length; j++) inputs[j].value='';
+               div.parentNode.appendChild(clone);
+       }
+       return shares;
+}
+
+function gcdD(a,b) { 
+    if (b == 0) return [a, 1, 0]; 
+    else { 
+        var n = Math.floor(a/b), c = a % b, r = gcdD(b,c); 
+        return [r[0], r[2], r[1]-r[2]*n];
+    }
+}
+
+function modInverse(k) { 
+    k = k % prime;
+    var r = (k < 0) ? -gcdD(prime,-k)[2] : gcdD(prime,k)[2];
+    return (prime + r) % prime;
+}
+
+function join(shares) {
+    var sum = 0;
+    
+    for(j = 0; j < shares.length; j++) {
+        var numerator = 1;
+        var denominator = 1;
+        for(m = 0; m < shares.length; m++) {
+            if(j == m) continue; // If not the same value
+            numerator = (numerator * shares[m].share_number) % prime;
+            denominator = (denominator * (shares[m].share_number - shares[j].share_number)) % prime;
+        }
+        sum = (prime + sum + (shares[j].share * numerator * modInverse(denominator))) % prime;
+    }
+    
+    return sum;
+}
+
+/* get the number of codes from the list of shares */
+function numberOfCodesIn(shares_list){
+       var result=null;
+       for (var i=0; i<shares_list.length; i++) {
+               if (result == null){            
+                       result = shares_list[i].parts.length;
+               } else {
+                       result=Math.min(shares_list[i].parts.length,result);
+               }               
+       }
+       return result;
+}
+
+/* fetches values from the input fields, decomposes each input string into several shares and reconstructs the original code/char for each position */
+function decode(){
+       var shares_list=collect(); // fetch shares
+       var ascii=getElement('ascii');
+       var result=getElement('result');        
+       
+       ascii.innerHTML='ascii: ';
+       result.innerHTML='Passphrase: ';
+       
+       var codeCount = numberOfCodesIn(shares_list);
+       for (var codeIndex = 0; codeIndex<codeCount; codeIndex++){
+               shares_for_code = [];
+               
+               shares_list.forEach(function(share_set){
+                       var share_number = share_set.share_number;
+                       var share = share_set.parts[codeIndex];
+                       shares_for_code.push({ share_number, share });
+               });
+               
+               var code = join(shares_for_code);
+               ascii.innerHTML += code+' ';
+               result.innerHTML+= String.fromCharCode(code);
+       }
+}
+
+/* decomposes the given secrets into single characters. Then, the ascii code of each caracter is treated as secre and split into keys */
+function secret2numbers(string){
+       var string_pos,share_number,coef,char_code,x,sum;
+       var number_of_shares = valueOfField('shares');
+       var treshold             = valueOfField('treshold');
+       var results = [];
+       
+       // create table elements for displaying the shares
+       var char_cells      = createElement('th','char');;
+       var char_code_cells = createElement('th','ascii');;
+       
+       // decompose string, for each character create secrets from asccii code
+       for (string_pos=0; string_pos<string.length;string_pos++) {
+               char_code        = string.charCodeAt(string_pos);
+               char_cells      += createElement('td',string[string_pos]);
+               char_code_cells += createElement('td',char_code);
+               
+               results[string_pos] = split(char_code,number_of_shares,treshold);
+       }       
+       
+       var code=createElement('tr',char_cells)+createElement('tr',char_code_cells);
+       var pages=getElement('pages');
+       var explanation=valueOfField('explanation').replace('%n',valueOfField('treshold')).replace(/\n/g,'<br/>');
+       pages.innerHTML='';
+       for (share_number=0;share_number<number_of_shares;share_number++){
+               var line=createElement('th','share '+(share_number+1));
+               var page='';
+               for (string_pos=0;string_pos<string.length;string_pos++){
+                       line+=createElement('td',results[string_pos][share_number]);
+                       page+=createElement('span',results[string_pos][share_number]);
+               }
+               code+=createElement('tr',line);         
+               pages.innerHTML+=createElement('div',  createElement('p',explanation)+createElement('p','Your share number: '+(share_number+1))+createElement('p',page)   );    
+       }
+       setHtmlOf('tab',code);
+       return char_code;
+}
+</script>
+</head>
+<body>
+       <fieldset>
+               <legend>Decode secret from shares</legend>
+               <div>
+                       <div class="share">
+                               Share #<input class="num" value="1" />: <input class="code" onkeyup="decode();"/>
+                       </div>
+               </div>          
+               <p id="ascii"></p>
+               <p id="result"></p>
+       </fieldset>
+       <fieldset>
+               <legend>Create shares from secret</legend>
+               Explanation to add:<br/>                
+               <textarea id="explanation" name="explanation">
+This document is a PART of a secret passphrase. At least %n of these secret parts are required to reconstruct the original passphrase.
+In the event of (enter condition here), you may meet with other secret-part holders to unite your keys.
+
+To obtain the secret phassphrase:
+<ol>
+       <li>collect at least %n secret shares</li>
+       <li>go to [url of this page]</li>
+       <li>enter the share number and the respective numbers separated by spaces</li>
+</ol>
+The passphrase obtained will give you access to [insert description of secured thing here...].
+
+[More instructions]
+
+Info: These secrets were generated using the "Shamir's Secret Sharing" algorithm.
+               </textarea><br/>
+               Passphrase parts to generate: <input id="shares" value="5" /></br>
+               Minimum nuber of shares required to recreate secret: <input id="treshold" value="3" /></br>
+               Secret: <input name="secret" onkeyup="secret2numbers(this.value);" />
+               <table id="tab"></table>
+               <ol>
+               <li>Set the explanation you want.</li>
+               <li>Enter the number of parts and shares you wish.</li>
+               <li>Enter your secret passphrase</li>
+               <li>Hit Ctrl+P or go to print via the menu</li>
+               </ol>
+       </fieldset>
+       <div id="pages"></div>
+</body>
+</html>
\ No newline at end of file