dd2a677a073890e11af1ce2eac7cb2c168ce933d
[shamirs_secret_web_implementation.git] / src / secret.html
1 <html>
2 <head>
3 <style type="text/css">
4         @media print {
5                 #pages > div{
6                         page-break-after: always;
7                 }
8         
9                 fieldset{
10                         display: none;
11                 };
12         }
13         
14         @media screen {
15                 #pages{
16                         display: none;
17                 }
18         }       
19
20         td{
21                 text-align: right;
22                 padding: 10px;
23         }
24         td:nth-child(2n){
25                 background:#ccc;
26         }
27         tr:nth-child(2) td{
28                 border-width: 0 0 5px 0;
29                 border-style: solid;
30                 
31         }
32         .half{
33                 border: 1px solid black;
34         }
35         .num{
36                 width: 40px;
37         }
38         
39         #pages span {
40         border: 1px solid gray;
41         display: inline-block;
42         margin: 3px;
43         padding: 3px;
44         }
45         textarea{ 
46                 width: 100%;
47                 min-height: 150px;
48         }
49         
50         
51 </style>
52 <script type="text/javascript">
53 var prime=257;
54 function createElement(e,t){return '<'+e+'>'+t+'</'+e+'>';} // html element with content t
55 function getElement(i){return document.getElementById(i);}
56 function setHtmlOf(i,t){getElement(i).innerHTML=t};
57 function valueOfField(i){return getElement(i).value;} // value of element with id
58
59 function rand256(){
60         return Math.floor(Math.random() * 256);
61 }
62
63 /* Split number into the shares */
64 function split(number, number_of_shares, needed) {
65     var coef = [number]
66     var shares = [];
67
68     for(var coef_index = 1; coef_index < needed; coef_index++){
69         coef[coef_index] = rand256();
70     }
71     
72     for(var share_number = 1; share_number <= number_of_shares; share_number++) {
73         var sum = 0;
74         for (var coef_index =0; coef_index<needed; coef_index++){
75                 sum += coef[coef_index]*Math.pow(share_number,coef_index);
76         }
77         
78         shares[share_number-1] = sum % prime; 
79     }
80     return shares;
81 }
82
83 function share(index,string){
84         this.index=index;
85         this.codes=string.split(' ');
86         this.codeCount=function(){return this.codes.length};
87         this.code=function(i){return this.codes[i];};
88         this.pick=function(i){return [this.index,this.codes[i]]};
89         this.string=function(){
90                 return 'Share '+this.index+': '+this.codes.join(' / ');
91         };
92 }
93
94 function collect(){
95         var divs=document.getElementsByClassName('share');
96         var shares=[],lastValue,div,inputs,num;
97         for (i=0; i<divs.length; i++){
98                 div=divs[i];
99                 inputs = div.getElementsByTagName('input');
100                 num=0;                  
101                 for (var j=0; j<inputs.length;j++){
102                         var input = inputs[j];
103                         if (input.className == 'num') {
104                                 num=input.value;
105                         } else {
106                                 lastValue=input.value;
107                                 if (num>0 && lastValue!='') shares[i]=new share(num,lastValue);
108                         }
109                 }
110         } 
111         if (lastValue!=''){
112                 var clone=div.cloneNode(true);
113                 var inputs=clone.getElementsByTagName('input');
114                 for (var j=0; j<inputs.length; j++) inputs[j].value='';
115                 div.parentNode.appendChild(clone);
116         }
117         return shares;
118 }
119
120 function gcdD(a,b) { 
121     if (b == 0) return [a, 1, 0]; 
122     else { 
123         var n = Math.floor(a/b), c = a % b, r = gcdD(b,c); 
124         return [r[0], r[2], r[1]-r[2]*n];
125     }
126 }
127
128 function modInverse(k) { 
129     k = k % prime;
130     var r = (k < 0) ? -gcdD(prime,-k)[2] : gcdD(prime,k)[2];
131     return (prime + r) % prime;
132 }
133
134 function join(shares) {
135     var accum, count, formula, startposition, nextposition, value, numerator, denominator;
136     for(formula = accum = 0; formula < shares.length; formula++) {
137         for(count = 0, numerator = denominator = 1; count < shares.length; count++) {
138             if(formula == count) continue; // If not the same value
139             startposition = shares[formula][0];
140             nextposition = shares[count][0];
141             numerator = (numerator * -nextposition) % prime;
142             denominator = (denominator * (startposition - nextposition)) % prime;
143         }
144         value = shares[formula][1];
145         accum = (prime + accum + (value * numerator * modInverse(denominator))) % prime;
146     }
147     return accum;
148 }
149
150 function decode(){
151         var shares=collect(); // fetch shares
152         var codeCount=null;
153         for (var i=0; i<shares.length; i++) codeCount=(codeCount==null)?shares[i].codeCount():Math.min(shares[i].codeCount(),codeCount);
154         var ascii=document.getElementById('ascii');
155         ascii.innerHTML='ascii: ';
156         result.innerHTML='Passphrase: ';
157         for (codeIndex=0; codeIndex<codeCount; codeIndex++){
158                 var shareSet=[];
159                 for (var i=0; i<shares.length; i++){
160                         shareSet[i]=shares[i].pick(codeIndex);
161                 }
162                 var r=join(shareSet);
163                 ascii.innerHTML += r+' ';
164                 result.innerHTML+= String.fromCharCode(r);
165         }
166 }
167
168 function secret2numbers(string){
169         var string_pos,share_number,coef,char_code,x,sum;
170         var number_of_shares = valueOfField('shares');
171         var treshold             = valueOfField('treshold');
172         var results = [];
173         
174         // create table elements for displaying the shares
175         var char_cells      = createElement('th','char');;
176         var char_code_cells = createElement('th','ascii');;
177         
178         // decompose string, for each character create secrets from asccii code
179         for (string_pos=0; string_pos<string.length;string_pos++) {
180                 char_code        = string.charCodeAt(string_pos);
181                 char_cells      += createElement('td',string[string_pos]);
182                 char_code_cells += createElement('td',char_code);
183                 
184                 results[string_pos] = split(char_code,number_of_shares,treshold);
185         }       
186         
187         var code=createElement('tr',char_cells)+createElement('tr',char_code_cells);
188         var pages=getElement('pages');
189         var explanation=valueOfField('explanation').replace('%n',valueOfField('treshold')).replace(/\n/g,'<br/>');
190         pages.innerHTML='';
191         for (share_number=0;share_number<number_of_shares;share_number++){
192                 var line=createElement('th','share '+(share_number+1));
193                 var page='';
194                 for (string_pos=0;string_pos<string.length;string_pos++){
195                         line+=createElement('td',results[string_pos][share_number]);
196                         page+=createElement('span',results[string_pos][share_number]);
197                 }
198                 code+=createElement('tr',line);         
199                 pages.innerHTML+=createElement('div',  createElement('p',explanation)+createElement('p','Your share number: '+(share_number+1))+createElement('p',page)   );    
200         }
201         setHtmlOf('tab',code);
202         return char_code;
203 }
204 </script>
205 </head>
206 <body>
207         <fieldset>
208                 <legend>Decode secret from shares</legend>
209                 <div>
210                         <div class="share">
211                                 Share #<input class="num" value="1" />: <input class="code" onkeyup="decode();"/>
212                         </div>
213                 </div>          
214                 <p id="ascii"></p>
215                 <p id="result"></p>
216         </fieldset>
217         <fieldset>
218                 <legend>Create shares from secret</legend>
219                 Explanation to add:<br/>                
220                 <textarea id="explanation" name="explanation">
221 This document is a PART of a secret passphrase. At least %n of these secret parts are required to reconstruct the original passphrase.
222 In the event of (enter condition here), you may meet with other secret-part holders to unite your keys.
223
224 To obtain the secret phassphrase:
225 <ol>
226         <li>collect at least %n secret shares</li>
227         <li>go to [url of this page]</li>
228         <li>enter the share number and the respective numbers separated by spaces</li>
229 </ol>
230 The passphrase obtained will give you access to [insert description of secured thing here...].
231
232 [More instructions]
233
234 Info: These secrets were generated using the "Shamir's Secret Sharing" algorithm.
235                 </textarea><br/>
236                 Passphrase parts to generate: <input id="shares" value="5" /></br>
237                 Minimum nuber of shares required to recreate secret: <input id="treshold" value="3" /></br>
238                 Secret: <input name="secret" onkeyup="secret2numbers(this.value);" />
239                 <table id="tab"></table>
240                 <ol>
241                 <li>Set the explanation you want.</li>
242                 <li>Enter the number of parts and shares you wish.</li>
243                 <li>Enter your secret passphrase</li>
244                 <li>Hit Ctrl+P or go to print via the menu</li>
245                 </ol>
246         </fieldset>
247         <div id="pages"></div>
248 </body>
249 </html>