├── README.md
├── bower.json
├── test.html
├── webcrypto.min.js
└── webcrypto.js
/README.md:
--------------------------------------------------------------------------------
1 | # webcrypto.js
2 | Library to sign and verify signatures using RSA keys and the WebCrypto API.
3 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webcrypto.js",
3 | "version": "1.0.3",
4 | "homepage": "https://github.com/deiu/webcrypto.js",
5 | "authors": [
6 | "Andrei Sambra "
7 | ],
8 | "description": "Lightweight library to sign and verify signatures using RSA keys and the WebCrypto API",
9 | "main": "webcrypto.js",
10 | "moduleType": [
11 | "globals"
12 | ],
13 | "keywords": [
14 | "RSA",
15 | "cryptographic signatures",
16 | "cryptographic signature verification",
17 | "WebCrypto",
18 | "WebCrypto API"
19 | ],
20 | "license": "MIT",
21 | "ignore": [
22 | "**/.*",
23 | "node_modules",
24 | "bower_components",
25 | "test",
26 | "tests"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Test sign/verify using the WebCrypto API
6 |
7 |
8 |
9 |
10 |
11 |
12 | Signature:
13 |
14 |
15 |
16 | Signature verified using the generated (fresh) keys:
17 |
18 |
19 |
20 | Signature verified using the parsed public key:
21 |
22 |
23 |
24 | Private key (PEM):
25 |
26 |
27 |
28 | Public key (PEM):
29 |
30 |
31 |
32 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/webcrypto.min.js:
--------------------------------------------------------------------------------
1 | (function(root){if(typeof $webCrypto==='undefined'){var $webCrypto={}}else{return $webCrypto;throw"Internal error: WebCrypto libray has already been loaded: $webCrypto already exists"}var crypto=window.crypto||window.msCrypto;if(!crypto.subtle){return;throw"WebCrypto API support missing from browser."}$webCrypto.signAlgorithm={name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}}$webCrypto.generateRSAKey=function(){var alg={name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"},modulusLength:2048,extractable:true,publicExponent:new Uint8Array([1,0,1])};return new Promise(function(resolve){var genkey=crypto.subtle.generateKey(alg,true,["sign","verify"]);genkey.then(function(pair){resolve(pair)}).catch(function(e){console.log(e);resolve(null)})})}$webCrypto.arrayBufferToBase64String=function(arrayBuffer){var byteArray=new Uint8Array(arrayBuffer)var byteString='';for(var i=0;i0&&lines[i].indexOf('-BEGIN RSA PRIVATE KEY-')<0&&lines[i].indexOf('-BEGIN RSA PUBLIC KEY-')<0&&lines[i].indexOf('-END RSA PRIVATE KEY-')<0&&lines[i].indexOf('-END RSA PUBLIC KEY-')<0){encoded+=lines[i].trim()}}return $webCrypto.base64StringToArrayBuffer(encoded)};$webCrypto.importPublicKey=function(pemKey,format){if(!format){format='spki'}return new Promise(function(resolve){var importer=crypto.subtle.importKey(format,$webCrypto.convertPemToBinary(pemKey),$webCrypto.signAlgorithm,true,["verify"]);importer.then(function(key){resolve({value:key,error:null})}).catch(function(e){console.log(e);resolve({value:null,error:e})})})};$webCrypto.importPrivateKey=function(pemKey,format){if(!format){format='pkcs8'}return new Promise(function(resolve){var importer=crypto.subtle.importKey(format,$webCrypto.convertPemToBinary(pemKey),$webCrypto.signAlgorithm,false,["sign"]);importer.then(function(key){if(!key||key.length===0){console.log("Problem parsing key..empty result")}resolve({value:key,error:null})}).catch(function(e){console.log(e);resolve({value:null,error:e})})})};$webCrypto.exportPublicKey=function(keys,format){if(!format){format='spki'}return new Promise(function(resolve){window.crypto.subtle.exportKey(format,keys.publicKey).then(function(key){resolve($webCrypto.convertBinaryToPem(key,"RSA PUBLIC KEY"))}).catch(function(e){console.log(e);resolve(null)})})};$webCrypto.exportPrivateKey=function(keys,format){if(!format){format='pkcs8'}return new Promise(function(resolve){var expK=window.crypto.subtle.exportKey(format,keys.privateKey);expK.then(function(key){resolve($webCrypto.convertBinaryToPem(key,"RSA PRIVATE KEY"))}).catch(function(e){console.log(e);resolve(null)})})};$webCrypto.exportPemKeys=function(keys){return new Promise(function(resolve){$webCrypto.exportPublicKey(keys).then(function(pubKey){$webCrypto.exportPrivateKey(keys).then(function(privKey){resolve({publicKey:pubKey,privateKey:privKey})}).catch(function(e){console.log(e);resolve(null)})}).catch(function(e){console.log(e);resolve(null)})})};$webCrypto.signData=function(key,data){var buffer=$webCrypto.textToArrayBuffer(data);return window.crypto.subtle.sign($webCrypto.signAlgorithm,key,buffer)};$webCrypto.verifySig=function(pub,sig,data){data=$webCrypto.textToArrayBuffer(data);return crypto.subtle.verify($webCrypto.signAlgorithm,pub,sig,data)};if(typeof exports!=='undefined'){if(typeof module!=='undefined'&&module.exports){exports=module.exports=$webCrypto}exports.$webCrypto=$webCrypto}else{if(typeof define==='function'&&define.amd){define([],function(){return $webCrypto})}root['$webCrypto']=$webCrypto}})(this);
--------------------------------------------------------------------------------
/webcrypto.js:
--------------------------------------------------------------------------------
1 | (function(root) {
2 | if( typeof $webCrypto === 'undefined' ) {
3 | var $webCrypto = {};
4 | } else {
5 | return $webCrypto;
6 | throw "Internal error: WebCrypto libray has already been loaded: $webCrypto already exists";
7 | }
8 |
9 | var crypto = window.crypto || window.msCrypto;
10 | if (!crypto.subtle) {
11 | return;
12 | throw "WebCrypto API support missing from browser.";
13 | }
14 |
15 | $webCrypto.signAlgorithm = {
16 | name: "RSASSA-PKCS1-v1_5",
17 | hash: {
18 | name: "SHA-256"
19 | }
20 | }
21 |
22 | $webCrypto.generateRSAKey = function() {
23 | var alg = {
24 | name: "RSASSA-PKCS1-v1_5",
25 | hash: {name: "SHA-256"},
26 | modulusLength: 2048,
27 | extractable: true,
28 | publicExponent: new Uint8Array([1, 0, 1])
29 | };
30 |
31 | return new Promise(function(resolve) {
32 | var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
33 | genkey.then(function (pair) {
34 | resolve(pair);
35 | }).catch(function(e) {
36 | console.log(e);
37 | resolve(null);
38 | });
39 | });
40 | }
41 |
42 | $webCrypto.arrayBufferToBase64String = function(arrayBuffer) {
43 | var byteArray = new Uint8Array(arrayBuffer)
44 | var byteString = '';
45 | for (var i=0; i 0 &&
95 | lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
96 | lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
97 | lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
98 | lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
99 | encoded += lines[i].trim();
100 | }
101 | }
102 | return $webCrypto.base64StringToArrayBuffer(encoded);
103 | };
104 |
105 | $webCrypto.importPublicKey = function(pemKey, format) {
106 | if (!format) {
107 | format = 'spki';
108 | }
109 | return new Promise(function(resolve) {
110 | var importer = crypto.subtle.importKey(format, $webCrypto.convertPemToBinary(pemKey), $webCrypto.signAlgorithm, true, ["verify"]);
111 | importer.then(function(key) {
112 | resolve({value: key, error: null});
113 | }).catch(function(e) {
114 | console.log(e);
115 | resolve({value: null, error: e});
116 | });
117 | });
118 | };
119 |
120 | $webCrypto.importPrivateKey = function(pemKey, format) {
121 | if (!format) {
122 | format = 'pkcs8';
123 | }
124 | return new Promise(function(resolve) {
125 | var importer = crypto.subtle.importKey(format, $webCrypto.convertPemToBinary(pemKey), $webCrypto.signAlgorithm, false, ["sign"]);
126 | importer.then(function(key) {
127 | if (!key || key.length === 0) {
128 | console.log("Problem parsing key..empty result");
129 | }
130 | resolve({value: key, error: null});
131 | }).catch(function(e) {
132 | console.log(e);
133 | resolve({value: null, error: e});
134 | });
135 | });
136 | };
137 |
138 | $webCrypto.exportPublicKey = function(keys, format) {
139 | if (!format) {
140 | format = 'spki';
141 | }
142 | return new Promise(function(resolve) {
143 | window.crypto.subtle.exportKey(format, keys.publicKey).
144 | then(function(key) {
145 | resolve($webCrypto.convertBinaryToPem(key, "RSA PUBLIC KEY"));
146 | }).catch(function(e) {
147 | console.log(e);
148 | resolve(null);
149 | });
150 | });
151 | };
152 |
153 | $webCrypto.exportPrivateKey = function(keys, format) {
154 | if (!format) {
155 | format = 'pkcs8';
156 | }
157 | return new Promise(function(resolve) {
158 | var expK = window.crypto.subtle.exportKey(format, keys.privateKey);
159 | expK.then(function(key) {
160 | resolve($webCrypto.convertBinaryToPem(key, "RSA PRIVATE KEY"));
161 | }).catch(function(e) {
162 | console.log(e);
163 | resolve(null);
164 | });
165 | });
166 | };
167 |
168 | $webCrypto.exportPemKeys = function(keys) {
169 | return new Promise(function(resolve) {
170 | $webCrypto.exportPublicKey(keys).then(function(pubKey) {
171 | $webCrypto.exportPrivateKey(keys).then(function(privKey) {
172 | resolve({publicKey: pubKey, privateKey: privKey});
173 | }).catch(function(e) {
174 | console.log(e);
175 | resolve(null);
176 | });
177 | }).catch(function(e) {
178 | console.log(e);
179 | resolve(null);
180 | });
181 | });
182 | };
183 |
184 | $webCrypto.signData = function(key, data) {
185 | var buffer = $webCrypto.textToArrayBuffer(data);
186 | return window.crypto.subtle.sign($webCrypto.signAlgorithm, key, buffer);
187 | };
188 |
189 | $webCrypto.verifySig = function(pub, sig, data) {
190 | data = $webCrypto.textToArrayBuffer(data);
191 | return crypto.subtle.verify($webCrypto.signAlgorithm, pub, sig, data);
192 | };
193 |
194 | // Handle node, amd, and global systems
195 | if (typeof exports !== 'undefined') {
196 | if (typeof module !== 'undefined' && module.exports) {
197 | exports = module.exports = $webCrypto;
198 | }
199 | exports.$webCrypto = $webCrypto;
200 | } else {
201 | if (typeof define === 'function' && define.amd) {
202 | define([], function() {
203 | return $webCrypto;
204 | });
205 | }
206 |
207 | // Leak a global regardless of module system
208 | root['$webCrypto'] = $webCrypto;
209 | }
210 | })(this);
--------------------------------------------------------------------------------