Skip to content

Commit

Permalink
feat(.): Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jwerle committed May 18, 2018
1 parent 4edbb4e commit 1659ef7
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 0 deletions.
49 changes: 49 additions & 0 deletions blake2b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict'

const { crypto_generichash_batch } = require('sodium-universal')
const isBuffer = require('is-buffer')
const alloc = require('buffer-alloc-unsafe')

const kDefaultBlake2bSize = 32

/**
* Generates a blake2b digest hash from input of a
* given size defaulting to 32 bytes. This function calls
* `crypto_generichash_batch` internally.
* @public
* @param {Buffer|Array<Buffer>} buffer
* @param {?(Number)} [size = 32]
* @return {Buffer}
* @throws TypeError
*/
function blake2b(buffer, size) {
if (null == size || 'number' != typeof size) {
size = kDefaultBlake2bSize
} else if (size <= 0) {
throw new TypeError("blake2b: Expecting size to be greater than 0.")
}

if (isBuffer(buffer)) {
buffer = [buffer]
}

if (false == Array.isArray(buffer)) {
throw new TypeError("blake2b: Expecting buffer as input.")
}

for (let i = 0; i < buffer.length; ++i) {
if (false == isBuffer(buffer[i])) {
throw new TypeError(`blake2b: Buffer at index ${i} is not buffer.`)
} else if (0 == buffer[i].length) {
throw new TypeError(`blake2b: Buffer at index ${i} is empty.`)
}
}

const digest = alloc(size)
crypto_generichash_batch(digest, buffer)
return digest
}

module.exports = {
blake2b
}
47 changes: 47 additions & 0 deletions discovery-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict'

const isBuffer = require('is-buffer')
const alloc = require('buffer-alloc-unsafe')

const {
crypto_generichash,
crypto_generichash_KEYBYTES_MIN,
} = require('sodium-universal')

const kDefaultDiscoveryKeyMessageKey = alloc(crypto_generichash_KEYBYTES_MIN).fill('ara')
const kDefaultDiscoveryKeySize = 32

/**
* Generate a discovery digest useful for network
* keys. This function calls `crypto_generichash` internally.
* @public
* @param {Buffer|Array<Buffer>} buffer
* @param {?(Number)} [size = 32]
* @return {Buffer}
* @throws TypeError
*/
function discoveryKey(buffer, size, key) {
if (null == size || 'number' != typeof size) {
size = kDefaultDiscoveryKeySize
} else if (size <= 0) {
throw new TypeError("discoveryKey: Expecting size to be greater than 0.")
}

if (null == key) {
key = kDefaultDiscoveryKeyMessageKey
} else if (false == isBuffer(key)) {
throw new TypeError("discoveryKey: Expecting key to be a buffer")
}

if (false == isBuffer(buffer)) {
throw new TypeError("discoveryKey: Expecting buffer.")
}

const digest = alloc(size)
crypto_generichash(digest, buffer, key)
return digest
}

module.exports = {
discoveryKey
}
19 changes: 19 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict'

const { discoveryKey } = require('./discovery-key')
const { randomBytes } = require('./random-bytes')
const { blake2b } = require('./blake2b')
const { keyPair } = require('./key-pair')
const { verify } = require('./verify')
const { sign } = require('./sign')
const uint64 = require('./uint64')

module.exports = {
discoveryKey,
randomBytes,
blake2b,
keyPair,
uint64,
verify,
sign,
}
58 changes: 58 additions & 0 deletions key-pair.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'

const isBuffer = require('is-buffer')
const alloc = require('buffer-alloc-unsafe')

const {
crypto_sign_PUBLICKEYBYTES,
crypto_sign_SECRETKEYBYTES,
crypto_sign_SEEDBYTES,
crypto_sign_seed_keypair,
crypto_sign_keypair,
} = require('sodium-universal')

/**
* Generate a public and secret key pair from an optional
* seed buffer. This function calls crypto_sign_seed_keypair and
* crypto_sign_keypair internally.
* @public
* @param {(Buffer)} [seed]
* @return {Object}
* @throws TypeError
*/
function keyPair(seed) {
if (null === seed) {
throw new TypeError("keyPair: Seed cannot be null.")
} else if (null != seed) {
if (false == isBuffer(seed)) {
throw new TypeError("keyPair: Expecting seed to be a buffer.")
} else if (0 == seed.length) {
throw new TypeError("keyPair: Cannot use empty buffer as seed.")
} else if (seed.length < crypto_sign_SEEDBYTES) {
throw new TypeError(
`keyPair: Seed buffer length too small. `+
`Expecting size ${crypto_sign_SEEDBYTES}.`
)
} else if (seed.length > crypto_sign_SEEDBYTES) {
throw new TypeError(
`keyPair: Seed buffer length too large. `+
`Expecting size ${crypto_sign_SEEDBYTES}.`
)
}
}

const publicKey = alloc(crypto_sign_PUBLICKEYBYTES)
const secretKey = alloc(crypto_sign_SECRETKEYBYTES)

if (seed) {
crypto_sign_seed_keypair(publicKey, secretKey, seed)
} else {
crypto_sign_keypair(publicKey, secretKey)
}

return { publicKey, secretKey }
}

module.exports = {
keyPair
}
30 changes: 30 additions & 0 deletions random-bytes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'

const { randombytes_buf } = require('sodium-universal')
const alloc = require('buffer-alloc-unsafe')

/**
* Generate a sized buffer of random bytes. This function calls `randombytes_buf`
* on a buffer of specified size.
* @public
* @param {Number} size
* @return {Buffer}
* @throws TypeError
*/
function randomBytes(size) {
if (null == size || 'number' != typeof size) {
throw new TypeError("randomBytes: Expecting size to be a number.")
} else if (size != size) {
throw new TypeError("randomBytes: Size cannot be NaN.")
} else if (size <= 0) {
throw new TypeError("randomBytes: Size must be larger than 0.")
}

const buffer = alloc(size)
randombytes_buf(buffer)
return buffer
}

module.exports = {
randomBytes
}
40 changes: 40 additions & 0 deletions sign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict'

const isBuffer = require('is-buffer')
const alloc = require('buffer-alloc-unsafe')

const {
crypto_sign_detached,
crypto_sign_BYTES,
} = require('sodium-universal')

/**
* Sign a message buffer with a secret key buffer. This function calls
* `crypto_sign_detached` on a buffer of size `crypto_sign_BYTES`.
* @public
* @param {Buffer} message
* @param {Buffer} secretKey
* @return {Buffer}
* @throws TypeError
*/
function sign(message, secretKey) {
if (null == message || false == isBuffer(message)) {
throw new TypeError("sign: Expecting message to be a buffer.")
} else if (0 == message.length) {
throw new TypeError("sign: Cannot sign an empty message.")
}

if (null == secretKey || false == isBuffer(secretKey)) {
throw new TypeError("sign: Expecting secretKey to be a buffer.")
} else if (0 == secretKey.length) {
throw new TypeError("sign: Cannot sign with an empty secretKey.")
}

const buffer = alloc(crypto_sign_BYTES)
crypto_sign_detached(buffer, message, secretKey)
return buffer
}

module.exports = {
sign
}
50 changes: 50 additions & 0 deletions uint64.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict'

const isBuffer = require('is-buffer')
const uint64be = require('uint64be')
const alloc = require('buffer-alloc-unsafe')

const kMinUInt64Size = 8
const kDefaultUInt64Size = kMinUInt64Size

/**
* Encode an unsigned 64-bit big endian number into a buffer
* of a given size defaulting to 8 bytes.
* @public
* @param {Number} value
* @param {?(Number)} size
* @return {Buffer}
* @throws {TypeError}
*/
function encode(value, size) {
if (null == size) { size = kDefaultUInt64Size }
if ('number' != typeof size || size < kMinUInt64Size) {
throw new TypeError("uint64.encode: Expecting size to greater than 8.")
} else if (value != value) {
throw new TypeError("uint64.encode: Cannot encode NaN.")
} else if ('number' != typeof value) {
throw new TypeError("uint64.encode: Expecting number.")
}
return uint64be.encode(value, alloc(size))
}

/**
* Decode an unsigned 64-bit big endian buffer into a number
* @public
* @param {Number} value
* @return {Buffer}
* @throws {TypeError}
*/
function decode(buffer) {
if (false == isBuffer(buffer)) {
throw new TypeError("uint64.decode: Expecting buffer.")
} else if (0 == buffer.length) {
throw new TypeError("uint64.decode: Cannot decode buffer of 0 length.")
}
return uint64be.decode(buffer)
}

module.exports = {
encode,
decode,
}
54 changes: 54 additions & 0 deletions verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict'

const isBuffer = require('is-buffer')

const {
crypto_sign_verify_detached,
crypto_sign_PUBLICKEYBYTES,
crypto_sign_BYTES,
} = require('sodium-universal')

/**
* Verify signature for a message signed with a given
* public key. This function calls `crypto_sign_verify_detached`
* internally.
* @public
* @param {Buffer} message
* @param {Buffer} signature
* @param {Buffer} publicKey
* @return {Boolean}
* @throws TypeError
*/
function verify(message, signature, publicKey) {
if (false == isBuffer(message)) {
throw new TypeError("verify: Expecting message to be a buffer.")
} else if (0 == message.length) {
throw new TypeError("verify: Cannot verify an empty message buffer.")
}

if (false == isBuffer(signature)) {
throw new TypeError("verify: Expecting signature to be a buffer.")
} else if (0 == signature.length) {
throw new TypeError("verify: Cannot verify message with an signature buffer.")
} else if (signature.length < crypto_sign_BYTES) {
throw new TypeError("verify: Signature buffer too small.")
} else if (signature.length > crypto_sign_BYTES) {
throw new TypeError("verify: Signature buffer too large.")
}

if (false == isBuffer(publicKey)) {
throw new TypeError("verify: Expecting publicKey to be a buffer.")
} else if (0 == publicKey.length) {
throw new TypeError("verify: Cannot verify message with an publicKey buffer.")
} else if (publicKey.length < crypto_sign_PUBLICKEYBYTES) {
throw new TypeError("verify: Public key buffer too small.")
} else if (publicKey.length > crypto_sign_PUBLICKEYBYTES) {
throw new TypeError("verify: Public key buffer too large.")
}

return crypto_sign_verify_detached(signature, message, publicKey)
}

module.exports = {
verify
}

0 comments on commit 1659ef7

Please sign in to comment.