203 lines
6.2 KiB
JavaScript
203 lines
6.2 KiB
JavaScript
var libsodium = require('libsodium-sumo')
|
|
var sodium = require('libsodium-wrappers-sumo')
|
|
|
|
var output_format = 'uint8array'
|
|
|
|
function _format_output (output, optionalOutputFormat) {
|
|
var selectedOutputFormat = optionalOutputFormat || output_format
|
|
if (!_is_output_format(selectedOutputFormat)) {
|
|
throw new Error(selectedOutputFormat + ' output format is not available')
|
|
}
|
|
if (output instanceof AllocatedBuf) {
|
|
if (selectedOutputFormat === 'uint8array') {
|
|
return output.to_Uint8Array()
|
|
} else if (selectedOutputFormat === 'text') {
|
|
return sodium.to_string(output.to_Uint8Array())
|
|
} else if (selectedOutputFormat === 'hex') {
|
|
return sodium.to_hex(output.to_Uint8Array())
|
|
} else if (selectedOutputFormat === 'base64') {
|
|
return sodium.to_base64(output.to_Uint8Array())
|
|
} else {
|
|
throw new Error('What is output format \"' + selectedOutputFormat + '\"?')
|
|
}
|
|
} else if (typeof output === 'object') { // Composed output. Example : key pairs
|
|
var props = Object.keys(output)
|
|
var formattedOutput = {}
|
|
for (var i = 0; i < props.length; i++) {
|
|
formattedOutput[props[i]] = _format_output(output[props[i]], selectedOutputFormat)
|
|
}
|
|
return formattedOutput
|
|
} else if (typeof output === 'string') {
|
|
return output
|
|
} else {
|
|
throw new TypeError('Cannot format output')
|
|
}
|
|
}
|
|
|
|
function _is_output_format (format) {
|
|
var formats = sodium.output_formats()
|
|
for (var i = 0; i < formats.length; i++) {
|
|
if (formats[i] === format) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
function _check_output_format (format) {
|
|
if (!format) {
|
|
return
|
|
} else if (typeof format !== 'string') {
|
|
throw new TypeError('When defined, the output format must be a string')
|
|
} else if (!_is_output_format(format)) {
|
|
throw new Error(format + ' is not a supported output format')
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Memory management
|
|
//
|
|
// AllocatedBuf: address allocated using _malloc() + length
|
|
function AllocatedBuf (length) {
|
|
this.length = length
|
|
this.address = _malloc(length)
|
|
}
|
|
|
|
// Copy the content of a AllocatedBuf (_malloc()'d memory) into a Uint8Array
|
|
AllocatedBuf.prototype.to_Uint8Array = function () {
|
|
var result = new Uint8Array(this.length)
|
|
result.set(libsodium.HEAPU8.subarray(this.address, this.address + this.length))
|
|
return result
|
|
}
|
|
|
|
// _malloc() a region and initialize it with the content of a Uint8Array
|
|
function _to_allocated_buf_address (bytes) {
|
|
var address = _malloc(bytes.length)
|
|
libsodium.HEAPU8.set(bytes, address)
|
|
return address
|
|
}
|
|
|
|
function _malloc (length) {
|
|
var result = libsodium._malloc(length)
|
|
if (result === 0) {
|
|
var err = {
|
|
message: '_malloc() failed',
|
|
length: length
|
|
}
|
|
throw err
|
|
}
|
|
return result
|
|
}
|
|
|
|
function _free (address) {
|
|
libsodium._free(address)
|
|
}
|
|
|
|
function _free_all (addresses) {
|
|
for (var i = 0; i < addresses.length; i++) {
|
|
_free(addresses[i])
|
|
}
|
|
}
|
|
|
|
function _free_and_throw_error (address_pool, err) {
|
|
_free_all(address_pool)
|
|
throw new Error(err)
|
|
}
|
|
|
|
function _free_and_throw_type_error (address_pool, err) {
|
|
_free_all(address_pool)
|
|
throw new TypeError(err)
|
|
}
|
|
|
|
function _require_defined (address_pool, varValue, varName) {
|
|
if (varValue === undefined) {
|
|
_free_and_throw_type_error(address_pool, varName + ' cannot be null or undefined')
|
|
}
|
|
}
|
|
|
|
function _any_to_Uint8Array (address_pool, varValue, varName) {
|
|
_require_defined(address_pool, varValue, varName)
|
|
if (varValue instanceof Uint8Array) {
|
|
return varValue
|
|
} else if (typeof varValue === 'string') {
|
|
return sodium.from_string(varValue)
|
|
}
|
|
_free_and_throw_type_error(address_pool, 'unsupported input type for ' + varName)
|
|
}
|
|
|
|
function crypto_generichash_blake2b_salt_personal (hash_length, message, key, salt, personal, outputFormat) {
|
|
var address_pool = []
|
|
_check_output_format(outputFormat)
|
|
|
|
// ---------- input: hash_length (uint)
|
|
|
|
_require_defined(address_pool, hash_length, 'hash_length')
|
|
|
|
if (!(typeof hash_length === 'number' && (hash_length | 0) === hash_length) && (hash_length | 0) > 0) {
|
|
_free_and_throw_type_error(address_pool, 'hash_length must be an unsigned integer')
|
|
}
|
|
|
|
// ---------- input: message (unsized_buf)
|
|
|
|
message = _any_to_Uint8Array(address_pool, message, 'message')
|
|
var message_address = _to_allocated_buf_address(message)
|
|
var message_length = message.length
|
|
address_pool.push(message_address)
|
|
|
|
// ---------- input: key (unsized_buf_optional)
|
|
|
|
var key_address = null
|
|
var key_length = 0
|
|
if (key !== undefined) {
|
|
key = _any_to_Uint8Array(address_pool, key, 'key')
|
|
key_address = _to_allocated_buf_address(key)
|
|
key_length = key.length
|
|
address_pool.push(key_address)
|
|
}
|
|
|
|
// ---------- input: salt (buf_optional)
|
|
|
|
var salt_address = null
|
|
if (salt !== undefined) {
|
|
salt = _any_to_Uint8Array(address_pool, salt, 'salt')
|
|
var salt_length = (libsodium._crypto_generichash_blake2b_saltbytes()) | 0
|
|
if (key.length !== salt_length) {
|
|
_free_and_throw_type_error(address_pool, 'invalid salt length')
|
|
}
|
|
salt_address = _to_allocated_buf_address(salt)
|
|
address_pool.push(salt_address)
|
|
}
|
|
|
|
// ---------- input: personal (buf_optional)
|
|
|
|
var personal_address = null
|
|
if (personal !== undefined) {
|
|
personal = _any_to_Uint8Array(address_pool, personal, 'personal')
|
|
var personal_length = (libsodium._crypto_generichash_blake2b_personalbytes()) | 0
|
|
if (personal.length !== personal_length) {
|
|
_free_and_throw_type_error(address_pool, 'invalid personal length')
|
|
}
|
|
personal_address = _to_allocated_buf_address(personal)
|
|
address_pool.push(personal_address)
|
|
}
|
|
|
|
// ---------- output hash (buf)
|
|
|
|
hash_length = (hash_length) | 0
|
|
var hash = new AllocatedBuf(hash_length)
|
|
var hash_address = hash.address
|
|
|
|
address_pool.push(hash_address)
|
|
|
|
if ((libsodium._crypto_generichash_blake2b_salt_personal(hash_address, hash_length, message_address, message_length, 0, key_address, key_length, salt_address, personal_address) | 0) === 0) {
|
|
var ret = _format_output(hash, outputFormat)
|
|
_free_all(address_pool)
|
|
return ret
|
|
}
|
|
_free_and_throw_error(address_pool)
|
|
}
|
|
|
|
module.exports = {
|
|
crypto_generichash_blake2b_salt_personal: crypto_generichash_blake2b_salt_personal
|
|
}
|