From e82962d6a66f8b55cb8d90157aea888a365957d2 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 12 Dec 2019 11:25:45 +0100 Subject: [PATCH 1/9] package.json --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index b73c0da..3a86198 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,10 @@ "encoder", "hypercore" ], + "repository": { + "type": "git", + "url": "git+https://github.com/ameba23/crypto-encoder.git" + }, "author": "Magma Collective", "license": "AGPL-3.0-or-later" } From 20aa40af66974378555d3488954019c1f15fd106 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 12 Dec 2019 11:28:23 +0100 Subject: [PATCH 2/9] 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a86198..875199a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crypto-encoder", - "version": "1.0.0", + "version": "1.0.1", "description": "A simple crypto encoder compatible with hypercore", "main": "index.js", "directories": { From b8889d4767328af2a718e4e1dfaf5536a55d1aff Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 15 Jul 2020 13:12:21 +0200 Subject: [PATCH 3/9] 1.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e351ce..9977d8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crypto-encoder", - "version": "1.0.1", + "version": "1.0.2", "description": "A simple crypto encoder compatible with hypercore", "main": "index.js", "directories": { From 6b02e22fe8596d58cfeedc6fb8418b1fad76ecef Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 16:43:34 +0200 Subject: [PATCH 4/9] use xor stream --- index.js | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 7c4f16c..2fd93c0 100644 --- a/index.js +++ b/index.js @@ -1,39 +1,42 @@ const sodium = require('sodium-native') const assert = require('assert') const codecs = require('codecs') -const zero = sodium.sodium_memzero module.exports = encoder module.exports.encryptionKey = encryptionKey -module.exports.KEYBYTES = sodium.crypto_secretbox_KEYBYTES +module.exports.KEYBYTES = sodium.crypto_stream_KEYBYTES +module.exports.generateNonce = function () { + const nonce = Buffer.alloc(sodium.crypto_stream_NONCEBYTES) + sodium.randombytes_buf(nonce) + return nonce +} function encoder (encryptionKey, opts = {}) { assert(Buffer.isBuffer(encryptionKey), 'encryption key must be a buffer') - assert(encryptionKey.length === sodium.crypto_secretbox_KEYBYTES, `cobox-crypto: key must be a buffer of length ${sodium.crypto_secretbox_KEYBYTES}`) + assert(encryptionKey.length === sodium.crypto_stream_KEYBYTES, `Key must be a buffer of length ${sodium.crypto_stream_KEYBYTES}`) const encoder = codecs(opts.valueEncoding) + const nonce = opts.nonce + + const encrypt = function (data) { + sodium.crypto_stream_xor(data, data, nonce, encryptionKey) + return data + } + + const decrypt = function (data) { + sodium.crypto_stream_xor(data, data, nonce, encryptionKey) + return data + } return { encode (message, buffer, offset) { // Run originally provided encoder if any - message = encoder.encode(message, buffer, offset) - const ciphertext = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES) - const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) - sodium.randombytes_buf(nonce) - sodium.crypto_secretbox_easy(ciphertext, message, nonce, encryptionKey) - zero(message) - return Buffer.concat([nonce, ciphertext]) + return encrypt(encoder.encode(message, buffer, offset)) }, - decode (buffer, start, end) { - const nonce = buffer.slice(0, sodium.crypto_secretbox_NONCEBYTES) - const messageWithMAC = buffer.slice(sodium.crypto_secretbox_NONCEBYTES) - const message = Buffer.alloc(messageWithMAC.length - sodium.crypto_secretbox_MACBYTES) - assert( - sodium.crypto_secretbox_open_easy(message, messageWithMAC, nonce, encryptionKey), - 'Decryption failed!' - ) + decode (message, start, end) { + // console.log(decode(message).toString()) // Run originally provided encoder if any - return encoder.decode(message, start, end) + return encoder.decode(decrypt(message), start, end) } } } From 79ef1a6b5a8914f5c2bb1195272c6f13b8c98ebb Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 16:43:49 +0200 Subject: [PATCH 5/9] update test --- test/index.test.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index a5559cf..63d94d7 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -10,7 +10,8 @@ const { cleanup, tmp } = require('./util') describe('message encoding', (context) => { context('encrypt and decrypt a message', (assert, next) => { const key = Encoder.encryptionKey() - const encoder = Encoder(key, { valueEncoding: 'utf-8' }) + const nonce = Encoder.generateNonce() + const encoder = Encoder(key, { nonce, valueEncoding: 'utf-8' }) const encrypted = encoder.encode('Hello World') assert.ok(encrypted, 'Encrypts the message') @@ -31,19 +32,20 @@ describe('hypercore', (context) => { context('encrypted the log', (assert, next) => { const key = Encoder.encryptionKey() - const encoder = Encoder(key, { valueEncoding: 'utf-8' }) + const nonce = Encoder.generateNonce() + const encoder = Encoder(key, { nonce, valueEncoding: 'utf-8' }) const feed = hypercore(storage, { valueEncoding: encoder }) feed.append('boop', (err) => { assert.error(err, 'no error') - var data = fs.readFileSync(path.join(storage, 'data')) + const data = fs.readFileSync(path.join(storage, 'data')) assert.notSame(data, 'boop', 'log entry is encrypted') assert.same(encoder.decode(data), 'boop', 'log entry is encrypted') feed.get(0, (err, entry) => { assert.error(err, 'no error') - assert.same('boop', entry, 'hypercore decrypts the message') + assert.same(entry, 'boop', 'hypercore decrypts the message') cleanup(storage, next) }) @@ -52,7 +54,8 @@ describe('hypercore', (context) => { context('encrypted the log, with a json object', (assert, next) => { const key = Encoder.encryptionKey() - const encoder = Encoder(key, { valueEncoding: 'json' }) + const nonce = Encoder.generateNonce() + const encoder = Encoder(key, { nonce, valueEncoding: 'json' }) const feed = hypercore(storage, { valueEncoding: encoder }) const message = { boop: 'beep' } @@ -60,6 +63,10 @@ describe('hypercore', (context) => { feed.append(message, (err) => { assert.error(err, 'no error') + const data = fs.readFileSync(path.join(storage, 'data')) + assert.notSame(JSON.stringify(data), JSON.stringify(message), 'log entry is encrypted') + assert.same(JSON.stringify(encoder.decode(data)), JSON.stringify(message), 'log entry is encrypted') + feed.get(0, (err, entry) => { assert.error(err, 'no error') assert.same(message, entry, 'hypercore decrypts the message') From 937fd16553815d79b50ef0f48af489fce640bb16 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 16:47:30 +0200 Subject: [PATCH 6/9] tidy --- index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.js b/index.js index 2fd93c0..3105f77 100644 --- a/index.js +++ b/index.js @@ -28,14 +28,12 @@ function encoder (encryptionKey, opts = {}) { sodium.crypto_stream_xor(data, data, nonce, encryptionKey) return data } + return { encode (message, buffer, offset) { - // Run originally provided encoder if any return encrypt(encoder.encode(message, buffer, offset)) }, decode (message, start, end) { - // console.log(decode(message).toString()) - // Run originally provided encoder if any return encoder.decode(decrypt(message), start, end) } } From f4cd77575a2d085cac61556a418bf20c2c0f477b Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 16:50:21 +0200 Subject: [PATCH 7/9] make clearer --- index.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 3105f77..287f943 100644 --- a/index.js +++ b/index.js @@ -19,22 +19,17 @@ function encoder (encryptionKey, opts = {}) { const nonce = opts.nonce - const encrypt = function (data) { - sodium.crypto_stream_xor(data, data, nonce, encryptionKey) - return data - } - - const decrypt = function (data) { + const encryptOrDecrypt = function (data) { sodium.crypto_stream_xor(data, data, nonce, encryptionKey) return data } return { encode (message, buffer, offset) { - return encrypt(encoder.encode(message, buffer, offset)) + return encryptOrDecrypt(encoder.encode(message, buffer, offset)) }, decode (message, start, end) { - return encoder.decode(decrypt(message), start, end) + return encoder.decode(encryptOrDecrypt(message), start, end) } } } From 36aad1a9f976c814ec5e1c6593696d041831f3d3 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 17:06:15 +0200 Subject: [PATCH 8/9] readme, assert nonce exists --- README.md | 9 ++++++++- index.js | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f186df..df677f2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ const hypercore = require('hypercore') const Encoder = require('.') const encryptionKey = Encoder.encryptionKey() -const valueEncoding = Encoder(encrytionKey, { valueEncoding: 'utf-8' }) +const nonce = Encoder.generateNonce() +const valueEncoding = Encoder(encrytionKey, { nonce, valueEncoding: 'utf-8' }) const feed = hypercore(storage, { valueEncoding }) ``` @@ -25,12 +26,18 @@ const encryptionKey = Encoder.encryptionKey() ``` Generate a random 32 byte key to be used to encrypt. +```js +const nonce = Encoder.generateNonce() +``` +Generate a random nonce used to encrypt. + ```js const valueEncoding = Encoder(encryptionKey, opts) ``` Returns a message encoder used for encrypting messages in hypercore. - `encryptionKey` must be a buffer of length `Encoder.KEYBYTES`. - `opts` is an optional object which may contain: + - `ops.nonce` a buffer containing a 24 byte nonce - `opts.valueEncoder`, an additional encoder to be used before encryption. May be one of: - The string 'utf-8' - utf-8 encoded strings will be assumed. - The string 'JSON' - JSON encoding will be assumed. diff --git a/index.js b/index.js index 287f943..1b716ef 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ function encoder (encryptionKey, opts = {}) { const encoder = codecs(opts.valueEncoding) const nonce = opts.nonce + assert(nonce, 'Nonce must be provided') const encryptOrDecrypt = function (data) { sodium.crypto_stream_xor(data, data, nonce, encryptionKey) From 32805ffe1b5c3b26c91346bd07926d7ac1826215 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 22 Jul 2020 17:09:14 +0200 Subject: [PATCH 9/9] check length of ciphertext --- test/index.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/index.test.js b/test/index.test.js index 63d94d7..0c833dc 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -16,6 +16,7 @@ describe('message encoding', (context) => { const encrypted = encoder.encode('Hello World') assert.ok(encrypted, 'Encrypts the message') assert.ok(encrypted instanceof Buffer, 'Returns a buffer') + assert.equals(encrypted.length, 'Hello World'.length, 'Ciphertext and plaintext are same length') const message = encoder.decode(encrypted) assert.same(message, 'Hello World', 'Decrypts the message')