pull/1/head
Avril 4 years ago
parent 030b0f000d
commit c5131764c2
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -1,15 +1,207 @@
* libkhash - kana-hash * libkhash - kana-hash
Kana mnemonic hashes Kana mnemonic hashes
** Installation
The dynamic library is built with ~Cargo~ and ~Rust~, and the cli example program is built with ~gcc~.
*** Build and install
The default build configuration builds both the dynamic library and the cli example program, and copies them to =/usr/lib/libkhash.so= and =/usr/bin/kana-hash= respectively.
#+BEGIN_SRC shell
$ make && sudo make install
#+END_SRC
The install path can be changed by editing the ~INSTALL~ and ~INSTALL-BIN~ paths in the [[file:./Makefile][Makefile]].
*** Uninstall
To remove installed binaries, run:
#+BEGIN_SRC shell
$ sudo make uninstall
#+END_SRC
*** Other build configurations
The Makefile contains some other build directives.
**** Native code optimisations
By default =libkhash= builds the shared library with native architecture optimisations enabled.
If you are intending to move the binary to another architecture, this might not be desireable.
To build without such optimisations, run:
#+BEGIN_SRC shell
$ make khash-nonative
#+END_SRC
**** Tests
To build and run all tests, run:
#+BEGIN_SRC shell
$ make test
#+END_SRC
**** Building the CLI
The default =make= directive builds both the library and the CLI example program.
To build just the CLI example program, run:
#+BEGIN_SRC shell
$ cd cli && make
#+END_SRC
** TODO Rust interface ** TODO Rust interface
** C header ** C header
Documented in =./include/khash.h= A header file is provided for C programs wanting to use the khash interface.
Documented more fully in [[file:./include/khash.h][./include/khash.h]].
All symbols defined here begin with either =KHASH_= (for macros) or =khash_=.
*** Example
To create a context
#+BEGIN_SRC c
#include <khash.h>
const char* input_salt = "salt!";
const char* input_data = "some data to hash".
khash_context ctx;
assert(khash_new_context(KHASH_ALGO_SHA256, KHASH_SALT_TYPE_SPECIFIC, input_salt, strlen(input_salt), &ctx) == KHASH_SUCCESS, "khash_new_context() failed.");
#+END_SRC
Find the buffer length we need.
#+BEGIN_SRC c
size_t length;
assert(khash_length(&ctx, input_data, strlen(input_data), &length) == KHASH_SUCCESS, "khash_length() failed.");
#+END_SRC
Create the buffer and hash, then print the result to ~stdout~.
#+BEGIN_SRC c
char* buffer = alloca(length+1);
assert(khash_do(&ctx, input_data, strlen(input_data), buffer, length) == KHASH_SUCCESS, "khash_do() failed.");
buffer[length] = 0; // Ensure we have a NUL terminator.
setlocale(LC_ALL, ""); //Ensure we can print UTF-8.
printf("Kana hash: %s\n", buffer);
#+END_SRC
*** Definitions
**** Macros
All macros defined are for options.
They cannot be combied as flags.
The =KHASH_ALGO_= prefixed ones are for use as the /algo/ parameter in the ~khash_new_context()~ function.
The =KHASH_SALT_TYPE_= prefixed ones are for use as the /salt_type/ parameter.
The =KHASH_ERROR_= prefixed ones each indicate an error code returned by all of the functions.
| Name | Description |
|-------------------------------+--------------------------------------------------------------------------------------------|
| ~KHASH_ALGO_DEFAULT~ | The default algorithm used by the library (truncated SHA256) |
| ~KHASH_ALGO_CRC32~ | CRC32 checksum algorithm |
| ~KHASH_ALGO_CRC64~ | CRC64 checksum algorithm |
| ~KHASH_ALGO_SHA256~ | SHA256 hash algorithm |
| ~KHSAH_ALGO_SHA256_TRUNCATED~ | SHA256 truncated to 64-bits |
| ~KHASH_SALT_TYPE_NONE~ | No salt |
| ~KHASH_SALT_TYPE_DEFAULT~ | The default static salt used by the library |
| ~KHASH_SALT_TYPE_SPECIFIC~ | A provided salt, as the /data/ and of the /size/ parameter passed to ~khash_new_context()~ |
| ~KHASH_SALT_TYPE_RANDOM~ | A randomly generated salt |
| ~KHASH_SUCCESS~ | The code returned by all of the functions when the operation was successful |
| ~KHASH_ERROR_IO~ | There was an IO error |
| ~KHASH_ERROR_FORMAT~ | The was a text formatting related error |
| ~KHASH_ERROR_LENGTH~ | There was a hash length mismatch |
| ~KHASH_ERROR_RNG~ | The random number generator failed |
| ~KHASH_ERROR_UNKNOWN~ | There was an unknown error or the stack attempted to unwind past the FFI boundary. |
**** Types
There are 2 exported structs, although you will rarely need to access their members directly.
| Name | Field | Description |
|-----------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------|
| ~khash_salt~ | | A salt allocated into a context by ~khash_new_context()~ and released by ~khash_free_context()~. You shouldn't mess with its field directly. |
| | /salt_type/ | The type of the salt. |
| | /size/ | The size of the salt. |
| | /body/ | A pointer to the body of the salt. (The memory allocated here is not guaranteed to be of the provided /size/.) |
|-----------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------|
| ~khash_context~ | | A context for the =khash_= functions. Allocated by ~khash_new_context()~. You can modify its fields if you want. |
| | /algo/ | The algorithm for this context. |
| | /flags/ | Placeholder for potential flags added in the future. Currently unused. |
| | /salt/ | The allocated salt. You shouldn't directly mess with this field. |
**** Functions
All defined functions return either ~KHASH_SUCCESS~ or one of the =KHASH_ERROR_= values [[Macros][above]].
| Name | Parameters | Description |
|-----------------------+------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ~khash_new_context~ | /algo/, /salt_type/, /data/, /size/, /output/ | Creates a new context for use with other =libkhash= functions. /algo/ is expected to be one of the =KHASH_ALGO_= macros listed [[Macros][above.]] Likewise /salt_type/ is expected to be one of the =KHASH_SALT_TYPE_= macros. /data/ can be ~NULL~ unless /salt_type/ is set to ~KHASH_SALT_TYPE_SPECIFIC~, in which exactly /size/ bytes are read from /data/. /output/ is expected to be a valid pointer to a currently unused `khash_context` structure. |
| ~khash_free_context~ | /ctx/ | Free a context allocated with ~khash_new_context()~. /ctx/ is expected to be a valid pointer to a currently allocated context. |
| ~khash_clone_context~ | /src/, /dst/ | Clone a context allocated with ~khash_new_context()~ into another. The newly allocated /dst/ must be properly released (with ~khash_free_context()~ or ~khash_do()~) as well as the source. /src/ is expected to be a valid pointer to an allocated context, and /dst/ is expected to be a valid pointer to an unallocated context. |
| ~khash_length~ | /ctx/, /data/, /size/, /length/ | Compute the length required to hold the output string for ~khash_do()~ for a given input. Will read exactly /size/ bytes from /data/ and compute the value into what is pointed to by /length/ (which is expected to be a valid pointer to a type of ~size_t~.) The resulting length does not include a =NUL= terminator for the string. |
| ~khash_do~ | /ctx/, /data/, /size/, /output/, /output_size/ | Compute the kana-hash of /size/ bytes from /data/ and store no more than /output_size/ of the the result into the string pointed to by /output/. Each pointer is expected to be valid. This function frees the supplied /ctx/ after the hash has been computed, and thus /ctx/ is no longer valid afterwards. |
** Node FFI bindings ** Node FFI bindings
NPM package in =./node= NPM package in [[file:./node/index.js][./node]]
*** Installation (npm)
Follow the [[installation]] section first.
#+BEGIN_SRC shell
$ npm install --save /path/to/repo/node
#+END_SRC
*** Examples
**** Import the package
#+BEGIN_SRC javascript
const hash = require('kana-hash');
#+END_SRC
**** Create a context
Create the context by specifying an algorithm identifier, and an optional salt.
If provided, the salt must be of type `Salt`.
#+BEGIN_SRC javascript
const ctx = new hash.Kana(hash.Kana.ALGO_DEFAULT, new hash.Salt("optional salt~"));
#+END_SRC
**** Create a hash
The `once()` function consumes the context and outputs a hash string.
#+BEGIN_SRC javascript
const output = ctx.once("input string");
#+END_SRC
***** Creating a hash without consuming
If you want to reuse the context, use the `hash()` function.
#+BEGIN_SRC javascript
const output = ctx.hash("input string");
#+END_SRC
***** Freeing the context
The context must be release after use if you have not called `once()`.
#+BEGIN_SRC javascript
ctx.finish();
#+END_SRC
***** Cloning an existing context
The new context must also be freed with either `once()` or `finish()`.
#+BEGIN_SRC javascript
const new_ctx = ctx.clone();
#+END_SRC
*** Interface documentation
The 2 exported objects are ~Kana~ and ~Salt~.
~Kana~'s constructor expects between 0 and 2 arguments.
+ The first is either an [[Defined constants][algorithm definition]] or empty, if empty ~Kana~ uses the default algorithm (truncated SHA256).
+ The second is either an instance of ~Salt~ or empty, if empty ~Kana~ uses the default library salt.
~Salt~'s constructor expects 0 or 1 argument.
+ Either a string to use as the specific salt or empty, if empty there is no salt.
**** Defined constants
| Name | Type | Description |
|------------------------------+----------------------+--------------------------------------------------------------------------|
| ~Kana.ALGO_DEFAULT~ | Algorithm definition | The default algorithm specified by the library (set to sha256 truncated) |
| ~Kana.ALGO_CRC32~ | Algorithm definition | CRC32 checksum algorithm |
| ~Kana.ALGO_CRC64~ | Algorithm definition | CRC64 checksum algorithm |
| ~Kana.ALGO_SHA256~ | Algorithm definition | SHA256 hashing algorithm |
| ~Kana.ALGO_SHA256_TRUNCATED~ | Algorithm definition | Truncated SHA256 algorithm, to 64-bits |
| ~Salt.None~ | Salt | No salt |
| ~Salt.Random~ | Salt | A cryptographically secure random salt |
| ~Salt.Default~ | Salt | The library's default static salt |
** Notes
The strings generated by this library are meant to be pretty, not secure. It is not a secure way of representing a hash as many collisions are possible.
** TODO Documentation *** TODO Digest algorithm
** License ** License
GPL'd with <3 GPL'd with <3

@ -84,4 +84,6 @@ extern "C" {
} }
#endif #endif
#undef _deprecated
#endif /* _KHASH_H */ #endif /* _KHASH_H */

@ -1,11 +1,5 @@
const ffi = require('ffi');
const struct = require('ref-struct');
const ref = require('ref');
const Kana = require('./kana'); const Kana = require('./kana');
const Salt = require('./salt'); const Salt = require('./salt');
//console.log(new Kana(Kana.CRC64, new Salt("hello lolis")).once("hello worldチそぬとね"));
exports.Kana = Kana; exports.Kana = Kana;
exports.Salt = Salt; exports.Salt = Salt;

@ -69,44 +69,63 @@ const get_salt_type = (salt) => {
else return Kana.SALT_DEFAULT; else return Kana.SALT_DEFAULT;
}; };
/// Create a new kana-hash context.
/// This context must be disposed of correctly either by calling `finish()` or `once()`.
/// `algo` is expected to be one of the `Kana.ALGO_*` constants, or `undefined`.
/// `salt` is expected to be either an object of `Salt` or `undefined`.
function Kana(algo, salt) function Kana(algo, salt)
{ {
if(algo && algo.ctx) {
this.ctx = algo.ctx;
} else {
const stype = get_salt_type(salt); const stype = get_salt_type(salt);
const fbuffer = salt ? salt.buffer || null : null; const fbuffer = salt ? salt.buffer || null : null;
this.ctx = ctx_create(algo || 0, stype, fbuffer, fbuffer ? fbuffer.length : 0); this.ctx = ctx_create(algo || 0, stype, fbuffer, fbuffer ? fbuffer.length : 0);
} }
}
const K = Kana.prototype; const K = Kana.prototype;
/// Free the associated context.
/// The object is no longer valid after this call.
K.finish = function() { K.finish = function() {
ctx_free(this.ctx); ctx_free(this.ctx);
this.ctx = null;
}; };
/// Compute the kana-hash for `string` and then free the associated context.
K.once = function(string) { K.once = function(string) {
let len = khash_length(this.ctx, string); let len = khash_length(this.ctx, string);
return khash_do(this.ctx, string, len); return khash_do(this.ctx, string, len);
}; };
/// Compute the kana-hash for `string`.
K.hash = function(string) {
const ctx = ctx_clone(this.ctx);
let len = khash_length(ctx, string);
return khash_do(ctx, string, len);
};
/// Clone this kana-hash context.
K.clone = function() {
const ctx = ctx_clone(this.ctx);
return new Kana({ctx: ctx});
};
/// The default algorithm used. (sha256 truncated.)
Kana.ALGO_DEFAULT = 0; Kana.ALGO_DEFAULT = 0;
/// CRC32 algorithm.
Kana.ALGO_CRC32 = 1; Kana.ALGO_CRC32 = 1;
/// CRC64 algorithm.
Kana.ALGO_CRC64 = 2; Kana.ALGO_CRC64 = 2;
/// SHA256 algorithm.
Kana.ALGO_SHA256 = 3; Kana.ALGO_SHA256 = 3;
/// SHA256 truncated to 64-bits.
Kana.ALGO_SHA256_TRUNCATED = 4; Kana.ALGO_SHA256_TRUNCATED = 4;
// You don't need to reference these directly, use the `Salt` module instead.
Kana.SALT_NONE = 0; Kana.SALT_NONE = 0;
Kana.SALT_DEFAULT = 1; Kana.SALT_DEFAULT = 1;
Kana.SALT_SPECIFIC = 2; Kana.SALT_SPECIFIC = 2;
Kana.SALT_RANDOM = 3; Kana.SALT_RANDOM = 3;
module.exports = Kana; module.exports = Kana;
/*
const Kana = require('./kana');
let buffer= ref.alloc('long');
let sz = ref.alloc('long');
console.log(libhkana._kana_length(buffer, 2, null, sz));
console.log(sz.deref());
let output = new Buffer(sz);
console.log(libhkana._kana_do(buffer, 2, null, output, sz));
console.log(ref.readCString(output, 0));*/

@ -1,6 +1,6 @@
{ {
"name": "kana-hash", "name": "kana-hash",
"version": "1.1.0", "version": "1.2.0",
"description": "Kana hashes", "description": "Kana hashes",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

@ -1,5 +1,6 @@
const ref = require('ref'); const ref = require('ref');
/// Create a new salt from the string `buffer`.
function Salt(buffer, tag) function Salt(buffer, tag)
{ {
this.tag = tag || '__SPECIFIC'; this.tag = tag || '__SPECIFIC';
@ -7,11 +8,15 @@ function Salt(buffer, tag)
this.buffer = ref.allocCString(buffer); this.buffer = ref.allocCString(buffer);
} else { } else {
this.buffer = null; this.buffer = null;
this.tag = '__NONE';
} }
} }
/// No salt.
Salt.None = new Salt(null, '__NONE'); Salt.None = new Salt(null, '__NONE');
/// A randomly generated salt.
Salt.Random = new Salt(null, '__RANDOM'); Salt.Random = new Salt(null, '__RANDOM');
/// The static default salt.
Salt.Default = new Salt(null, '__DEFAULT'); Salt.Default = new Salt(null, '__DEFAULT');
module.exports = Salt; module.exports = Salt;

Loading…
Cancel
Save