-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebcrypto
More file actions
228 lines (157 loc) · 8.62 KB
/
webcrypto
File metadata and controls
228 lines (157 loc) · 8.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
function webcrypto(){
var obj = {};
var pretty = {};
var rsa = {};
obj.encrypt=async function(public,message){
var buf = txt_buf(message);
var iv = window.crypto.getRandomValues(new Uint8Array(16));
var key = window.crypto.getRandomValues(new Uint8Array(16));
var encoded = await window.crypto.subtle.importKey('raw',key.buffer,'AES-CTR',false,['encrypt','decrypt']);
var encrypted = await window.crypto.subtle.encrypt({name:'AES-CTR',counter:iv,length:64},encoded,buf);
var data_b64 = buf_b64(encrypted);
var buf = new Uint8Array(32);
buf.set(iv,0);
buf.set(key,16);
var hdr_b64 = await rsa.encrypt(public,buf);
var blob = hdr_b64+'.'+data_b64;
return blob;
}//encrypt
obj.decrypt=async function(private,blob){
var i = blob.indexOf('.');
var hdr_b64 = blob.slice(0,i);
var data_b64 = blob.slice(i+1);
var buf = await rsa.decrypt(private,hdr_b64);
var iv = buf.slice(0,16);
var key = buf.slice(16);
var encoded = await window.crypto.subtle.importKey('raw',key,'AES-CTR',false,['encrypt','decrypt']);
var buf = b64_buf(data_b64);
var decrypted = await window.crypto.subtle.decrypt({name:'AES-CTR',counter:iv,length:64},encoded,buf);
var txt = buf_txt(decrypted);
return txt;
}//decrypt
//:
obj.keypair=async function(){
var params = {name:'RSA-OAEP',modulusLength:1024,publicExponent:new Uint8Array([1,0,1]),hash:'SHA-256'};
var keys = await window.crypto.subtle.generateKey(params,true,['encrypt','decrypt']);
return keys;
}//keypair
rsa.encrypt=async function(public,buf){
var encrypted = await window.crypto.subtle.encrypt({name:'RSA-OAEP'},public,buf);
var b64 = buf_b64(encrypted);
return b64;
}//encrpyt
rsa.decrypt=async function(private,b64){
var buf = b64_buf(b64);
var decrypted = await window.crypto.subtle.decrypt({name:'RSA-OAEP'},private,buf);
return decrypted;
}//decrypt
obj.export=async function(type,key){
var format = type=='public' ? 'spki' : 'pkcs8';
var buf = await window.crypto.subtle.exportKey(format,key);
var b64 = buf_b64(buf);
var pem = hdr(type)+b64+ftr(type);
var txt = pretty.out(pem);
return txt;
}//export
obj.export.public = public=>obj.export('public',public);
obj.export.private = private=>obj.export('private',private);
obj.import=async function(type,txt){
var pem = pretty.in(txt);
var {b64} = extract(pem);
var buf = b64_buf(b64);
var params = {name:'RSA-OAEP',hash:'SHA-256'};
var format = type=='public' ? 'spki' : 'pkcs8';
var mode = type=='public' ? 'encrypt' : 'decrypt';
var public = await window.crypto.subtle.importKey(format,buf,params,true,[mode]);
return public;
}//import
obj.import.public = public_pem=>obj.import('public',public_pem);
obj.import.private = private_pem=>obj.import('private',private_pem);
//:
var hdr = (type='public')=>`-----BEGIN ${type.toUpperCase()} KEY-----`;
var ftr = (type='public')=>`-----END ${type.toUpperCase()} KEY-----`;
function extract(pem){
var i1 = pem.indexOf('KEY')+8;
var i2 = pem.lastIndexOf('END')-5;
var hdr = pem.slice(0,i1);
var b64 = pem.substring(i1,i2);
var ftr = pem.slice(i2);
return {hdr,b64,ftr};
}//extract
pretty.out=function(pem){
var {hdr,b64,ftr} = extract(pem);
var txt = hdr+'\n';
var n = hdr.length;
var i = 0;
while(i<b64.length){
var str = b64.slice(i,i+n);
txt += str.padEnd(n)+'\n';
i += n;
}//while
txt += ftr;
return txt;
}//pretty.out
pretty.in=function(txt){
txt = txt.trim();
var arr = txt.split('\n');
var hdr = arr.shift();
var ftr = arr.pop();
var b64 = arr.join('').trim();
var pem = hdr+b64+ftr;
return pem;
}//pretty.in
//:
obj.txt_buf=function(txt){return txt_buf(txt)}
function txt_buf(txt){
var buf = new TextEncoder().encode(txt);
return buf;
}//txt_buf
obj.buf_txt=function(buf){return buf_txt(buf)}
function buf_txt(buf){
var txt = new TextDecoder().decode(buf);
return txt;
}//buf_txt
obj.buf_b64=function(buf){return buf_b64(buf)}
function buf_b64(buf){
var bytes = new Uint8Array(buf);
var bin = bytes.reduce((acc,byte)=>acc+=String.fromCharCode(byte),'');
var b64 = btoa(bin);
return b64;
}//buf_b64
obj.b64_buf=function(b64){return b64_buf(b64)}
function b64_buf(b64){
var bin = atob(b64);
var bytes = [...bin].map(c=>c.charCodeAt(0));
var buf = new Uint8Array(bytes);
return buf;
}//b64_buf
//:
obj.help=function(){
var txt = `
alice wants to send bob a secure message
bob generates a keypair and sends alice the public key
alice encrypts the message and sends bob the result
bob uses the private key to decrypt what alice sends
(async()=>{
console.clear();
webcrypto = webcrypto();
var keys = await webcrypto.keypair();
var public = await webcrypto.export.public(keys.publicKey);
console.log(public);
var private = await webcrypto.export.private(keys.privateKey);
console.log(private);
var message = 'helloworld';
console.log(message);
public = await webcrypto.import.public(public);
var blob = await webcrypto.encrypt(public,message);
console.log(blob);
private = await webcrypto.import.private(private);
var message = await webcrypto.decrypt(private,blob);
console.log(message);
})();
`;
return txt;
}//help
return obj;
//webcrypto
}