diff --git a/DESCRIPTION b/DESCRIPTION index 9446a97..900b74e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: secretbase Type: Package Title: Cryptographic Hash and Extendable-Output Functions -Version: 0.3.0.9007 +Version: 0.3.0.9008 Description: Fast and memory-efficient streaming hash functions. Performs direct hashing of strings, raw bytes, and files potentially larger than memory, as well as hashing in-memory objects through R's serialization mechanism, diff --git a/NAMESPACE b/NAMESPACE index 586a474..0be9c2c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,5 +3,4 @@ export(sha256) export(sha3) export(siphash13) -export(siphash24) useDynLib(secretbase, .registration = TRUE) diff --git a/NEWS.md b/NEWS.md index 3d61ab0..36ea353 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# secretbase 0.3.0.9007 (development) +# secretbase 0.3.0.9008 (development) * Adds HMAC generation to `sha256()`. * Adds SipHash pseudo-random function (PRF) as a fast, cryptographically-strong keyed hash. diff --git a/R/base.R b/R/base.R index 931409a..0e5750a 100644 --- a/R/base.R +++ b/R/base.R @@ -147,9 +147,8 @@ sha256 <- function(x, key = NULL, convert = TRUE, file) #' SipHash Pseudorandom Function #' #' Returns a fast, cryptographically-strong SipHash keyed hash of the supplied -#' object or file. SipHash-1-3 is optimised for performance, whereas -#' SipHash-2-4 is recommended for security. Note: SipHash is not a -#' cryptographic hash algorithm. +#' object or file. SipHash-1-3 is optimised for performance. Note: SipHash +#' is not a cryptographic hash algorithm. #' #' @inheritParams sha3 #' @param key [default NULL] a character string or raw vector comprising the 16 @@ -179,11 +178,11 @@ sha256 <- function(x, key = NULL, convert = TRUE, file) #' # SipHash-1-3 hash as raw vector: #' siphash13("secret base", convert = FALSE) #' -#' # SipHash-2-4 hash using a character string key: -#' siphash24("secret", key = "base") +#' # SipHash-1-3 hash using a character string key: +#' siphash13("secret", key = "base") #' -#' # SipHash-2-4 hash using a raw vector key: -#' siphash24("secret", key = charToRaw("base")) +#' # SipHash-1-3 hash using a raw vector key: +#' siphash13("secret", key = charToRaw("base")) #' #' # SipHash-1-3 hash a file: #' file <- tempfile(); cat("secret base", file = file) @@ -195,10 +194,3 @@ sha256 <- function(x, key = NULL, convert = TRUE, file) siphash13 <- function(x, key = NULL, convert = TRUE, file) if (missing(file)) .Call(secretbase_siphash13, x, key, convert) else .Call(secretbase_siphash13_file, file, key, convert) - -#' @rdname siphash13 -#' @export -#' -siphash24 <- function(x, key = NULL, convert = TRUE, file) - if (missing(file)) .Call(secretbase_siphash24, x, key, convert) else - .Call(secretbase_siphash24_file, file, key, convert) diff --git a/README.Rmd b/README.Rmd index 4613d66..868b1e0 100644 --- a/README.Rmd +++ b/README.Rmd @@ -47,14 +47,16 @@ install.packages("secretbase", repos = "https://shikokuchuo.r-universe.dev") ### Quick Start -#### SHA-3 and XOF usage: +```{r secretbase} +library(secretbase) +``` + +#### SHA-3 - For the SHA-3 cryptographic hash algorithm, specify 'bits' as `224`, `256`, `384` or `512` - For the SHAKE256 extendable-output function (XOF), specify any other bit length -```{r secretbase} -library(secretbase) - +```{r sha3} sha3("secret base") sha3("secret base", convert = FALSE) @@ -63,9 +65,10 @@ sha3("秘密の基地の中", bits = 512) ``` -#### Hash arbitrary R objects: +#### Hash arbitrary R objects - - Uses memory-efficient 'streaming' serialization, without allocation of the serialized object + - Character strings and raw vectors (without attributes) are hashed 'as is' + - Other objects are hashed using memory-efficient 'streaming' serialization, without allocation of the serialized object - Portable as always uses R serialization version 3 big-endian representation, skipping headers (which contain R version and native encoding information) ```{r streaming} @@ -74,7 +77,7 @@ sha3(data.frame(a = 1, b = 2), bits = 160) sha3(NULL) ``` -#### Hash files: +#### Hash files - Performed in a streaming fashion, accepting files larger than memory @@ -86,7 +89,7 @@ sha3(file = file) unlink(file) ``` -#### Hash to integer: +#### Hash to integer - Specify 'convert' as `NA` (and 'bits' as `32` for a single integer value) - May be supplied as deterministic random seeds for R's pseudo random number generators (RNGs) @@ -99,24 +102,25 @@ sha3("秘密の基地の中", bits = 32, convert = NA) For use in parallel computing, this is a valid method for reducing to a negligible probability that RNGs in each process may overlap. This may be especially suitable when first-best alternatives such as using recursive streams are too expensive or unable to preserve reproducibility. [2] -#### Generating a SHA-256 HMAC: +#### SHA-256 -- Use `sha256()` passing a character string or raw vector to 'key'. +```{r sha256} +sha256("secret base") +``` + +- For a SHA-256 HMAC, pass a character string or raw vector to 'key' ```{r hmac} sha256("secret base", key = "秘密の基地の中") ``` -#### Using SipHash: +#### SipHash -- SipHash is a fast, cryptographically-strong keyed hash. -- Pass a character string or raw vector to 'key'. Up to 16 bytes (128 bits) of the key data is used. -- SipHash-1-3 is optimized for performance; SipHash-2-4 recommended for security. +- SipHash-1-3 is optimized for performance +- Pass a character string or raw vector to 'key' - up to 16 bytes (128 bits) of the key data is used ```{r siphash} siphash13("secret base", key = charToRaw("秘密の基地の中")) - -siphash24("secret base", key = charToRaw("秘密の基地の中")) ``` ### References diff --git a/README.md b/README.md index 0f23bbf..c4f218e 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,11 @@ install.packages("secretbase", repos = "https://shikokuchuo.r-universe.dev") ### Quick Start -#### SHA-3 and XOF usage: +``` r +library(secretbase) +``` + +#### SHA-3 - For the SHA-3 cryptographic hash algorithm, specify ‘bits’ as `224`, `256`, `384` or `512` @@ -65,8 +69,6 @@ install.packages("secretbase", repos = "https://shikokuchuo.r-universe.dev") bit length ``` r -library(secretbase) - sha3("secret base") #> [1] "a721d57570e7ce366adee2fccbe9770723c6e3622549c31c7cab9dbb4a795520" @@ -78,10 +80,12 @@ sha3("秘密の基地の中", bits = 512) #> [1] "e30cdc73f6575c40d55b5edc8eb4f97940f5ca491640b41612e02a05f3e59dd9c6c33f601d8d7a8e2ca0504b8c22f7bc69fa8f10d7c01aab392781ff4ae1e610" ``` -#### Hash arbitrary R objects: +#### Hash arbitrary R objects -- Uses memory-efficient ‘streaming’ serialization, without allocation of - the serialized object +- Character strings and raw vectors (without attributes) are hashed ‘as + is’ +- Other objects are hashed using memory-efficient ‘streaming’ + serialization, without allocation of the serialized object - Portable as always uses R serialization version 3 big-endian representation, skipping headers (which contain R version and native encoding information) @@ -94,7 +98,7 @@ sha3(NULL) #> [1] "b3e37e4c5def1bfb2841b79ef8503b83d1fed46836b5b913d7c16de92966dcee" ``` -#### Hash files: +#### Hash files - Performed in a streaming fashion, accepting files larger than memory @@ -104,7 +108,7 @@ sha3(file = file) #> [1] "a721d57570e7ce366adee2fccbe9770723c6e3622549c31c7cab9dbb4a795520" ``` -#### Hash to integer: +#### Hash to integer - Specify ‘convert’ as `NA` (and ‘bits’ as `32` for a single integer value) @@ -126,29 +130,29 @@ be especially suitable when first-best alternatives such as using recursive streams are too expensive or unable to preserve reproducibility. \[2\] -#### Generating a SHA-256 HMAC: +#### SHA-256 -- Use `sha256()` passing a character string or raw vector to ‘key’. +``` r +sha256("secret base") +#> [1] "1951c1ca3d50e95e6ede2b1c26fefd0f0e8eba1e51a837f8ccefb583a2b686fe" +``` + +- For a SHA-256 HMAC, pass a character string or raw vector to ‘key’ ``` r sha256("secret base", key = "秘密の基地の中") #> [1] "ec58099ab21325e792bef8f1aafc0a70e1a7227463cfc410931112705d753392" ``` -#### Using SipHash: +#### SipHash -- SipHash is a fast, cryptographically-strong keyed hash. -- Pass a character string or raw vector to ‘key’. Up to 16 bytes (128 - bits) of the key data is used. -- SipHash-1-3 is optimized for performance; SipHash-2-4 recommended for - security. +- SipHash-1-3 is optimized for performance +- Pass a character string or raw vector to ‘key’ - up to 16 bytes (128 + bits) of the key data is used ``` r siphash13("secret base", key = charToRaw("秘密の基地の中")) #> [1] "a1f0a751892cc7dd" - -siphash24("secret base", key = charToRaw("秘密の基地の中")) -#> [1] "1bedfe817cac0562" ``` ### References diff --git a/man/siphash13.Rd b/man/siphash13.Rd index 9899b51..fd73a78 100644 --- a/man/siphash13.Rd +++ b/man/siphash13.Rd @@ -2,12 +2,9 @@ % Please edit documentation in R/base.R \name{siphash13} \alias{siphash13} -\alias{siphash24} \title{SipHash Pseudorandom Function} \usage{ siphash13(x, key = NULL, convert = TRUE, file) - -siphash24(x, key = NULL, convert = TRUE, file) } \arguments{ \item{x}{object to hash. A character string or raw vector (without @@ -35,9 +32,8 @@ A character string, raw or integer vector depending on 'convert'. } \description{ Returns a fast, cryptographically-strong SipHash keyed hash of the supplied - object or file. SipHash-1-3 is optimised for performance, whereas - SipHash-2-4 is recommended for security. Note: SipHash is not a - cryptographic hash algorithm. + object or file. SipHash-1-3 is optimised for performance. Note: SipHash + is not a cryptographic hash algorithm. } \details{ The SipHash family of cryptographically-strong pseudorandom @@ -59,11 +55,11 @@ siphash13("secret base") # SipHash-1-3 hash as raw vector: siphash13("secret base", convert = FALSE) -# SipHash-2-4 hash using a character string key: -siphash24("secret", key = "base") +# SipHash-1-3 hash using a character string key: +siphash13("secret", key = "base") -# SipHash-2-4 hash using a raw vector key: -siphash24("secret", key = charToRaw("base")) +# SipHash-1-3 hash using a raw vector key: +siphash13("secret", key = charToRaw("base")) # SipHash-1-3 hash a file: file <- tempfile(); cat("secret base", file = file) diff --git a/src/init.c b/src/init.c index 412f5eb..c5031ad 100644 --- a/src/init.c +++ b/src/init.c @@ -25,8 +25,6 @@ static const R_CallMethodDef callMethods[] = { {"secretbase_sha256_file", (DL_FUNC) &secretbase_sha256_file, 3}, {"secretbase_siphash13", (DL_FUNC) &secretbase_siphash13, 3}, {"secretbase_siphash13_file", (DL_FUNC) &secretbase_siphash13_file, 3}, - {"secretbase_siphash24", (DL_FUNC) &secretbase_siphash24, 3}, - {"secretbase_siphash24_file", (DL_FUNC) &secretbase_siphash24_file, 3}, {NULL, NULL, 0} }; diff --git a/src/secret.h b/src/secret.h index a865eda..752d211 100644 --- a/src/secret.h +++ b/src/secret.h @@ -93,7 +93,6 @@ typedef struct secretbase_sha256_context { typedef struct secretbase_siphash_context { int skip; - unsigned N; CSipHash *ctx; } secretbase_siphash_context; diff --git a/src/secret3.c b/src/secret3.c index 758c4d4..a534102 100644 --- a/src/secret3.c +++ b/src/secret3.c @@ -107,7 +107,7 @@ void c_siphash_init_nokey(CSipHash *state) { } -static inline void c_siphash_append_N(CSipHash *state, const uint8_t *bytes, size_t n_bytes, unsigned N) { +static inline void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes) { const uint8_t *end = bytes + n_bytes; size_t left = state->n_bytes & 7; @@ -123,8 +123,7 @@ static inline void c_siphash_append_N(CSipHash *state, const uint8_t *bytes, siz return; state->v3 ^= state->padding; - for (unsigned i = 0; i < N; i++) - c_siphash_sipround(state); + c_siphash_sipround(state); state->v0 ^= state->padding; state->padding = 0; @@ -136,8 +135,7 @@ static inline void c_siphash_append_N(CSipHash *state, const uint8_t *bytes, siz m = c_siphash_read_le64(bytes); state->v3 ^= m; - for (unsigned i = 0; i < N; i++) - c_siphash_sipround(state); + c_siphash_sipround(state); state->v0 ^= m; } @@ -163,20 +161,19 @@ static inline void c_siphash_append_N(CSipHash *state, const uint8_t *bytes, siz } -static inline uint64_t c_siphash_finalize_NM(CSipHash *state, unsigned N, unsigned M) { +static inline uint64_t c_siphash_finalize(CSipHash *state) { uint64_t b; b = state->padding | (((uint64_t) state->n_bytes) << 56); state->v3 ^= b; - for (unsigned i = 0; i < N; i++) - c_siphash_sipround(state); + c_siphash_sipround(state); state->v0 ^= b; state->v2 ^= 0xff; - for (unsigned i = 0; i < M; i++) + for (unsigned i = 0; i < 3; i++) c_siphash_sipround(state); return state->v0 ^ state->v1 ^ state->v2 ^ state->v3; @@ -188,11 +185,11 @@ static inline uint64_t c_siphash_finalize_NM(CSipHash *state, unsigned N, unsign static void hash_bytes(R_outpstream_t stream, void *src, int len) { secretbase_siphash_context *sctx = (secretbase_siphash_context *) stream->data; - sctx->skip ? (void) sctx->skip-- : c_siphash_append_N(sctx->ctx, (uint8_t *) src, (size_t) len, sctx->N); + sctx->skip ? (void) sctx->skip-- : c_siphash_append(sctx->ctx, (uint8_t *) src, (size_t) len); } -static void hash_file(CSipHash *ctx, const SEXP x, const unsigned N) { +static void hash_file(CSipHash *ctx, const SEXP x) { if (TYPEOF(x) != STRSXP) Rf_error("'file' must be specified as a character string"); @@ -204,10 +201,8 @@ static void hash_file(CSipHash *ctx, const SEXP x, const unsigned N) { if ((f = fopen(file, "rb")) == NULL) Rf_error("file not found or no read permission at '%s'", file); - setbuf(f, NULL); - while ((cur = fread(buf, sizeof(char), SB_BUF_SIZE, f))) { - c_siphash_append_N(ctx, buf, cur, N); + c_siphash_append(ctx, buf, cur); } if (ferror(f)) { @@ -218,19 +213,19 @@ static void hash_file(CSipHash *ctx, const SEXP x, const unsigned N) { } -static void hash_object(CSipHash *ctx, const SEXP x, const unsigned N) { +static void hash_object(CSipHash *ctx, const SEXP x) { switch (TYPEOF(x)) { case STRSXP: if (XLENGTH(x) == 1 && ATTRIB(x) == R_NilValue) { const char *s = CHAR(STRING_ELT(x, 0)); - c_siphash_append_N(ctx, (uint8_t *) s, strlen(s), N); + c_siphash_append(ctx, (uint8_t *) s, strlen(s)); return; } break; case RAWSXP: if (ATTRIB(x) == R_NilValue) { - c_siphash_append_N(ctx, (uint8_t *) STDVEC_DATAPTR(x), (size_t) XLENGTH(x), N); + c_siphash_append(ctx, (uint8_t *) STDVEC_DATAPTR(x), (size_t) XLENGTH(x)); return; } break; @@ -238,7 +233,6 @@ static void hash_object(CSipHash *ctx, const SEXP x, const unsigned N) { secretbase_siphash_context sctx; sctx.skip = SB_SERIAL_HEADERS; - sctx.N = N; sctx.ctx = ctx; struct R_outpstream_st output_stream; @@ -257,8 +251,7 @@ static void hash_object(CSipHash *ctx, const SEXP x, const unsigned N) { } static SEXP secretbase_siphash_impl(const SEXP x, const SEXP key, const SEXP convert, - void (*const hash_func)(CSipHash *, SEXP, unsigned), - const unsigned N, const unsigned M) { + void (*const hash_func)(CSipHash *, SEXP)) { const int conv = LOGICAL(convert)[0]; uint64_t hash; @@ -286,9 +279,8 @@ static SEXP secretbase_siphash_impl(const SEXP x, const SEXP key, const SEXP con memcpy(seed, data, klen < SB_SKEY_SIZE ? klen : SB_SKEY_SIZE); c_siphash_init(&ctx, seed); } - hash_func(&ctx, x, N); - hash = c_siphash_finalize_NM(&ctx, N, M); - clear_buffer(&ctx, sizeof(CSipHash)); + hash_func(&ctx, x); + hash = c_siphash_finalize(&ctx); return hash_to_sexp((unsigned char *) &hash, SB_SIPH_SIZE, conv); @@ -298,24 +290,12 @@ static SEXP secretbase_siphash_impl(const SEXP x, const SEXP key, const SEXP con SEXP secretbase_siphash13(SEXP x, SEXP key, SEXP convert) { - return secretbase_siphash_impl(x, key, convert, hash_object, 1u, 3u); + return secretbase_siphash_impl(x, key, convert, hash_object); } SEXP secretbase_siphash13_file(SEXP x, SEXP key, SEXP convert) { - return secretbase_siphash_impl(x, key, convert, hash_file, 1u, 3u); - -} - -SEXP secretbase_siphash24(SEXP x, SEXP key, SEXP convert) { - - return secretbase_siphash_impl(x, key, convert, hash_object, 2u, 4u); - -} - -SEXP secretbase_siphash24_file(SEXP x, SEXP key, SEXP convert) { - - return secretbase_siphash_impl(x, key, convert, hash_file, 2u, 4u); + return secretbase_siphash_impl(x, key, convert, hash_file); } diff --git a/tests/tests.R b/tests/tests.R index 7b821ff..f2168d0 100644 --- a/tests/tests.R +++ b/tests/tests.R @@ -70,11 +70,9 @@ test_equal(sha256("secret base", key = character()), "6bc4693e2025baadf345dd0b13 test_error(sha256("secret base", key = list()), "'key' must be a character string, raw vector or NULL") # SipHash tests: test_equal(siphash13(""), "2c530c1562a7fbd1") -test_equal(siphash24(""), "d70077739d4b921e") test_equal(siphash13("", key = ""), "2c530c1562a7fbd1") test_equal(siphash13("", key = character()), "2c530c1562a7fbd1") test_equal(siphash13("secret base"), "48c60a316babef0e") -test_equal(siphash24("secret base"), "bdb6899a934fdf5a") test_equal(siphash13("secret base", key = "secret base"), "2cf27a8f22f02e59") test_equal(siphash13("secret base", key = c("secret base", "more")), "2cf27a8f22f02e59") test_equal(siphash13("secret base", key = as.raw(1L)), "5ecd894f7d269521") @@ -88,14 +86,12 @@ test_equal(siphash13(NULL), "08d5f59e833de599") test_equal(siphash13(substitute()), "c8cadc1ab377142a") test_equal(siphash13(`class<-`(siphash13(character(), convert = FALSE), "hash")), "39124d8b9643418a") test_error(siphash13(file = NULL), "'file' must be specified as a character string") -hash_func <- function(file, string, func) { +hash_func <- function(file, string) { on.exit(unlink(file)) cat(string, file = file) - func(file = file) + siphash13(file = file) } -test_equal(hash_func(tempfile(), "secret base", siphash13), "48c60a316babef0e") -test_equal(hash_func(tempfile(), "secret base", siphash24), "bdb6899a934fdf5a") -test_error(hash_func("", "", siphash13), "file not found or no read permission") -test_error(hash_func("", "", siphash24), "file not found or no read permission") +test_equal(hash_func(tempfile(), "secret base"), "48c60a316babef0e") +test_error(hash_func("", ""), "file not found or no read permission") if (.Platform[["OS.type"]] == "unix") test_error(siphash13(file = "~/"), "file read error") test_equal(siphash13(paste(1:888, collapse = "")), "8337f50b05209c40")