git ssb

1+

Dominic / ssb-keys



Tree: 9380a0ea407a45d5dc3c9720cb27c322b538739f

Files: 9380a0ea407a45d5dc3c9720cb27c322b538739f / index.js

4839 bytesRaw
1var deepEqual = require('deep-equal')
2
3var crypto = require('crypto')
4var createHmac = require('hmac')
5
6var sodium = require('chloride')
7var ssbref = require('ssb-ref')
8
9var pb = require('private-box')
10
11var u = require('./util')
12
13var isBuffer = Buffer.isBuffer
14
15function isString (s) {
16 return 'string' === typeof s
17}
18//UTILS
19
20
21function hasSigil (s) {
22 return /^(@|%|&)/.test(s)
23}
24
25function clone (obj) {
26 var _obj = {}
27 for(var k in obj) {
28 if(Object.hasOwnProperty.call(obj, k))
29 _obj[k] = obj[k]
30 }
31 return _obj
32}
33
34function hash (data, enc) {
35 data = (
36 'string' === typeof data && enc == null
37 ? new Buffer(data, 'binary')
38 : new Buffer(data, enc)
39 )
40 return crypto.createHash('sha256').update(data).digest('base64')+'.sha256'
41}
42
43var isLink = ssbref.isLink
44var isFeedId = ssbref.isFeedId
45
46exports.hash = hash
47
48function isObject (o) {
49 return 'object' === typeof o
50}
51
52function isFunction (f) {
53 return 'function' === typeof f
54}
55
56function isString(s) {
57 return 'string' === typeof s
58}
59
60//crazy hack to make electron not crash
61function base64ToBuffer(s) {
62 var l = s.length * 6 / 8
63 if(s[s.length - 2] == '=')
64 l = l - 2
65 else
66 if(s[s.length - 1] == '=')
67 l = l - 1
68
69 var b = new Buffer(l)
70 b.write(s, 'base64')
71 return b
72}
73
74function toBuffer(buf) {
75 if(buf == null) return buf
76 if(Buffer.isBuffer(buf)) throw new Error('already a buffer')
77 var i = buf.indexOf('.')
78 var start = (hasSigil(buf)) ? 1 : 0
79 return base64ToBuffer(buf.substring(start, ~i ? i : buf.length))
80}
81
82//function toUint8(buf) {
83// return new Uint8Array(toBuffer(buf))
84//}
85
86
87var curves = {}
88curves.ed25519 = require('./sodium')
89try { curves.k256 = require('./eccjs') }
90catch (_) {}
91
92function getCurve(keys) {
93 var curve = keys.curve
94
95 if(!keys.curve && isString(keys.public))
96 keys = keys.public
97
98 if(!curve && isString(keys))
99 curve = getTag(keys)
100
101 if(!curves[curve]) {
102 throw new Error(
103 'unkown curve:' + curve +
104 ' expected: '+Object.keys(curves)
105 )
106 }
107
108 return curve
109}
110
111//this should return a key pair:
112// {curve: curve, public: Buffer, private: Buffer}
113
114exports.generate = function (curve, seed) {
115 curve = curve || 'ed25519'
116
117 if(!curves[curve])
118 throw new Error('unknown curve:'+curve)
119
120 return u.keysToJSON(curves[curve].generate(seed), curve)
121}
122
123//import functions for loading/saving keys from storage
124var FS = require('./fs')(exports.generate)
125for(var key in FS) exports[key] = FS[key]
126
127
128exports.loadOrCreate = function (filename, cb) {
129 exports.load(filename, function (err, keys) {
130 if(!err) return cb(null, keys)
131 exports.create(filename, cb)
132 })
133}
134
135exports.loadOrCreateSync = function (namefile) {
136 try {
137 return exports.loadSync(filename)
138 } catch (err) {
139 return exports.createSync(filename)
140 }
141}
142
143
144//takes a public key and a hash and returns a signature.
145//(a signature must be a node buffer)
146
147exports.sign = function (keys, msg) {
148 if(isString(msg))
149 msg = new Buffer(msg)
150 if(!isBuffer(msg))
151 throw new Error('msg should be buffer')
152 var curve = getCurve(keys)
153
154 return curves[curve]
155 .sign(toBuffer(keys.private || keys), msg)
156 .toString('base64')+'.sig.'+curve
157
158}
159
160//takes a public key, signature, and a hash
161//and returns true if the signature was valid.
162exports.verify = function (keys, sig, msg) {
163 if(isObject(sig))
164 throw new Error('signature should be base64 string, did you mean verifyObj(public, signed_obj)')
165 return curves[getCurve(keys)].verify(
166 toBuffer(keys.public || keys),
167 toBuffer(sig),
168 isBuffer(msg) ? msg : new Buffer(msg)
169 )
170}
171
172// OTHER CRYTPO FUNCTIONS
173
174exports.hmac = function (data, key) {
175 return createHmac(createHash, 64, key)
176 .update(data).digest('base64')+'.sha256.hmac'
177}
178
179exports.signObj = function (keys, obj) {
180 var _obj = clone(obj)
181 var b = new Buffer(JSON.stringify(_obj, null, 2))
182 _obj.signature = exports.sign(keys, b)
183 return _obj
184}
185
186exports.verifyObj = function (keys, obj) {
187 obj = clone(obj)
188 var sig = obj.signature
189 delete obj.signature
190 var b = new Buffer(JSON.stringify(obj, null, 2))
191 return exports.verify(keys, sig, b)
192}
193
194exports.box = function (msg, recipients) {
195 msg = new Buffer(JSON.stringify(msg))
196
197 recipients = recipients.map(function (keys) {
198 var public = keys.public || keys
199 return sodium.crypto_sign_ed25519_pk_to_curve25519(toBuffer(public))
200 })
201
202 //it's since the nonce is 24 bytes (a multiple of 3)
203 //it's possible to concatenate the base64 strings
204 //and still have a valid base64 string.
205 return pb.multibox(msg, recipients).toString('base64')+'.box'
206}
207
208exports.unbox = function (boxed, keys) {
209 boxed = toBuffer(boxed)
210 var sk = sodium.crypto_sign_ed25519_sk_to_curve25519(toBuffer(keys.private || keys))
211
212 var msg = pb.multibox_open(boxed, sk)
213 if(msg) return JSON.parse(''+msg)
214}
215
216
217
218
219
220
221

Built with git-ssb-web