Class: Phylax::Digest

Inherits:
Object
  • Object
show all
Defined in:
lib/phylax.rb,
ext/phylax/phylax.c

Overview

Streaming message digest (SHA-256/384/512).

d = Phylax::Digest.new(:sha256)
d << "chunk one" << "chunk two"
d.hexdigest            # non-destructive; you may keep updating

Constant Summary collapse

SIZES =

Bytes in the final digest, keyed by algorithm symbol.

{ sha256: 32, sha384: 48, sha512: 64 }.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Digest

Returns a new instance of Digest.



117
118
119
120
121
# File 'lib/phylax.rb', line 117

def initialize(name)
  idx = HASHES.fetch(name) { raise ArgumentError, "unknown hash #{name.inspect}" }
  @name = name
  _init(idx)
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



115
116
117
# File 'lib/phylax.rb', line 115

def name
  @name
end

Class Method Details

.digest(name, data) ⇒ Object

Convenience: hash data in one call.



138
139
140
# File 'lib/phylax.rb', line 138

def self.digest(name, data)
  new(name).update(data).digest
end

.hexdigest(name, data) ⇒ Object



142
143
144
# File 'lib/phylax.rb', line 142

def self.hexdigest(name, data)
  digest(name, data).unpack1("H*")
end

Instance Method Details

#<<(data) ⇒ Object



123
124
125
# File 'lib/phylax.rb', line 123

def <<(data)
  update(data)
end

#_init(vidx) ⇒ Object

Phylax::Digest#_init(idx) — (re)create the underlying hash object.



427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'ext/phylax/phylax.c', line 427

static VALUE
digest_init(VALUE self, VALUE vidx)
{
    digest_t *d = digest_get(self);
    int i = alg_index(vidx);
    NTSTATUS st;

    if (d->h) { BCryptDestroyHash(d->h); d->h = NULL; }
    st = BCryptCreateHash(g_hash[i], &d->h, NULL, 0, NULL, 0, 0);
    if (!NT_SUCCESS(st))
        raise_nt("BCryptCreateHash", st);
    d->idx = i;
    return self;
}

#digestObject

Non-destructive: duplicate the running state and finish the copy, leaving the original open for further #update (matches Ruby stdlib Digest semantics).



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'ext/phylax/phylax.c', line 460

static VALUE
digest_digest(VALUE self)
{
    digest_t *d = digest_get(self);
    BCRYPT_HASH_HANDLE dup = NULL;
    PUCHAR obj;
    ULONG objlen;
    NTSTATUS st;
    VALUE out;

    if (!d->h) rb_raise(eError, "phylax: digest not initialized");

    /* Allocate the Ruby output first so the malloc below is the last resource
     * acquired; an rb_str_new (OOM) raise then leaks nothing. */
    out = rb_str_new(NULL, g_dlen[d->idx]);
    rb_enc_associate(out, rb_ascii8bit_encoding());

    objlen = g_objlen_hash[d->idx];
    obj = (PUCHAR)malloc(objlen ? objlen : 1);
    if (!obj) rb_raise(rb_eNoMemError, "phylax: out of memory");

    st = BCryptDuplicateHash(d->h, &dup, obj, objlen, 0);
    if (NT_SUCCESS(st))
        st = BCryptFinishHash(dup, (PUCHAR)RSTRING_PTR(out), g_dlen[d->idx], 0);
    if (dup) BCryptDestroyHash(dup);
    free(obj);
    if (!NT_SUCCESS(st))
        raise_nt("BCryptDuplicateHash", st);

    return out;
}

#digest_lengthObject



492
493
494
495
496
497
498
# File 'ext/phylax/phylax.c', line 492

static VALUE
digest_size(VALUE self)
{
    digest_t *d = digest_get(self);
    if (d->idx < 0) rb_raise(eError, "phylax: digest not initialized");
    return UINT2NUM(g_dlen[d->idx]);
}

#hexdigestObject



133
134
135
# File 'lib/phylax.rb', line 133

def hexdigest
  digest.unpack1("H*")
end

#inspectObject



151
152
153
# File 'lib/phylax.rb', line 151

def inspect
  "#<Phylax::Digest #{@name}>"
end

#resetObject

Discard any fed data and start over.



128
129
130
131
# File 'lib/phylax.rb', line 128

def reset
  _init(HASHES.fetch(@name))
  self
end

#sizeObject Also known as: length



146
147
148
# File 'lib/phylax.rb', line 146

def size
  digest_length
end

#update(data) ⇒ Object



442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'ext/phylax/phylax.c', line 442

static VALUE
digest_update(VALUE self, VALUE data)
{
    digest_t *d = digest_get(self);
    PUCHAR pin;
    ULONG nin;
    NTSTATUS st;

    if (!d->h) rb_raise(eError, "phylax: digest not initialized");
    nin = str_bytes(&data, &pin);
    st = BCryptHashData(d->h, pin, nin, 0);
    if (!NT_SUCCESS(st))
        raise_nt("BCryptHashData", st);
    return self;
}