UNPKG

3.64 kBJavaScriptView Raw
1'use strict'
2var sodium = require('chloride')
3
4var pb = require('private-box')
5
6var u = require('./util')
7
8var isBuffer = Buffer.isBuffer
9
10//UTILS
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
21var hmac = sodium.crypto_auth
22
23exports.hash = u.hash
24
25exports.getTag = u.getTag
26
27function isObject (o) {
28 return 'object' === typeof o
29}
30
31function isFunction (f) {
32 return 'function' === typeof f
33}
34
35function isString(s) {
36 return 'string' === typeof s
37}
38
39var curves = {}
40curves.ed25519 = require('./sodium')
41
42function 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//this should return a key pair:
62// {curve: curve, public: Buffer, private: Buffer}
63
64exports.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//import functions for loading/saving keys from storage
74var storage = require('./storage')(exports.generate)
75for(var key in storage) exports[key] = storage[key]
76
77
78exports.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
85exports.loadOrCreateSync = function (filename) {
86 try {
87 return exports.loadSync(filename)
88 } catch (err) {
89 return exports.createSync(filename)
90 }
91}
92
93
94//takes a public key and a hash and returns a signature.
95//(a signature must be a node buffer)
96
97function 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//takes a public key, signature, and a hash
111//and returns true if the signature was valid.
112function 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// OTHER CRYTPO FUNCTIONS
123
124exports.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
133exports.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
143exports.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
153exports.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