pike.git
/
src
/
post_modules
/
Nettle
/
hash.cmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/post_modules/Nettle/hash.cmod:5:
*/ #include "global.h" #include "interpret.h" #include "svalue.h" #include "threads.h" /* For this_object() */ #include "object.h" #include "module_support.h"
+
#include "pike_memory.h"
#include "nettle_config.h" #ifdef HAVE_LIBNETTLE DECLARATIONS #include "nettle.h" #include <nettle/md5.h>
pike.git/src/post_modules/Nettle/hash.cmod:40:
va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); } #else #define werror(x) #endif
-
static struct program *Fd_ref_program = NULL;
-
static struct program *Fd_program = NULL;
-
+
/*! @module Nettle */ /*! @class HashInfo *! *! Represents information about a hash algorithm, such as *! name, digest size, and internal block size. */ PIKECLASS HashInfo { CVAR const struct nettle_hash *meta;
-
/*! @decl string name(void)
+
/*! @decl string
(0..255)
name(void)
*! *! Returns a human readable name for the algorithm. */
-
PIKEFUN string name()
+
PIKEFUN string
(0..255)
name()
optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("HashInfo not properly initialized.\n"); push_text(THIS->meta->name); }
-
/*! @decl
string
digest_size(void)
+
/*! @decl
int(0..)
digest_size(void)
*! *! Returns the size of a hash digests. */
-
PIKEFUN int digest_size()
+
PIKEFUN int
(0..)
digest_size()
optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("HashInfo not properly initialized.\n"); push_int(THIS->meta->digest_size); }
-
/*! @decl
string
block_size(void)
+
/*! @decl
int(0..)
block_size(void)
*! *! Returns the internal block size of the hash algorithm. */
-
PIKEFUN int block_size()
+
PIKEFUN int
(0..)
block_size()
optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("HashInfo not properly initialized.\n"); push_int(THIS->meta->block_size); }
-
/*! @decl string hash(string data)
+
/*! @decl string
(0..255)
hash(string data)
*! *! Works as a (faster) shortcut for *! @expr{HashState()->update(data)->digest()@}, where HashState is *! the hash state class corresponding to this HashInfo. *! *! @seealso *! @[HashState()->update()] and @[HashState()->digest()]. */
-
PIKEFUN string hash(string in)
+
PIKEFUN string
(0..255)
hash(string in)
optflags OPT_TRY_OPTIMIZE; { void *ctx; struct pike_string *out; unsigned digest_length; const struct nettle_hash *meta = THIS->meta; if (!meta) Pike_error("HashInfo not properly initialized.\n"); NO_WIDE_STRING(in);
pike.git/src/post_modules/Nettle/hash.cmod:138:
} digest_length = meta->digest_size; out = begin_shared_string(digest_length); meta->digest(ctx, digest_length, (uint8_t *)out->str); pop_n_elems(args); push_string(end_shared_string(out)); }
-
/*! @decl string hash(Stdio.File file, void|int bytes)
+
int is_stdio_file(struct object *o)
+
{
+
struct program *p = o->prog;
+
INT32 i = p->num_inherits;
+
while( i-- )
+
{
+
if( p->inherits[i].prog->id == PROG_STDIO_FD_ID ||
+
p->inherits[i].prog->id == PROG_STDIO_FD_REF_ID )
+
return 1;
+
}
+
return 0;
+
}
+
+
/*! @decl string
(0..255)
hash(Stdio.File file, void|int bytes)
*! *! Works as a (faster) shortcut for *! @expr{HashState()->update(Stdio.read_file(file))->digest()@}, *! where HashState is the hash state class corresponding to this *! HashInfo. *! *! @param bytes *! The number of bytes of the file object @[file] that should be *! hashed. Negative numbers are ignored and the whole file is *! hashed. *! *! @seealso *! @[Stdio.File], @[HashState()->update()] and *! @[HashState()->digest()]. */
-
PIKEFUN string hash(object in, void|int bytes)
+
PIKEFUN string
(0..255)
hash(object in, void|int bytes)
optflags OPT_EXTERNAL_DEPEND; { void *ctx; int len, fd; char *read_buffer; PIKE_STAT_T st; struct pike_string *out; const struct nettle_hash *meta = THIS->meta; if (!meta) Pike_error("HashInfo not properly initialized.\n");
-
/* Verify that the input is a Stdio.Fd or Stdio.Fd_ref */
-
if (!
Fd
_
program)
-
{
-
push
_
text
(
"files.Fd"
)
;
-
SAFE
_
APPLY_MASTER
("
resolv",1);
-
Fd
_program
=
program_from_svalue(Pike_sp-1);
-
if (!
Fd_
program)
{
-
pop_stack();
-
Pike_error("Unable to resolv files
.
Fd.
\n");
-
}
-
add_ref(Fd_program);
-
pop_stack( );
-
}
+
if (!
is
_
stdio
_
file
(
in
)
)
+
Pike
_
error
("
Object
not
Fd
or
Fd_
ref,
or
subclass
.\n");
-
if (!Fd_ref_program)
-
{
-
push_text("files.Fd_ref");
-
SAFE_APPLY_MASTER("resolv",1);
-
Fd_ref_program = program_from_svalue(Pike_sp-1);
-
if (!Fd_ref_program) {
-
pop_stack();
-
Pike_error("Unable to resolv files.Fd_ref.\n");
-
}
-
add_ref(Fd_ref_program);
-
pop_stack( );
-
}
-
-
if (!get_storage(in, Fd_program) && !get_storage(in, Fd_ref_program) )
-
Pike_error("Object not Fd or Fd_ref or subclass.\n");
-
-
safe_
apply(in, "query_fd", 0);
+
apply(in, "query_fd", 0);
fd = Pike_sp[-1].u.integer; pop_stack(); if (fd_fstat(fd, &st)<0) Pike_error("File not found!\n"); if (!S_ISREG(st.st_mode)) Pike_error("Non-regular file.\n"); ctx = (void *)alloca(meta->context_size);
pike.git/src/post_modules/Nettle/hash.cmod:240:
free(read_buffer); THREADS_DISALLOW(); out = begin_shared_string(meta->digest_size); meta->digest(ctx, meta->digest_size, (uint8_t *)out->str); pop_n_elems(args); push_string(end_shared_string(out)); }
+
/* NOTE: This is NOT the MIME base64 table! */
+
static const char b64tab[64] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+
static inline void b64enc(char *dest, int a, int b, int c, int sz)
+
{
+
unsigned int bitbuf = a | (b << 8) | (c << 16);
+
while (sz--) {
+
*(dest++) = b64tab[bitbuf & 63];
+
bitbuf >>= 6;
+
}
+
}
+
+
/*! @decl string(0..127) crypt_hash(string password, string salt, rounds)
+
*!
+
*! Password hashing function in @[crypt_md5()]-style.
+
*!
+
*! Implements the algorithm described in
+
*! @url{http://www.akkadia.org/drepper/SHA-crypt.txt@}.
+
*!
+
*! This is the algorithm used by @tt{crypt(2)@} in
+
*! methods @tt{$5$@} (SHA256) and @tt{$6$@} (SHA512).
+
*!
+
*! @seealso
+
*! @[crypt_md5()]
+
*/
+
PIKEFUN string(0..127) crypt_hash(string password, string salt, int rounds)
+
{
+
struct pike_string *res;
+
const struct nettle_hash *meta = THIS->meta;
+
void *ctx;
+
uint8_t *abcbuf;
+
uint8_t *dpbuf;
+
uint8_t *dsbuf;
+
+
unsigned char *p;
+
unsigned char *s;
+
int plen;
+
int slen;
+
int dsz = meta->digest_size;
+
+
int i;
+
int r;
+
+
int a, b, c;
+
+
if (!rounds) rounds = 5000;
+
if (rounds < 1000) rounds = 1000;
+
if (rounds > 999999999) rounds = 999999999;
+
+
NO_WIDE_STRING(password);
+
NO_WIDE_STRING(salt);
+
+
ctx = (void *)alloca(meta->context_size);
+
if (!ctx)
+
SIMPLE_OUT_OF_MEMORY_ERROR("crypt_hash", meta->context_size);
+
+
abcbuf = (uint8_t *)alloca(meta->digest_size * 3);
+
if (!abcbuf)
+
SIMPLE_OUT_OF_MEMORY_ERROR("crypt_hash", meta->digest_size * 3);
+
+
dpbuf = abcbuf + meta->digest_size;
+
dsbuf = dpbuf + meta->digest_size;
+
+
/* NB: We use these to allow the compiler to
+
* avoid dereferencing at every step.
+
*/
+
p = (unsigned char*)password->str;
+
plen = password->len;
+
s = (unsigned char*)salt->str;
+
slen = salt->len;
+
if (slen > 16) slen = 16;
+
dsz = meta->digest_size;
+
+
/* NB: We allocate the result here to avoid throwing away all the work
+
* on out of memory at the end.
+
*/
+
if (dsz == 32) {
+
/* 4 * (30/3) + 3 */
+
res = begin_shared_string(43);
+
} else if (dsz == 64) {
+
/* 4 * (63/3) + 2 */
+
res = begin_shared_string(86);
+
} else {
+
Pike_error("crypt_hash() not supported for this digest size yet (%d).\n",
+
dsz);
+
}
+
+
THREADS_ALLOW();
+
+
/* NB: Comments refer to http://www.akkadia.org/drepper/SHA-crypt.txt */
+
meta->init(ctx); /* 4 */
+
meta->update(ctx, plen, p); /* 5 */
+
meta->update(ctx, slen, s); /* 6 */
+
meta->update(ctx, plen, p); /* 7 */
+
meta->digest(ctx, dsz, abcbuf); /* 8 */
+
+
meta->init(ctx); /* 1 */
+
meta->update(ctx, plen, p); /* 2 */
+
meta->update(ctx, slen, s); /* 3 */
+
+
for (i = 0; i + dsz < plen; i += dsz) { /* 9 */
+
meta->update(ctx, dsz, abcbuf);
+
}
+
+
meta->update(ctx, plen - i, abcbuf); /* 10 */
+
+
for (i = 1; i < plen; i <<= 1) { /* 11 */
+
if (plen & i) {
+
meta->update(ctx, dsz, abcbuf);
+
} else {
+
meta->update(ctx, plen, p);
+
}
+
}
+
+
meta->digest(ctx, dsz, abcbuf); /* 12 */
+
+
meta->init(ctx); /* 13 */
+
for (i = 0; i < plen; i++) { /* 14 */
+
meta->update(ctx, plen, p);
+
}
+
meta->digest(ctx, dsz, dpbuf); /* 15 */
+
+
/* Sequence P is implicit. */ /* 16 */
+
+
meta->init(ctx); /* 17 */
+
for(i = 0; i < 16 + abcbuf[0]; i++) { /* 18 */
+
meta->update(ctx, slen, s);
+
}
+
meta->digest(ctx, dsz, dsbuf); /* 19 */
+
+
/* Sequence S is implicit. */ /* 20 */
+
+
for (r = 0; r < rounds; r++) { /* 21 */
+
meta->init(ctx); /* a */
+
if (r & 1) { /* b */
+
for (i = 0; i + dsz < plen; i += dsz) {
+
meta->update(ctx, dsz, dpbuf);
+
}
+
meta->update(ctx, plen - i, dpbuf);
+
} else {
+
meta->update(ctx, dsz, abcbuf); /* c */
+
}
+
if (r % 3) { /* d */
+
for (i = 0; i + dsz < slen; i += dsz) {
+
meta->update(ctx, dsz, dsbuf);
+
}
+
meta->update(ctx, slen - i, dsbuf);
+
}
+
if (r % 7) { /* e */
+
for (i = 0; i + dsz < plen; i += dsz) {
+
meta->update(ctx, dsz, dpbuf);
+
}
+
meta->update(ctx, plen - i, dpbuf);
+
}
+
if (r & 1) { /* f */
+
meta->update(ctx, dsz, abcbuf);
+
} else { /* g */
+
for (i = 0; i + dsz < plen; i += dsz) {
+
meta->update(ctx, dsz, dpbuf);
+
}
+
meta->update(ctx, plen - i, dpbuf);
+
}
+
meta->digest(ctx, dsz, abcbuf); /* h */
+
}
+
THREADS_DISALLOW();
+
+
/* And now time for some pointless shuffling of the result.
+
* Note that the shuffling is slightly different between
+
* the two cases.
+
*
+
* This is followed by a custom base64-style encoding.
+
*/
+
c = 0;
+
b = dsz/3;
+
a = 2*b;
+
if (dsz == 32) {
+
for (i = 0, r = 0; i + 3 < dsz; i+=3, r+=4) {
+
int t;
+
b64enc(res->str + r, abcbuf[a], abcbuf[b], abcbuf[c], 4);
+
+
t = a+1;
+
a = b+1;
+
b = c+1;
+
c = t;
+
}
+
b64enc(res->str + r, abcbuf[30], abcbuf[31], 0, 3);
+
} else {
+
for (i = 0, r = 0; i + 3 < dsz; i+=3, r+=4) {
+
int t;
+
b64enc(res->str + r, abcbuf[a], abcbuf[b], abcbuf[c], 4);
+
+
t = a+1;
+
a = c+1;
+
c = b+1;
+
b = t;
+
}
+
b64enc(res->str + r, abcbuf[63], 0, 0, 2);
+
}
+
+
push_string(end_shared_string(res)); /* 22e */
+
+
/* Clean intermediate values. */
+
MEMSET(ctx, 0, meta->context_size);
+
MEMSET(abcbuf, 0, 3*dsz);
+
}
+
INIT { werror("HashInfo->INIT\n"); THIS->meta = NULL; } } /*! @endclass HashInfo */ #define GET_META(o) \
pike.git/src/post_modules/Nettle/hash.cmod:295:
THREADS_ALLOW(); meta->update(ctx, data->len, (const uint8_t *)data->str); THREADS_DISALLOW(); } else { meta->update(ctx, data->len, (const uint8_t *)data->str); } push_object(this_object()); }
-
/*! @decl string digest(int|void length)
+
/*! @decl string
(0..255)
digest(int|void length)
*! *! Generates a digests, and resets the hashing contents. *! *! @param length *! If the length argument is provided, the digest is truncated *! to the given length. *! *! @returns *! The digest. */
-
PIKEFUN string digest(int|void arg)
+
PIKEFUN string
(0..255)
digest(int|void arg)
{ const struct nettle_hash *meta; struct pike_string *digest; unsigned length; if (! THIS->ctx) Pike_error("HashState not properly initialized.\n"); meta = GET_META(Pike_fp->current_object); assert(meta);
pike.git/src/post_modules/Nettle/hash.cmod:428:
hash_init(void) { werror("Nettle, hash init\n"); INIT; } void hash_exit(void) { werror("Nettle, hash exit\n");
-
if (Fd_program) {
-
free_program( Fd_program );
-
}
-
if (Fd_ref_program) {
-
free_program( Fd_ref_program );
-
}
+
EXIT; } #endif /* HAVE_LIBNETTLE */