git ssb

1+

Dominic / ssb-keys



Tree: dbfcdc3e700706a37cf8e462ae1d1560d58ac44f

Files: dbfcdc3e700706a37cf8e462ae1d1560d58ac44f / index.js

5676 bytesRaw
1var fs = require('fs')
2var crypto = require('crypto')
3var ecc = require('eccjs')
4var k256 = ecc.curves.k256
5var Blake2s = require('blake2s')
6var mkdirp = require('mkdirp')
7var path = require('path')
8var curve = ecc.curves.k256
9var createHmac = require('hmac')
10var deepEqual = require('deep-equal')
11
12function clone (obj) {
13 var _obj = {}
14 for(var k in obj) {
15 if(Object.hasOwnProperty.call(obj, k))
16 _obj[k] = obj[k]
17 }
18 return _obj
19}
20
21function hash (data, enc) {
22 return new Blake2s().update(data, enc).digest('base64') + '.blake2s'
23}
24
25
26function isHash (data) {
27 return isString(data) && /^[A-Za-z0-9\/+]{43}=\.blake2s$/.test(data)
28}
29
30function isObject (o) {
31 return 'object' === typeof o
32}
33
34exports.isHash = isHash
35exports.hash = hash
36
37function isString(s) {
38 return 'string' === typeof s
39}
40
41function empty(v) { return !!v }
42
43function constructKeys() {
44 var privateKey = crypto.randomBytes(32)
45 var k = keysToBase64(ecc.restore(k256, privateKey))
46 k.keyfile = [
47 '# this is your SECRET name.',
48 '# this name gives you magical powers.',
49 '# with it you can mark your messages so that your friends can verify',
50 '# that they really did come from you.',
51 '#',
52 '# if any one learns this name, they can use it to destroy your identity',
53 '# NEVER show this to anyone!!!',
54 '',
55 k.private.toString('hex'),
56 '',
57 '# WARNING! It\'s vital that you DO NOT edit OR share your secret name',
58 '# instead, share your public name',
59 '# your public name: ' + k.id.toString('hex')
60 ].join('\n')
61 return k
62}
63
64
65function toBuffer(buf) {
66 if(buf == null) return buf
67 return new Buffer(buf.substring(0, buf.indexOf('.')), 'base64')
68}
69
70function keysToBase64 (keys) {
71 var pub = tag(keys.public, 'k256')
72 return {
73 public: pub,
74 private: tag(keys.private, 'k256'),
75 id: hash(pub)
76 }
77}
78
79function hashToBuffer(hash) {
80 if(!isHash(hash)) throw new Error('sign expects a hash')
81 return toBuffer(hash)
82}
83
84function keysToBuffer(key) {
85 return isString(key) ? toBuffer(key) : {
86 public: toBuffer(key.public),
87 private: toBuffer(key.private)
88 }
89}
90
91function reconstructKeys(privateKeyStr) {
92 privateKeyStr = privateKeyStr
93 .replace(/\s*\#[^\n]*/g, '')
94 .split('\n').filter(empty).join('')
95
96 var privateKey = (
97 !/\./.test(privateKeyStr)
98 ? new Buffer(privateKeyStr, 'hex')
99 : toBuffer(privateKeyStr)
100 )
101
102 return keysToBase64(ecc.restore(k256, privateKey))
103}
104
105function tag (key, tag) {
106 return key.toString('base64')+'.' + tag.replace(/^\./, '')
107}
108
109var toNameFile = exports.toNameFile = function (namefile) {
110 if(isObject(namefile))
111 return path.join(namefile.path, 'secret')
112 return namefile
113}
114
115exports.load = function(namefile, cb) {
116 namefile = toNameFile(namefile)
117 fs.readFile(namefile, 'ascii', function(err, privateKeyStr) {
118 if (err) return cb(err)
119 try { cb(null, reconstructKeys(privateKeyStr)) }
120 catch (e) { cb(err) }
121 })
122}
123
124exports.loadSync = function(namefile) {
125 namefile = toNameFile(namefile)
126 return reconstructKeys(fs.readFileSync(namefile, 'ascii'))
127}
128
129exports.create = function(namefile, cb) {
130 namefile = toNameFile(namefile)
131 var k = constructKeys()
132 mkdirp(path.dirname(namefile), function (err) {
133 if(err) return cb(err)
134 fs.writeFile(namefile, k.keyfile, function(err) {
135 if (err) return cb(err)
136 delete k.keyfile
137 cb(null, k)
138 })
139 })
140}
141
142exports.createSync = function(namefile) {
143 namefile = toNameFile(namefile)
144 var k = constructKeys()
145 mkdirp.sync(path.dirname(namefile))
146 fs.writeFileSync(namefile, k.keyfile)
147 delete k.keyfile
148 return k
149}
150
151exports.loadOrCreate = function (namefile, cb) {
152 namefile = toNameFile(namefile)
153 exports.load(namefile, function (err, keys) {
154 if(!err) return cb(null, keys)
155 exports.create(namefile, cb)
156 })
157}
158exports.loadOrCreateSync = function (namefile) {
159 namefile = toNameFile(namefile)
160 try {
161 return exports.loadSync(namefile)
162 } catch (err) {
163 return exports.createSync(namefile)
164 }
165}
166
167//this should return a key pair:
168// {public: Buffer, private: Buffer}
169
170exports.generate = function () {
171 return keysToBase64(ecc.restore(curve, crypto.randomBytes(32)))
172}
173
174//takes a public key and a hash and returns a signature.
175//(a signature must be a node buffer)
176exports.sign = function (keys, hash) {
177 var hashTag = hash.substring(hash.indexOf('.'))
178 return tag(
179 ecc.sign(curve, keysToBuffer(keys), hashToBuffer(hash)),
180 hashTag + '.k256'
181 )
182}
183
184//takes a public key, signature, and a hash
185//and returns true if the signature was valid.
186exports.verify = function (pub, sig, hash) {
187 return ecc.verify(curve, keysToBuffer(pub), toBuffer(sig), hashToBuffer(hash))
188}
189
190function createHash() {
191 return new Blake2s()
192}
193
194exports.hmac = function (data, key) {
195 return createHmac(createHash, 64, key)
196 .update(data).digest('base64')+'.blake2s.hmac'
197}
198
199exports.signObj = function (keys, obj) {
200 var _obj = clone(obj)
201 var str = JSON.stringify(_obj, null, 2)
202 var h = hash(str, 'utf8')
203 _obj.signature = exports.sign(keys, h)
204 return _obj
205}
206
207exports.verifyObj = function (keys, obj) {
208 obj = clone(obj)
209 var sig = obj.signature
210 delete obj.signature
211 var str = JSON.stringify(obj, null, 2)
212 var h = hash(str, 'utf8')
213 return exports.verify(keys, sig, h)
214}
215
216exports.signObjHmac = function (secret, obj) {
217 obj = clone(obj)
218 var str = JSON.stringify(obj, null, 2)
219 obj.hmac = exports.hmac(str, secret)
220 return obj
221}
222
223exports.verifyObjHmac = function (secret, obj) {
224 obj = clone(obj)
225 var hmac = obj.hmac
226 delete obj.hmac
227 var str = JSON.stringify(obj, null, 2)
228 var _hmac = exports.hmac(str, secret)
229 return deepEqual(hmac, _hmac)
230}
231

Built with git-ssb-web