2012-10-04 08:00:56 -04:00
|
|
|
#include "ruby.h"
|
2013-05-20 10:57:41 -04:00
|
|
|
#ifdef HAVE_RUBY_DIGEST_H
|
|
|
|
#include "ruby/digest.h"
|
|
|
|
#else
|
|
|
|
#include "digest.h"
|
|
|
|
#endif
|
2012-10-04 12:30:56 -04:00
|
|
|
#include "KeccakNISTInterface.h"
|
2012-10-04 08:00:56 -04:00
|
|
|
|
2012-10-04 12:30:56 -04:00
|
|
|
#define MAX_DIGEST_SIZE 64
|
2013-05-20 10:57:41 -04:00
|
|
|
#define DEFAULT_DIGEST_LEN 512
|
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
static int keccak_init_func(hashState *ctx);
|
|
|
|
static void keccak_update_func(hashState *ctx, unsigned char *str, size_t len)keccak
|
|
|
|
static int keccak_finish_func(hashState *ctx, unsigned char *digest);
|
2013-05-20 10:57:41 -04:00
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
/*
|
2019-06-08 07:53:04 -04:00
|
|
|
Metadata definition for the Keccak algorithm.
|
2015-05-20 22:51:29 -04:00
|
|
|
Defines the Version, sizes for block and digest as well as
|
|
|
|
the entry points for the algorithms
|
|
|
|
*/
|
2019-06-08 07:53:04 -04:00
|
|
|
static rb_digest_metadata_t keccak = {
|
2013-05-20 10:57:41 -04:00
|
|
|
RUBY_DIGEST_API_VERSION,
|
|
|
|
DEFAULT_DIGEST_LEN,
|
2015-05-20 22:51:29 -04:00
|
|
|
KeccakPermutationSize - (2 * DEFAULT_DIGEST_LEN), //size of blocks
|
|
|
|
sizeof(hashState), //size of context for the object we'll be passed in below functions.
|
2019-06-08 07:53:04 -04:00
|
|
|
(rb_digest_hash_init_func_t)keccak_init_func,
|
|
|
|
(rb_digest_hash_update_func_t)keccak_update_func,
|
|
|
|
(rb_digest_hash_finish_func_t)keccak_finish_func,
|
2013-05-20 10:57:41 -04:00
|
|
|
};
|
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
/* Initialization function for the algorithm,
|
|
|
|
gets called during allocation of the digest object.
|
|
|
|
we override initialize to do custom hash size, so we don't care too much here.
|
|
|
|
*/
|
|
|
|
static int
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_init_func(hashState *ctx) {
|
2015-05-20 22:51:29 -04:00
|
|
|
// Just return a 1 ' successful' we override the init function
|
|
|
|
// so this is not necessary
|
|
|
|
// the base class alloc calls this to initialize the algorithm
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update function, take the current context and add str to it */
|
|
|
|
static void
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_update_func(hashState *ctx, unsigned char *str, size_t len) {
|
2015-05-20 22:51:29 -04:00
|
|
|
Update(ctx, str, len * 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finish the hash calculation and return the finished string */
|
|
|
|
static int
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_finish_func(hashState *ctx, unsigned char *digest) {
|
2015-05-20 22:51:29 -04:00
|
|
|
Final(ctx, digest);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
/* Ruby method. Digest::Keccak#finish()
|
2015-05-20 22:51:29 -04:00
|
|
|
* No Arguments
|
|
|
|
* @returns [String] Encoded Digest String
|
|
|
|
*/
|
|
|
|
static VALUE
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_keccak_finish(VALUE self) {
|
2015-05-20 22:51:29 -04:00
|
|
|
hashState *ctx;
|
|
|
|
VALUE digest;
|
|
|
|
|
|
|
|
ctx = (hashState *)RTYPEDDATA_DATA(self);
|
|
|
|
digest = rb_str_new(0, ctx->capacity / 2 / 8);
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_finish_func(ctx, (unsigned char *)RSTRING_PTR(digest));
|
2015-05-20 22:51:29 -04:00
|
|
|
|
|
|
|
return digest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: private method
|
|
|
|
* initialize the ctx with the bitlength
|
|
|
|
*/
|
2013-05-20 10:57:41 -04:00
|
|
|
static void
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_init(hashState *ctx, size_t bitlen) {
|
2013-05-20 10:57:41 -04:00
|
|
|
switch (Init(ctx, bitlen)) {
|
|
|
|
case SUCCESS:
|
|
|
|
return;
|
|
|
|
case FAIL:
|
|
|
|
rb_raise(rb_eRuntimeError, "Unknown error");
|
|
|
|
case BAD_HASHLEN:
|
2013-05-20 11:14:04 -04:00
|
|
|
rb_raise(rb_eArgError, "Bad hash length (must be 0, 224, 256, 384 or 512)");
|
2013-05-20 10:57:41 -04:00
|
|
|
default:
|
|
|
|
rb_raise(rb_eRuntimeError, "Unknown error code");
|
|
|
|
}
|
|
|
|
}
|
2012-10-04 12:30:56 -04:00
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
/* Ruby method. Digest::Keccak.new(hashlen)
|
2015-05-20 22:51:29 -04:00
|
|
|
* @param hashlen The length of hash, only supports 224, 256, 384 or 512
|
2019-06-08 07:53:04 -04:00
|
|
|
* @returns [Digest::Keccak] new object.
|
2015-05-20 22:51:29 -04:00
|
|
|
*/
|
2012-10-05 14:40:31 -04:00
|
|
|
static VALUE
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_keccak_initialize(int argc, VALUE *argv, VALUE self) {
|
2013-05-20 10:57:41 -04:00
|
|
|
hashState *ctx;
|
2012-10-04 12:33:35 -04:00
|
|
|
VALUE hashlen;
|
|
|
|
int i_hashlen;
|
|
|
|
|
|
|
|
if (rb_scan_args(argc, argv, "01", &hashlen) == 0) {
|
2013-05-20 10:57:41 -04:00
|
|
|
i_hashlen = DEFAULT_DIGEST_LEN;
|
2012-10-04 12:33:35 -04:00
|
|
|
} else {
|
|
|
|
i_hashlen = NUM2INT(hashlen);
|
|
|
|
}
|
2015-05-20 22:51:29 -04:00
|
|
|
if ( i_hashlen == 0) {
|
2013-05-20 11:14:04 -04:00
|
|
|
rb_raise(rb_eArgError, "Unsupported hash length");
|
2015-05-20 22:51:29 -04:00
|
|
|
}
|
2012-10-04 12:30:56 -04:00
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
ctx = (hashState *)RTYPEDDATA_DATA(self);
|
2019-06-08 07:53:04 -04:00
|
|
|
keccak_init(ctx, i_hashlen);
|
2013-05-20 10:57:41 -04:00
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
return rb_call_super(0, NULL);
|
2012-10-04 12:30:56 -04:00
|
|
|
}
|
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
/* Ruby method. Digest::Keccak#digest_length
|
2015-05-20 22:51:29 -04:00
|
|
|
* @returns [Numeric] Length of the digest.
|
|
|
|
*/
|
2012-10-04 12:30:56 -04:00
|
|
|
static VALUE
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_keccak_digest_length(VALUE self) {
|
2013-05-20 10:57:41 -04:00
|
|
|
hashState *ctx;
|
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
ctx = (hashState *)RTYPEDDATA_DATA(self);
|
2013-05-20 10:57:41 -04:00
|
|
|
return INT2FIX(ctx->capacity / 2 / 8);
|
2012-10-04 12:30:56 -04:00
|
|
|
}
|
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
/* Ruby method. Digest::Keccak#block_length
|
2015-05-20 22:51:29 -04:00
|
|
|
* @returns [Numeric] Length of blocks in this digest.
|
|
|
|
*/
|
2012-10-04 12:30:56 -04:00
|
|
|
static VALUE
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_keccak_block_length(VALUE self) {
|
2013-05-20 10:57:41 -04:00
|
|
|
hashState *ctx;
|
2012-10-04 12:30:56 -04:00
|
|
|
|
2015-05-20 22:51:29 -04:00
|
|
|
ctx = (hashState *)RTYPEDDATA_DATA(self);
|
2013-05-20 10:57:41 -04:00
|
|
|
return INT2FIX(ctx->rate / 8);
|
2012-10-04 12:30:56 -04:00
|
|
|
}
|
2012-10-04 08:00:56 -04:00
|
|
|
|
2012-10-04 12:37:58 -04:00
|
|
|
void __attribute__((visibility("default")))
|
2019-06-08 07:53:04 -04:00
|
|
|
Init_keccak() {
|
|
|
|
VALUE mDigest, cDigest_Base, cKeccak;
|
2013-05-20 10:57:41 -04:00
|
|
|
|
|
|
|
rb_require("digest");
|
|
|
|
|
|
|
|
mDigest = rb_path2class("Digest");
|
|
|
|
cDigest_Base = rb_path2class("Digest::Base");
|
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
cKeccak = rb_define_class_under(mDigest, "Keccak", cDigest_Base);
|
2013-05-20 10:57:41 -04:00
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_iv_set(cKeccak, "metadata", Data_Wrap_Struct(0, 0, 0, (void *)&keccak));
|
2013-05-20 10:57:41 -04:00
|
|
|
|
2019-06-08 07:53:04 -04:00
|
|
|
rb_define_method(cKeccak, "initialize", rb_keccak_initialize, -1);
|
|
|
|
rb_define_method(cKeccak, "digest_length", rb_keccak_digest_length, 0);
|
|
|
|
rb_define_method(cKeccak, "block_length", rb_keccak_block_length, 0);
|
|
|
|
rb_define_method(cKeccak, "finish", rb_keccak_finish, 0);
|
2012-10-04 08:00:56 -04:00
|
|
|
}
|