Files: c6ca6ea4a1433067774515ee3b8b5250962fb050 / index.js
3844 bytesRaw
1 | var deepEqual = require('deep-equal') |
2 | |
3 | var sodium = require('chloride') |
4 | var ssbref = require('ssb-ref') |
5 | |
6 | var pb = require('private-box') |
7 | |
8 | var u = require('./util') |
9 | |
10 | var isBuffer = Buffer.isBuffer |
11 | |
12 | function isString (s) { |
13 | return 'string' === typeof s |
14 | } |
15 | //UTILS |
16 | |
17 | function clone (obj) { |
18 | var _obj = {} |
19 | for(var k in obj) { |
20 | if(Object.hasOwnProperty.call(obj, k)) |
21 | _obj[k] = obj[k] |
22 | } |
23 | return _obj |
24 | } |
25 | |
26 | var isLink = ssbref.isLink |
27 | var isFeedId = ssbref.isFeedId |
28 | |
29 | exports.hash = u.hash |
30 | |
31 | exports.getTag = u.getTag |
32 | |
33 | function isObject (o) { |
34 | return 'object' === typeof o |
35 | } |
36 | |
37 | function isFunction (f) { |
38 | return 'function' === typeof f |
39 | } |
40 | |
41 | function isString(s) { |
42 | return 'string' === typeof s |
43 | } |
44 | |
45 | var curves = {} |
46 | curves.ed25519 = require('./sodium') |
47 | try { curves.k256 = require('./eccjs') } |
48 | catch (_) {} |
49 | |
50 | function getCurve(keys) { |
51 | var curve = keys.curve |
52 | |
53 | if(!keys.curve && isString(keys.public)) |
54 | keys = keys.public |
55 | |
56 | if(!curve && isString(keys)) |
57 | curve = u.getTag(keys) |
58 | |
59 | if(!curves[curve]) { |
60 | throw new Error( |
61 | 'unkown curve:' + curve + |
62 | ' expected: '+Object.keys(curves) |
63 | ) |
64 | } |
65 | |
66 | return curve |
67 | } |
68 | |
69 | //this should return a key pair: |
70 | // {curve: curve, public: Buffer, private: Buffer} |
71 | |
72 | exports.generate = function (curve, seed) { |
73 | curve = curve || 'ed25519' |
74 | |
75 | if(!curves[curve]) |
76 | throw new Error('unknown curve:'+curve) |
77 | |
78 | return u.keysToJSON(curves[curve].generate(seed), curve) |
79 | } |
80 | |
81 | //import functions for loading/saving keys from storage |
82 | var storage = require('./storage')(exports.generate) |
83 | for(var key in storage) exports[key] = storage[key] |
84 | |
85 | |
86 | exports.loadOrCreate = function (filename, cb) { |
87 | exports.load(filename, function (err, keys) { |
88 | if(!err) return cb(null, keys) |
89 | exports.create(filename, cb) |
90 | }) |
91 | } |
92 | |
93 | exports.loadOrCreateSync = function (filename) { |
94 | try { |
95 | return exports.loadSync(filename) |
96 | } catch (err) { |
97 | return exports.createSync(filename) |
98 | } |
99 | } |
100 | |
101 | |
102 | //takes a public key and a hash and returns a signature. |
103 | //(a signature must be a node buffer) |
104 | |
105 | exports.sign = function (keys, msg) { |
106 | if(isString(msg)) |
107 | msg = new Buffer(msg) |
108 | if(!isBuffer(msg)) |
109 | throw new Error('msg should be buffer') |
110 | var curve = getCurve(keys) |
111 | |
112 | return curves[curve] |
113 | .sign(u.toBuffer(keys.private || keys), msg) |
114 | .toString('base64')+'.sig.'+curve |
115 | |
116 | } |
117 | |
118 | //takes a public key, signature, and a hash |
119 | //and returns true if the signature was valid. |
120 | exports.verify = function (keys, sig, msg) { |
121 | if(isObject(sig)) |
122 | throw new Error('signature should be base64 string, did you mean verifyObj(public, signed_obj)') |
123 | return curves[getCurve(keys)].verify( |
124 | u.toBuffer(keys.public || keys), |
125 | u.toBuffer(sig), |
126 | isBuffer(msg) ? msg : new Buffer(msg) |
127 | ) |
128 | } |
129 | |
130 | // OTHER CRYTPO FUNCTIONS |
131 | |
132 | exports.signObj = function (keys, obj) { |
133 | var _obj = clone(obj) |
134 | var b = new Buffer(JSON.stringify(_obj, null, 2)) |
135 | _obj.signature = exports.sign(keys, b) |
136 | return _obj |
137 | } |
138 | |
139 | exports.verifyObj = function (keys, obj) { |
140 | obj = clone(obj) |
141 | var sig = obj.signature |
142 | delete obj.signature |
143 | var b = new Buffer(JSON.stringify(obj, null, 2)) |
144 | return exports.verify(keys, sig, b) |
145 | } |
146 | |
147 | exports.box = function (msg, recipients) { |
148 | msg = new Buffer(JSON.stringify(msg)) |
149 | |
150 | recipients = recipients.map(function (keys) { |
151 | var public = keys.public || keys |
152 | return sodium.crypto_sign_ed25519_pk_to_curve25519(u.toBuffer(public)) |
153 | }) |
154 | |
155 | //it's since the nonce is 24 bytes (a multiple of 3) |
156 | //it's possible to concatenate the base64 strings |
157 | //and still have a valid base64 string. |
158 | return pb.multibox(msg, recipients).toString('base64')+'.box' |
159 | } |
160 | |
161 | exports.unbox = function (boxed, keys) { |
162 | boxed = u.toBuffer(boxed) |
163 | var sk = sodium.crypto_sign_ed25519_sk_to_curve25519(u.toBuffer(keys.private || keys)) |
164 | |
165 | var msg = pb.multibox_open(boxed, sk) |
166 | if(msg) return JSON.parse(''+msg) |
167 | } |
168 | |
169 | |
170 | |
171 | |
172 | |
173 |
Built with git-ssb-web