diff options
-rw-r--r-- | chksum.c | 112 | ||||
-rw-r--r-- | chksum.h | 6 | ||||
-rw-r--r-- | txr.1 | 112 |
3 files changed, 230 insertions, 0 deletions
@@ -48,6 +48,8 @@ #include "chksums/md5.h" #include "chksum.h" +static val sha256_ctx_s, md5_ctx_s; + static void sha256_stream_impl(val stream, val nbytes, unsigned char *hash) { SHA256_t s256; @@ -165,6 +167,57 @@ val sha256(val obj, val buf_in) } } +static struct cobj_ops sha256_ops = cobj_ops_init(cobj_equal_handle_op, + cobj_print_op, + cobj_destroy_free_op, + cobj_mark_op, + cobj_handle_hash_op); +val sha256_begin(void) +{ + SHA256_t *ps256 = coerce(SHA256_t *, chk_malloc(sizeof *ps256)); + SHA256_init(ps256); + return cobj(coerce(mem_t *, ps256), sha256_ctx_s, &sha256_ops); +} + +val sha256_hash(val ctx, val obj) +{ + val self = lit("sha256-hash"); + SHA256_t *ps256 = coerce(SHA256_t *, cobj_handle(self, ctx, sha256_ctx_s)); + + switch (type(obj)) { + case STR: + case LSTR: + case LIT: + { + char *str = utf8_dup_to(c_str(obj)); + SHA256_update(ps256, coerce(const unsigned char *, str), strlen(str)); + free(str); + } + break; + case BUF: + SHA256_update(ps256, obj->b.data, c_unum(obj->b.len)); + break; + default: + uw_throwf(error_s, lit("~a: cannot hash ~s, only buffer and strings"), + self, obj, nao); + } + + return obj; +} + +val sha256_end(val ctx, val buf_in) +{ + val self = lit("sha256-end"); + unsigned char *hash; + SHA256_t *ps256 = coerce(SHA256_t *, cobj_handle(self, ctx, sha256_ctx_s)); + val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA256_DIGEST_LENGTH), + &hash, lit("SHA-256")); + + SHA256_final(ps256, hash); + SHA256_init(ps256); + return buf; +} + val crc32_stream(val stream, val nbytes) { u32_t crc = 0; @@ -351,12 +404,71 @@ val md5(val obj, val buf_in) } } +static struct cobj_ops md5_ops = cobj_ops_init(cobj_equal_handle_op, + cobj_print_op, + cobj_destroy_free_op, + cobj_mark_op, + cobj_handle_hash_op); +val md5_begin(void) +{ + MD5_t *pmd5 = coerce(MD5_t *, chk_malloc(sizeof *pmd5)); + MD5_init(pmd5); + return cobj(coerce(mem_t *, pmd5), md5_ctx_s, &md5_ops); +} + +val md5_hash(val ctx, val obj) +{ + val self = lit("md5-hash"); + MD5_t *pmd5 = coerce(MD5_t *, cobj_handle(self, ctx, md5_ctx_s)); + + switch (type(obj)) { + case STR: + case LSTR: + case LIT: + { + char *str = utf8_dup_to(c_str(obj)); + MD5_update(pmd5, coerce(const unsigned char *, str), strlen(str)); + free(str); + } + break; + case BUF: + MD5_update(pmd5, obj->b.data, c_unum(obj->b.len)); + break; + default: + uw_throwf(error_s, lit("~a: cannot hash ~s, only buffer and strings"), + self, obj, nao); + } + + return obj; +} + +val md5_end(val ctx, val buf_in) +{ + val self = lit("md5-end"); + unsigned char *hash; + MD5_t *pmd5 = coerce(MD5_t *, cobj_handle(self, ctx, md5_ctx_s)); + val buf = chksum_ensure_buf(self, buf_in, num_fast(MD5_DIGEST_LENGTH), + &hash, lit("SHA-256")); + + MD5_final(pmd5, hash); + MD5_init(pmd5); + return buf; +} + void chksum_init(void) { + sha256_ctx_s = intern(lit("sha256-ctx"), user_package); + md5_ctx_s = intern(lit("md5-ctx"), user_package); reg_fun(intern(lit("sha256-stream"), user_package), func_n3o(sha256_stream, 1)); reg_fun(intern(lit("sha256"), user_package), func_n2o(sha256, 1)); + reg_fun(intern(lit("sha256-begin"), user_package), func_n0(sha256_begin)); + reg_fun(intern(lit("sha256-hash"), user_package), func_n2(sha256_hash)); + reg_fun(intern(lit("sha256-end"), user_package), func_n2o(sha256_end, 1)); reg_fun(intern(lit("crc32-stream"), user_package), func_n2o(crc32_stream, 1)); reg_fun(intern(lit("crc32"), user_package), func_n1(crc32)); reg_fun(intern(lit("md5-stream"), user_package), func_n3o(md5_stream, 1)); reg_fun(intern(lit("md5"), user_package), func_n2o(md5, 1)); + reg_fun(intern(lit("md5-begin"), user_package), func_n0(md5_begin)); + reg_fun(intern(lit("md5-hash"), user_package), func_n2(md5_hash)); + reg_fun(intern(lit("md5-end"), user_package), func_n2o(md5_end, 1)); } @@ -27,8 +27,14 @@ val sha256_stream(val stream, val nbytes, val buf); val sha256(val obj, val buf); +val sha256_begin(void); +val sha256_hash(val ctx, val obj); +val sha256_end(val ctx, val buf); val crc32_stream(val stream, val nbytes); val crc32(val obj); val md5_stream(val stream, val nbytes, val buf); val md5(val obj, val buf_in); +val md5_begin(void); +val md5_hash(val ctx, val obj); +val md5_end(val ctx, val buf); void chksum_init(void); @@ -52382,6 +52382,118 @@ argument is specified, it must be a buffer that is at least 16 bytes long in the case of MD5, and at least 32 bytes long in the case of SHA-256. The hash is placed into that buffer, which is then returned. +.coNP Functions @, sha256-begin @ sha256-hash and @ sha256-end +.synb +.mets (sha256-begin) +.mets (sha256-hash < ctx << obj ) +.mets (sha256-end < ctx <> [ buf ]) +.syne +.desc +The three functions +.codn sha256-begin , +.code sha256-hash +and +.code sha256-end +implement a stateful computation of SHA256 digest which allows multiple input +sources to contribute to the result. Furthermore, the context object may be +serially re-used for calculating multiple digests. + +The +.code sha256-begin +function, which takes no arguments, returns a new SHA256 digest-producing +context object. + +The +.code sha256-hash +updates the state of the SHA256 digest object +.meta ctx +by including +.meta obj +into the digest calculation. The +.meta obj +argument may be a character string, whose UTF-8 representation is digested, +or a buffer object, whose contents are digested. +The +.code sha256-hash +function may be called multiple times to include any mixture of +strings and buffers into the digest calculation. + +The +.code sha256-end +function finalizes the digest calculation and returns the digest in +a buffer. If the +.meta buf +argument is omitted, then a new 32-byte buffer is created for this +purpose. Otherwise, +.meta buf +must specify a +.code buf +object that is at least 32 bytes long. The digest is stored into this +buffer and that the buffer is returned. + +The +.code sha256-end +function additionally resets the +.meta ctx +object into the initial state of a newly created context object, so +that it may be used for another digest session. + +.coNP Functions @, md5-begin @ md5-hash and @ md5-end +.synb +.mets (md5-begin) +.mets (md5-hash < ctx << obj ) +.mets (md5-end < ctx <> [ buf ]) +.syne +.desc +The three functions +.codn md5-begin , +.code md5-hash +and +.code md5-end +implement a stateful computation of MD5 digest which allows multiple input +sources to contribute to the result. Furthermore, the context object may be +serially re-used for calculating multiple digests. + +The +.code md5-begin +function, which takes no arguments, returns a new MD5 digest-producing +context object. + +The +.code md5-hash +updates the state of the MD5 digest object +.meta ctx +by including +.meta obj +into the digest calculation. The +.meta obj +argument may be a character string, whose UTF-8 representation is digested, +or a buffer object, whose contents are digested. +The +.code md5-hash +function may be called multiple times to include any mixture of +strings and buffers into the digest calculation. + +The +.code md5-end +function finalizes the digest calculation and returns the digest in +a buffer. If the +.meta buf +argument is omitted, then a new 16-byte buffer is created for this +purpose. Otherwise, +.meta buf +must specify a +.code buf +object that is at least 16 bytes long. The digest is stored into this +buffer and that the buffer is returned. + +The +.code md5-end +function additionally resets the +.meta ctx +object into the initial state of a newly created context object, so +that it may be used for another digest session. + .SS* The Awk Utility The \*(TL library provides a macro called |