1 | 'use strict'
|
2 | var sodium = require('chloride')
|
3 |
|
4 | var pb = require('private-box')
|
5 |
|
6 | var u = require('./util')
|
7 |
|
8 | var isBuffer = Buffer.isBuffer
|
9 |
|
10 |
|
11 |
|
12 | function 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 |
|
21 | var hmac = sodium.crypto_auth
|
22 |
|
23 | exports.hash = u.hash
|
24 |
|
25 | exports.getTag = u.getTag
|
26 |
|
27 | function isObject (o) {
|
28 | return 'object' === typeof o
|
29 | }
|
30 |
|
31 | function isFunction (f) {
|
32 | return 'function' === typeof f
|
33 | }
|
34 |
|
35 | function isString(s) {
|
36 | return 'string' === typeof s
|
37 | }
|
38 |
|
39 | var curves = {}
|
40 | curves.ed25519 = require('./sodium')
|
41 |
|
42 | function getCurve(keys) {
|
43 | var curve = keys.curve
|
44 |
|
45 | if(!keys.curve && isString(keys.public))
|
46 | keys = keys.public
|
47 |
|
48 | if(!curve && isString(keys))
|
49 | curve = u.getTag(keys)
|
50 |
|
51 | if(!curves[curve]) {
|
52 | throw new Error(
|
53 | 'unkown curve:' + curve +
|
54 | ' expected: '+Object.keys(curves)
|
55 | )
|
56 | }
|
57 |
|
58 | return curve
|
59 | }
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | exports.generate = function (curve, seed) {
|
65 | curve = curve || 'ed25519'
|
66 |
|
67 | if(!curves[curve])
|
68 | throw new Error('unknown curve:'+curve)
|
69 |
|
70 | return u.keysToJSON(curves[curve].generate(seed), curve)
|
71 | }
|
72 |
|
73 |
|
74 | var storage = require('./storage')(exports.generate)
|
75 | for(var key in storage) exports[key] = storage[key]
|
76 |
|
77 |
|
78 | exports.loadOrCreate = function (filename, cb) {
|
79 | exports.load(filename, function (err, keys) {
|
80 | if(!err) return cb(null, keys)
|
81 | exports.create(filename, cb)
|
82 | })
|
83 | }
|
84 |
|
85 | exports.loadOrCreateSync = function (filename) {
|
86 | try {
|
87 | return exports.loadSync(filename)
|
88 | } catch (err) {
|
89 | return exports.createSync(filename)
|
90 | }
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | function sign (keys, msg) {
|
98 | if(isString(msg))
|
99 | msg = new Buffer(msg)
|
100 | if(!isBuffer(msg))
|
101 | throw new Error('msg should be buffer')
|
102 | var curve = getCurve(keys)
|
103 |
|
104 | return curves[curve]
|
105 | .sign(u.toBuffer(keys.private || keys), msg)
|
106 | .toString('base64')+'.sig.'+curve
|
107 |
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 | function verify (keys, sig, msg) {
|
113 | if(isObject(sig))
|
114 | throw new Error('signature should be base64 string, did you mean verifyObj(public, signed_obj)')
|
115 | return curves[getCurve(keys)].verify(
|
116 | u.toBuffer(keys.public || keys),
|
117 | u.toBuffer(sig),
|
118 | isBuffer(msg) ? msg : new Buffer(msg)
|
119 | )
|
120 | }
|
121 |
|
122 |
|
123 |
|
124 | exports.signObj = function (keys, hmac_key, obj) {
|
125 | if(!obj) obj = hmac_key, hmac_key = null
|
126 | var _obj = clone(obj)
|
127 | var b = new Buffer(JSON.stringify(_obj, null, 2))
|
128 | if(hmac_key) b = hmac(b, hmac_key)
|
129 | _obj.signature = sign(keys, b)
|
130 | return _obj
|
131 | }
|
132 |
|
133 | exports.verifyObj = function (keys, hmac_key, obj) {
|
134 | if(!obj) obj = hmac_key, hmac_key = null
|
135 | obj = clone(obj)
|
136 | var sig = obj.signature
|
137 | delete obj.signature
|
138 | var b = new Buffer(JSON.stringify(obj, null, 2))
|
139 | if(hmac_key) b = hmac(b, hmac_key)
|
140 | return verify(keys, sig, b)
|
141 | }
|
142 |
|
143 | exports.box = function (msg, recipients) {
|
144 | msg = new Buffer(JSON.stringify(msg))
|
145 |
|
146 | recipients = recipients.map(function (keys) {
|
147 | return sodium.crypto_sign_ed25519_pk_to_curve25519(u.toBuffer(keys.public || keys))
|
148 | })
|
149 |
|
150 | return pb.multibox(msg, recipients).toString('base64')+'.box'
|
151 | }
|
152 |
|
153 | exports.unbox = function (boxed, keys) {
|
154 | boxed = u.toBuffer(boxed)
|
155 | var sk = sodium.crypto_sign_ed25519_sk_to_curve25519(u.toBuffer(keys.private || keys))
|
156 |
|
157 | var msg = pb.multibox_open(boxed, sk)
|
158 | try {
|
159 | return JSON.parse(''+msg)
|
160 | } catch (_) { }
|
161 | return
|
162 | }
|
163 |
|
164 |
|