Browse Source

remove prototype constructor, causing issues...

Kieran Gibb 2 years ago
parent
commit
8df8a95d3d
No known key found for this signature in database
2 changed files with 177 additions and 180 deletions
  1. 174
    177
      index.js
  2. 3
    3
      test/index.test.js

+ 174
- 177
index.js View File

@@ -5,208 +5,205 @@ const bip39 = require('bip39')
5 5
 const encoder = require('crypto-encoder')
6 6
 const zero = sodium.sodium_memzero
7 7
 
8
-class Crypto {
9
-  constructor () {
10
-    this.PACKEDLENGTH = sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_secretbox_KEYBYTES
11
-  }
12
-
13
-  randomBytes (length) {
14
-    return crypto.randomBytes(length)
15
-  }
16
-
17
-  masterKey () {
18
-    const key = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
19
-    sodium.crypto_kdf_keygen(key)
20
-    return key
21
-  }
8
+const PACKEDLENGTH = sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_secretbox_KEYBYTES
9
+
10
+module.exports = {
11
+  PACKEDLENGTH,
12
+  randomBytes,
13
+  address,
14
+  encryptionKey,
15
+  masterKey,
16
+  keyPair,
17
+  keySet,
18
+  accessKey,
19
+  pack,
20
+  unpack,
21
+  isKey,
22
+  toBuffer,
23
+  keyToMnemonic: bip39.entropyToMnemonic,
24
+  mnemonicToKey,
25
+  encoder,
26
+  deriveBoxKeyPair,
27
+  boxKeyPair,
28
+  box,
29
+  unbox,
30
+  genericHash,
31
+  scalarMult
32
+}
22 33
 
23
-  address () {
24
-    return this.randomBytes(sodium.crypto_secretbox_KEYBYTES)
25
-  }
34
+function randomBytes (length) {
35
+  return crypto.randomBytes(length)
36
+}
26 37
 
27
-  encryptionKey (encryptionKey) {
28
-    if (!encryptionKey) return encoder.encryptionKey()
29
-    var key = sodium.sodium_malloc(sodium.crypto_secretbox_KEYBYTES)
38
+function masterKey () {
39
+  const key = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
40
+  sodium.crypto_kdf_keygen(key)
41
+  return key
42
+}
30 43
 
31
-    if (encryptionKey && Buffer.isBuffer(encryptionKey) && !encryptionKey.secure) {
32
-      key.write(encryptionKey.toString('hex'), 'hex')
33
-      zero(encryptionKey)
34
-    } else if (encryptionKey && Buffer.isBuffer(encryptionKey) && encryptionKey.secure) {
35
-      return encryptionKey
36
-    } else if (encryptionKey && typeof encryptionKey === 'string') {
37
-      key.write(encryptionKey, 'hex')
38
-    } else return encoder.encryptionKey()
44
+function address () {
45
+  return randomBytes(sodium.crypto_secretbox_KEYBYTES)
46
+}
39 47
 
40
-    return key
41
-  }
48
+function encryptionKey (encryptionKey) {
49
+  if (!encryptionKey) return encoder.encryptionKey()
50
+  var key = sodium.sodium_malloc(sodium.crypto_secretbox_KEYBYTES)
42 51
 
43
-  _deriveSeed (masterKey, id, ctxt = 'coboxcobox') {
44
-    const context = sodium.sodium_malloc(sodium.crypto_hash_sha256_BYTES)
45
-    sodium.crypto_hash_sha256(context, Buffer.from(ctxt))
46
-    const seed = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
52
+  if (encryptionKey && Buffer.isBuffer(encryptionKey) && !encryptionKey.secure) {
53
+    key.write(encryptionKey.toString('hex'), 'hex')
54
+    zero(encryptionKey)
55
+  } else if (encryptionKey && Buffer.isBuffer(encryptionKey) && encryptionKey.secure) {
56
+    return encryptionKey
57
+  } else if (encryptionKey && typeof encryptionKey === 'string') {
58
+    key.write(encryptionKey, 'hex')
59
+  } else return encoder.encryptionKey()
47 60
 
48
-    sodium.crypto_kdf_derive_from_key(seed, id, context, masterKey)
49
-    zero(context)
50
-    return seed
51
-  }
61
+  return key
62
+}
52 63
 
53
-  keyPair (masterKey, id, ctxt = 'coboxcobox') {
54
-    return crypto.keyPair(this._deriveSeed(masterKey, id, ctxt))
55
-  }
64
+function deriveSeed (masterKey, id, ctxt = 'coboxcobox') {
65
+  const context = sodium.sodium_malloc(sodium.crypto_hash_sha256_BYTES)
66
+  sodium.crypto_hash_sha256(context, Buffer.from(ctxt))
67
+  const seed = sodium.sodium_malloc(sodium.crypto_kdf_KEYBYTES)
56 68
 
57
-  keySet () {
58
-    return {
59
-      address: this.address(),
60
-      encryptionKey: this.encryptionKey()
61
-    }
62
-  }
69
+  sodium.crypto_kdf_derive_from_key(seed, id, context, masterKey)
70
+  zero(context)
71
+  return seed
72
+}
63 73
 
64
-  accessKey () {
65
-    return this.pack(this.randomBytes(sodium.crypto_secretbox_KEYBYTES), this.encryptionKey())
66
-  }
74
+function keyPair (masterKey, id, ctxt = 'coboxcobox') {
75
+  return crypto.keyPair(deriveSeed(masterKey, id, ctxt))
76
+}
67 77
 
68
-  pack (address, encryptionKey) {
69
-    address = this.toBuffer(address, sodium.crypto_sign_PUBLICKEYBYTES)
70
-    encryptionKey = this.toBuffer(encryptionKey, sodium.crypto_secretbox_KEYBYTES)
71
-    const accessKey = sodium.sodium_malloc(this.PACKEDLENGTH)
72
-    address.copy(accessKey)
73
-    encryptionKey.copy(accessKey, sodium.crypto_secretbox_KEYBYTES)
74
-    return accessKey
78
+function keySet () {
79
+  return {
80
+    address: address(),
81
+    encryptionKey: encryptionKey()
75 82
   }
83
+}
76 84
 
77
-  unpack (key) {
78
-    key = this.toBuffer(key, [sodium.crypto_sign_PUBLICKEYBYTES, this.PACKEDLENGTH])
79
-
80
-    if (key.length === sodium.crypto_sign_PUBLICKEYBYTES) return { address: key }
81
-
82
-    const address = key.slice(0, sodium.crypto_sign_PUBLICKEYBYTES)
83
-    const encryptionKey = key.slice(sodium.crypto_secretbox_KEYBYTES)
85
+function accessKey () {
86
+  return pack(randomBytes(sodium.crypto_secretbox_KEYBYTES), encryptionKey())
87
+}
84 88
 
85
-    return {
86
-      address,
87
-      encryptionKey
88
-    }
89
-  }
89
+function pack (address, encryptionKey) {
90
+  address = toBuffer(address, sodium.crypto_sign_PUBLICKEYBYTES)
91
+  encryptionKey = toBuffer(encryptionKey, sodium.crypto_secretbox_KEYBYTES)
92
+  const accessKey = sodium.sodium_malloc(PACKEDLENGTH)
93
+  address.copy(accessKey)
94
+  encryptionKey.copy(accessKey, sodium.crypto_secretbox_KEYBYTES)
95
+  return accessKey
96
+}
90 97
 
91
-  isKey (key) {
92
-    if (!(key instanceof Buffer || typeof key === 'string')) return false
93
-    const length = Buffer.from(key, 'hex').length
94
-    return length === sodium.crypto_sign_PUBLICKEYBYTES ||
95
-      length === sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_secretbox_KEYBYTES
96
-  }
98
+function unpack (key) {
99
+  key = toBuffer(key, [sodium.crypto_sign_PUBLICKEYBYTES, PACKEDLENGTH])
97 100
 
98
-  toBuffer (stringOrBuffer, lengths) {
99
-    if (!lengths) lengths = [sodium.crypto_sign_PUBLICKEYBYTES, sodium.crypto_secretbox_KEYBYTES]
100
-    if (typeof lengths === 'number') lengths = [lengths]
101
-    if ((Buffer.isBuffer(stringOrBuffer)) && (lengths.indexOf(stringOrBuffer.length) > -1)) return stringOrBuffer
102
-    assert(typeof stringOrBuffer === 'string', 'Key is incorrect type')
103
-    const res = Buffer.from(stringOrBuffer, 'hex')
104
-    assert(lengths.indexOf(res.length) > -1, 'Invalid key')
105
-    return res
106
-  }
101
+  if (key.length === sodium.crypto_sign_PUBLICKEYBYTES) return { address: key }
107 102
 
108
-  keyToMnemonic (key) {
109
-    return bip39.entropyToMnemonic(key)
110
-  }
103
+  const address = key.slice(0, sodium.crypto_sign_PUBLICKEYBYTES)
104
+  const encryptionKey = key.slice(sodium.crypto_secretbox_KEYBYTES)
111 105
 
112
-  mnemonicToKey (mnemonic) {
113
-    return this.toBuffer(bip39.mnemonicToEntropy(mnemonic), [sodium.crypto_secretbox_KEYBYTES])
106
+  return {
107
+    address,
108
+    encryptionKey
114 109
   }
110
+}
115 111
 
116
-  encoder (encryptionKey, opts = {}) {
117
-    return encoder(encryptionKey, opts)
118
-  }
112
+function isKey (key) {
113
+  if (!(key instanceof Buffer || typeof key === 'string')) return false
114
+  const length = Buffer.from(key, 'hex').length
115
+  return length === sodium.crypto_sign_PUBLICKEYBYTES ||
116
+    length === sodium.crypto_sign_PUBLICKEYBYTES + sodium.crypto_secretbox_KEYBYTES
117
+}
119 118
 
120
-  boxKeypair (masterKey, id, ctxt = 'coboxcobox') {
121
-    return this._boxKeypair(this._deriveSeed(masterKey, id, ctxt))
122
-  }
119
+function toBuffer (stringOrBuffer, lengths) {
120
+  if (!lengths) lengths = [sodium.crypto_sign_PUBLICKEYBYTES, sodium.crypto_secretbox_KEYBYTES]
121
+  if (typeof lengths === 'number') lengths = [lengths]
122
+  if ((Buffer.isBuffer(stringOrBuffer)) && (lengths.indexOf(stringOrBuffer.length) > -1)) return stringOrBuffer
123
+  assert(typeof stringOrBuffer === 'string', 'Key is incorrect type')
124
+  const res = Buffer.from(stringOrBuffer, 'hex')
125
+  assert(lengths.indexOf(res.length) > -1, 'Invalid key')
126
+  return res
127
+}
123 128
 
124
-  _boxKeypair (seed) {
125
-    const publicKey = sodium.sodium_malloc(sodium.crypto_box_PUBLICKEYBYTES)
126
-    const secretKey = sodium.sodium_malloc(sodium.crypto_box_SECRETKEYBYTES)
127
-    if (seed) {
128
-      seed = this.toBuffer(seed, sodium.crypto_box_SEEDBYTES)
129
-      sodium.crypto_box_seed_keypair(publicKey, secretKey, seed)
130
-      zero(seed)
131
-    } else {
132
-      sodium.crypto_box_keypair(publicKey, secretKey)
133
-    }
134
-    return { publicKey, secretKey }
135
-  }
129
+function mnemonicToKey (mnemonic) {
130
+  return toBuffer(bip39.mnemonicToEntropy(mnemonic), [sodium.crypto_secretbox_KEYBYTES])
131
+}
136 132
 
137
-  box (pubKey, messageBuffer, contextMessage = Buffer.from('cobox')) {
138
-    pubKey = this.toBuffer(pubKey, sodium.crypto_box_PUBLICKEYBYTES)
139
-    if (typeof messageBuffer === 'string') messageBuffer = Buffer.from(messageBuffer)
140
-    if (typeof contextMessage === 'string') contextMessage = Buffer.from(contextMessage)
141
-    var boxed = Buffer.alloc(messageBuffer.length + sodium.crypto_secretbox_MACBYTES)
142
-    const ephKeypair = this._boxKeypair()
143
-    const nonce = this.randomBytes(sodium.crypto_secretbox_NONCEBYTES)
144
-    var sharedSecret = this.genericHash(
145
-      Buffer.concat([ephKeypair.publicKey, pubKey, contextMessage]),
146
-      this.genericHash(this.scalarMult(ephKeypair.secretKey, pubKey)))
147
-
148
-    sodium.crypto_secretbox_easy(boxed, messageBuffer, nonce, sharedSecret)
149
-
150
-    zero(sharedSecret)
151
-    zero(ephKeypair.secretKey)
152
-    return Buffer.concat([nonce, ephKeypair.publicKey, boxed])
153
-  }
133
+function deriveBoxKeyPair (masterKey, id, ctxt = 'coboxcobox') {
134
+  return boxKeyPair(deriveSeed(masterKey, id, ctxt))
135
+}
154 136
 
155
-  unbox (cipherText, keypair, contextMessage = Buffer.from('cobox')) {
156
-    keypair.publicKey = this.toBuffer(keypair.publicKey, sodium.crypto_box_PUBLICKEYBYTES)
157
-    keypair.secretKey = this.toBuffer(keypair.secretKey, sodium.crypto_box_SECRETKEYBYTES)
158
-    if (typeof contextMessage === 'string') contextMessage = Buffer.from(contextMessage)
159
-    const NONCEBYTES = sodium.crypto_secretbox_NONCEBYTES
160
-    const KEYBYTES = sodium.crypto_secretbox_KEYBYTES
161
-    try {
162
-      var nonce = cipherText.slice(0, NONCEBYTES)
163
-      var pubKey = cipherText.slice(NONCEBYTES, NONCEBYTES + KEYBYTES)
164
-      var box = cipherText.slice(NONCEBYTES + KEYBYTES, cipherText.length)
165
-      var unboxed = Buffer.alloc(box.length - sodium.crypto_secretbox_MACBYTES)
166
-    } catch (err) {
167
-      return false
168
-    }
169
-    const sharedSecret = this.genericHash(
170
-      Buffer.concat([pubKey, keypair.publicKey, contextMessage]),
171
-      this.genericHash(this.scalarMult(keypair.secretKey, pubKey)))
172
-
173
-    const success = sodium.crypto_secretbox_open_easy(unboxed, box, nonce, sharedSecret)
174
-    zero(sharedSecret)
175
-    zero(keypair.secretKey)
176
-    zero(keypair.publicKey)
177
-    return success ? unboxed : false
178
-  }
137
+function boxKeyPair (seed) {
138
+  const publicKey = sodium.sodium_malloc(sodium.crypto_box_PUBLICKEYBYTES)
139
+  const secretKey = sodium.sodium_malloc(sodium.crypto_box_SECRETKEYBYTES)
140
+  if (seed) {
141
+    seed = toBuffer(seed, sodium.crypto_box_SEEDBYTES)
142
+    sodium.crypto_box_seed_keypair(publicKey, secretKey, seed)
143
+    zero(seed)
144
+  } else {
145
+    sodium.crypto_box_keypair(publicKey, secretKey)
146
+  }
147
+  return { publicKey, secretKey }
148
+}
179 149
 
180
-  genericHash (msg, key, length = sodium.crypto_generichash_BYTES_MAX) {
181
-    assert(
182
-      typeof length === 'number' &&
183
-        length >= sodium.crypto_generichash_BYTES_MIN &&
184
-        length <= sodium.crypto_generichash_BYTES_MAX,
185
-      'invalid length property'
186
-    )
187
-    var hash = sodium.sodium_malloc(length)
188
-    sodium.crypto_generichash(hash, msg, key)
189
-    return hash
190
-  }
150
+function box (pubKey, messageBuffer, contextMessage = Buffer.from('cobox')) {
151
+  pubKey = toBuffer(pubKey, sodium.crypto_box_PUBLICKEYBYTES)
152
+  if (typeof messageBuffer === 'string') messageBuffer = Buffer.from(messageBuffer)
153
+  if (typeof contextMessage === 'string') contextMessage = Buffer.from(contextMessage)
154
+  var boxed = Buffer.alloc(messageBuffer.length + sodium.crypto_secretbox_MACBYTES)
155
+  const ephKeypair = boxKeyPair()
156
+  const nonce = randomBytes(sodium.crypto_secretbox_NONCEBYTES)
157
+  var sharedSecret = genericHash(
158
+    Buffer.concat([ephKeypair.publicKey, pubKey, contextMessage]),
159
+    genericHash(scalarMult(ephKeypair.secretKey, pubKey)))
160
+
161
+  sodium.crypto_secretbox_easy(boxed, messageBuffer, nonce, sharedSecret)
162
+
163
+  zero(sharedSecret)
164
+  zero(ephKeypair.secretKey)
165
+  return Buffer.concat([nonce, ephKeypair.publicKey, boxed])
166
+}
191 167
 
192
-  scalarMult (sk, pk) {
193
-    var result = sodium.sodium_malloc(sodium.crypto_scalarmult_BYTES)
194
-    sodium.crypto_scalarmult(result, sk, pk)
195
-    return result
196
-  }
168
+function unbox (cipherText, keypair, contextMessage = Buffer.from('cobox')) {
169
+  keypair.publicKey = toBuffer(keypair.publicKey, sodium.crypto_box_PUBLICKEYBYTES)
170
+  keypair.secretKey = toBuffer(keypair.secretKey, sodium.crypto_box_SECRETKEYBYTES)
171
+  if (typeof contextMessage === 'string') contextMessage = Buffer.from(contextMessage)
172
+  const NONCEBYTES = sodium.crypto_secretbox_NONCEBYTES
173
+  const KEYBYTES = sodium.crypto_secretbox_KEYBYTES
174
+  try {
175
+    var nonce = cipherText.slice(0, NONCEBYTES)
176
+    var pubKey = cipherText.slice(NONCEBYTES, NONCEBYTES + KEYBYTES)
177
+    var box = cipherText.slice(NONCEBYTES + KEYBYTES, cipherText.length)
178
+    var unboxed = Buffer.alloc(box.length - sodium.crypto_secretbox_MACBYTES)
179
+  } catch (err) {
180
+    return false
181
+  }
182
+  const sharedSecret = genericHash(
183
+    Buffer.concat([pubKey, keypair.publicKey, contextMessage]),
184
+    genericHash(scalarMult(keypair.secretKey, pubKey)))
185
+
186
+  const success = sodium.crypto_secretbox_open_easy(unboxed, box, nonce, sharedSecret)
187
+  zero(sharedSecret)
188
+  zero(keypair.secretKey)
189
+  zero(keypair.publicKey)
190
+  return success ? unboxed : false
191
+}
197 192
 
198
-  _resolveStringEncoder (encoder) {
199
-    if (encoder === 'json') return {
200
-      encode: (msg) => Buffer.from(JSON.stringify(msg)),
201
-      decode: (msg) => JSON.parse(msg.toString())
202
-    }
203
-
204
-    if (encoder === 'utf-8') return {
205
-      encode: (msg) => Buffer.from(msg),
206
-      decode: (msg) => msg.toString()
207
-    }
208
-    return encoder
209
-  }
193
+function genericHash (msg, key, length = sodium.crypto_generichash_BYTES_MAX) {
194
+  assert(
195
+    typeof length === 'number' &&
196
+    length >= sodium.crypto_generichash_BYTES_MIN &&
197
+    length <= sodium.crypto_generichash_BYTES_MAX,
198
+    'invalid length property'
199
+  )
200
+  var hash = sodium.sodium_malloc(length)
201
+  sodium.crypto_generichash(hash, msg, key)
202
+  return hash
210 203
 }
211 204
 
212
-module.exports = new Crypto()
205
+function scalarMult (sk, pk) {
206
+  var result = sodium.sodium_malloc(sodium.crypto_scalarmult_BYTES)
207
+  sodium.crypto_scalarmult(result, sk, pk)
208
+  return result
209
+}

+ 3
- 3
test/index.test.js View File

@@ -211,11 +211,11 @@ describe('hypercore', (context) => {
211 211
 describe('box and unbox', (context) => {
212 212
   context('boxkeypair', (assert, next) => {
213 213
     const masterKey = crypto.masterKey()
214
-    const { publicKey, secretKey } = crypto.boxKeypair(masterKey, 4)
214
+    const { publicKey, secretKey } = crypto.deriveBoxKeyPair(masterKey, 4)
215 215
     assert.ok(Buffer.isBuffer(publicKey), 'public key generated')
216 216
     assert.ok(Buffer.isBuffer(secretKey), 'secret key generated')
217 217
     const seed = crypto.randomBytes(sodium.crypto_box_SEEDBYTES)
218
-    const seedKeypair = crypto._boxKeypair(seed)
218
+    const seedKeypair = crypto.boxKeyPair(seed)
219 219
     assert.ok(Buffer.isBuffer(seedKeypair.publicKey), 'public key generated from seed')
220 220
     assert.ok(Buffer.isBuffer(seedKeypair.secretKey), 'secret key generated from seed')
221 221
     next()
@@ -223,7 +223,7 @@ describe('box and unbox', (context) => {
223 223
 
224 224
   context('box and unbox', (assert, next) => {
225 225
     const masterKey = crypto.masterKey()
226
-    const { publicKey, secretKey } = crypto.boxKeypair(masterKey, 4)
226
+    const { publicKey, secretKey } = crypto.deriveBoxKeyPair(masterKey, 4)
227 227
     const msg = 'beep boop'
228 228
     const boxedMsg = crypto.box(publicKey, Buffer.from(msg))
229 229
     assert.true(boxedMsg.toString('hex') !== msg.toString('hex'), 'boxed message !== message')