Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hypercore-xsalsa20-onwrite-hook

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hypercore-xsalsa20-onwrite-hook - npm Package Compare versions

Comparing version 0.2.0 to 1.0.0

test.js

42

example.js

@@ -1,6 +0,4 @@

const { keyPair } = require('hypercore-crypto')
const replicate = require('hypercore-replicate')
const hypercore = require('hypercore')
const xsalsa20 = require('xsalsa20-encoding')
const crypto = require('crypto')
const crypto = require('hypercore-crypto')
const hook = require('./')

@@ -10,30 +8,22 @@ const ram = require('random-access-memory')

const key = crypto.randomBytes(32)
const nonce = crypto.randomBytes(32)
const onwrite = hook({ nonce, key })
const { publicKey, secretKey } = keyPair()
const valueEncoding = xsalsa20(nonce, key)
const feed = hypercore(ram, publicKey, { secretKey, valueEncoding })
const { publicKey, secretKey } = crypto.keyPair()
const nonces = ram()
feed.ready(() => {
const copy = hypercore(ram, publicKey, { onwrite })
const other = hypercore(ram, publicKey, { valueEncoding })
const feed = hypercore(ram, publicKey, {
secretKey,
onwrite: hook(nonces, key)
})
feed.append('hello')
const copy = hypercore(ram, publicKey, {
onwrite: hook(nonces, key)
})
replicate(feed, replicate(copy, { live: true }), replicate(other, { live: true }), {
live: true
})
feed.append(Buffer.from('hello'), (err) => {
feed.head(console.log) // ciphertext
})
copy.update(() => {
copy.head((err, buf) => {
console.log('%s', buf) // 'hello'
})
})
other.update(() => {
other.head((err, buf) => {
console.log('%s', buf) // 'hello'
})
})
replicate(feed, copy, (err) => {
if (err) throw err
copy.head(console.log) // plaintext
})

@@ -1,26 +0,46 @@

const xsalsa20 = require('xsalsa20')
const xsalsa20 = require('xsalsa20-encoding')
const assert = require('assert')
/**
* The size in bytes of the nonce attached to an
* enciphered buffer returned from the xsalsa20
* encoding.
* @public
* @const
*/
const NONCE_BYTES = 24
const KEY_BYTES = 32
function createHook(opts) {
if (opts && 'object' !== typeof opts) {
throw new TypeError('Expecting options to be an object.')
/**
* Creates a `onwrite()` hook for a Hypercore feed that uses the
* xsalsa20 cipher to encipher or decipher blocks in a Hypercore feed. Blocks
* that are written to a Hypercore feed are encrypted detached from the
* nonce used for encryption. Nonces are written to a user supplied
* "nonce storage" which can be reused for deciphering blocks appended
* to a Hypercore feed.
*
* This function preserves block sizes but requires an external storage
* for nonces. Users should provide a `random-access-storage` compliant
* instance or a factory function that returns one.
* @param {Function<Object,Buffer>} createStorage
* @param {String|Buffer} key
* @param {?(Object)} opts
* @return {Function}
*/
function createHook(createStorage, key, opts) {
if ('string' === typeof key) {
key = Buffer.from(key, 'hex')
}
// make copy of opts because we'll modify the
// nonce and key in place if they are strings
opts = Object.assign({}, opts)
opts = Object.assign({}, opts)
if ('string' === typeof opts.nonce) {
opts.nonce = Buffer.from(opts.nonce, 'hex')
}
assert(Buffer.isBuffer(key), '`key` is not a buffer.')
if ('string' === typeof opts.key) {
opts.key = Buffer.from(opts.key, 'hex')
if (createStorage && 'object' !== typeof createStorage) {
assert('function' === typeof createStorage,
'`createStorage` is not a function.')
}
if (opts.nonce && !Buffer.isBuffer(opts.nonce)) {
throw new TypeError('Expecting given nonce to be a buffer.')
}
const storage = 'function' === typeof createStorage
? createStorage(opts, key)
: createStorage

@@ -30,28 +50,27 @@ return onwrite

function onwrite(index, data, peer, done) {
const feed = this
const offset = index * NONCE_BYTES
// The caller could call `feed.append()` before the feed is ready
// which calls this hook synchronously
feed.ready(() => {
// This hook should only handle 'readable' feeds that are
// replicating with a peer.
// The hook can only handle buffers as the 'xsalsa20' will
// update the buffer in place
if (!opts.key || feed.writable || !peer || !Buffer.isBuffer(data)) {
if (!peer) {
const encrypted = xsalsa20(key).encode(data)
const nonce = encrypted.slice(0, NONCE_BYTES)
encrypted.slice(NONCE_BYTES).copy(data)
storage.write(offset, nonce, done)
} else {
storage.read(offset, NONCE_BYTES, (err, nonce) => {
// istanbul ignore next
if (err) { return done(err) }
const attached = Buffer.concat([nonce, data])
const decrypted = xsalsa20(key).decode(attached)
decrypted.copy(data)
done(null)
} else {
// We use the feed's public key as a nonce if one is not given
const nonce = Buffer.from(opts.nonce || feed.key).slice(0, NONCE_BYTES)
const key = Buffer.from(opts.key).slice(0, KEY_BYTES)
const xor = opts.xor || xsalsa20(nonce, key)
xor.update(data, data)
done(null)
}
})
})
}
}
}
/**
* Module exports.
*/
module.exports = Object.assign(createHook, {
NONCE_BYTES,
KEY_BYTES,
NONCE_BYTES
})
{
"name": "hypercore-xsalsa20-onwrite-hook",
"version": "0.2.0",
"version": "1.0.0",
"description": "A write hook to decrypt data using a XSalsa20 cipher into a hypercore storage when replicating from peers",
"main": "index.js",
"scripts": {
"test": ":"
"test": "nyc tape test.js"
},

@@ -19,8 +19,11 @@ "keywords": [

"hypercore": "^8.0.0",
"hypercore-crypto": "^1.0.0",
"hypercore-ready": "^0.2.0",
"hypercore-replicate": "^0.2.0",
"nyc": "^15.0.0",
"random-access-memory": "^3.1.1",
"xsalsa20-encoding": "^0.1.0"
"tape": "^4.12.1"
},
"dependencies": {
"xsalsa20": "^1.0.2"
"xsalsa20-encoding": "^0.2.0"
},

@@ -27,0 +30,0 @@ "repository": {

hypercore-xsalsa20-onwrite-hook
===============================
A write hook to decrypt data using a XSalsa20 cipher into a hypercore
storage when replicating from peers.
> A write hook to decrypt data using a xsalsa20 cipher into a Hypercore
> storage when replicating from peers.
## Installation

@@ -17,9 +16,4 @@

```js
const hook = require('hypercore-xsalsa20-onwrite-hook')
const feed = hypercore(storage, key, {
onwrite: hook({
nonce: storageNonce,
key: sharedStorageKey
})
})
const nonces = ram() // or any `random-access-storage` compliant object
const onwrite = hook(nonces, sharedSecret)
```

@@ -30,7 +24,5 @@

```js
const { keyPair } = require('hypercore-crypto')
const replicate = require('hypercore-replicate')
const hypercore = require('hypercore')
const xsalsa20 = require('xsalsa20-encoding')
const crypto = require('crypto')
const crypto = require('hypercore-crypto')
const hook = require('hypercore-xsalsa20-onwrite-hook')

@@ -40,31 +32,21 @@ const ram = require('random-access-memory')

const key = crypto.randomBytes(32)
const nonce = crypto.randomBytes(32)
const onwrite = hook({ nonce, key })
const { publicKey, secretKey } = keyPair()
const valueEncoding = xsalsa20(nonce, key)
const feed = hypercore(ram, publicKey, { secretKey, valueEncoding })
const { publicKey, secretKey } = crypto.keyPair()
const nonces = ram()
feed.ready(() => {
const copy = hypercore(ram, publicKey, { onwrite })
const other = hypercore(ram, publicKey, { valueEncoding })
const feed = hypercore(ram, publicKey, {
secretKey,
onwrite: hook(nonces, key)
})
feed.append('hello')
const copy = hypercore(ram, publicKey, {
onwrite: hook(nonces, key)
})
replicate(feed, copy.replicate({ live: true }), other.replicate({ live: true }), {
userData: Buffer.from([0xfa, 0xce]),
live: true
})
feed.append(Buffer.from('hello'), (err) => {
feed.head(console.log) // ciphertext
})
copy.update(() => {
copy.head((err, buf) => {
console.log('%s', buf) // 'hello'
})
})
other.update(() => {
other.head((err, buf) => {
console.log('%s', buf) // 'hello'
})
})
replicate(feed, copy, (err) => {
copy.head(console.log) // plaintext
})

@@ -75,12 +57,14 @@ ```

### `hook = require('hypercore-xsalsa20-onwrite-hook')(opts)`
### `const onwrite = hook(nonceStorage, sharedKey)`
where `opts` can be:
Creates a `onwrite()` hook for a Hypercore feed that uses the
xsalsa20 cipher to encipher or decipher blocks in a Hypercore feed.
Blocks that are written to a Hypercore feed are encrypted detached
from the nonce used for encryption. Nonces are written to a user
supplied "nonce storage" which can be reused for deciphering blocks
appended to a Hypercore feed.
```js
{
nonce: [Buffer], // An optional 24 byte nonce. If not given, the hypercore's public key is used
key: Buffer, // A required shared 32 byte shared secret key
}
```
This function preserves block sizes but requires an external storage
for nonces (`nonceStorage`). Users should provide a `random-access-storage`
compliant instance or a factory function that returns one.

@@ -87,0 +71,0 @@ ## License

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc