sha3 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sha3 might be problematic. Click here for more details.

data/ext/sha3/_sha3.c CHANGED
@@ -1,38 +1,306 @@
1
- #include <ruby.h>
2
- #include "KeccakNISTInterface.h"
1
+ #include "_sha3.h"
3
2
 
4
- #define MAX_DIGEST_SIZE 64
3
+ /* Document-module: SHA3
4
+ * SHA3
5
+ */
5
6
 
6
- VALUE mSHA3;
7
-
8
- /* @overload digest(data, data_len, hashbit_len)
7
+ /* Document-class: SHA3::Digest < Digest::Class
8
+ * SHA3::Digest allows you to compute message digests
9
+ * (interchangeably called "hashes") of arbitrary data that are
10
+ * cryptographically secure using SHA3 (Keccak) algorithm.
11
+ *
12
+ * == Usage
13
+ *
14
+ * require 'sha3'
9
15
  *
10
- * @param data [String] The DATA!
11
- * @param data_len [String] The number of input bits provided in the input data.
12
- * @param hashbit_len [Fixnum] The desired number of output bits (i.e., 224, 256, 384, 512).
16
+ * === Basics
17
+ *
18
+ * # Instantiate a new SHA3::Digest class with 256 bit length
19
+ * s = SHA3::Digest.new(:sha256)
20
+ * # => #<SHA3::Digest: c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470>
21
+ *
22
+ * # Update hash state, and compute new value
23
+ * s.update "Compute Me"
24
+ * # => #<SHA3::Digest: c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470>
25
+ *
26
+ * # << is an .update() alias
27
+ * s << "Me too"
28
+ * # => #<SHA3::Digest: e26f539eee3a05c52eb1f9439652d23343adea9764f011da232d24cd6d19924a>
29
+ *
30
+ * # Print digest bytes string
31
+ * puts s.digest
32
+ *
33
+ * # Print digest hex string
34
+ * puts s.hexdigest
35
+ *
36
+ * === Hashing a file
37
+ *
38
+ * # Compute the hash value for given file, and return the result as hex
39
+ * s = SHA3::Digest.new(224).file("my_awesome_file.bin").hexdigest
13
40
  *
14
- * @return [String] Computed hash
15
- */
16
- VALUE m_sha3_digest(VALUE self, VALUE data, VALUE datalen, VALUE hashbitlen)
41
+ * === Bit operation
42
+ *
43
+ * # Compute hash of "011"
44
+ * SHA3::Digest.compute(:sha224, "\xC0", 3).unpack("H*")
45
+ * # => ["2b695a6fd92a2b3f3ce9cfca617d22c9bb52815dd59a9719b01bad25"]
46
+ *
47
+ * == Notes
48
+ *
49
+ * ::Digest::Class call sequence ->
50
+ * | .alloc() ->
51
+ * | .new() ->
52
+ * | .update() ->
53
+ * | .digest or .hexdigest or .inspect -> (Instance.digest or .hexdigest()) ->
54
+ * --| .alloc() ->
55
+ * | .copy() ->
56
+ * | .finish() ->
57
+ *
58
+ */
59
+
60
+ static int get_hlen(VALUE obj)
61
+ {
62
+ int hlen;
63
+
64
+ if (TYPE(obj) == T_SYMBOL) {
65
+ ID symid;
66
+
67
+ symid = SYM2ID(obj);
68
+
69
+ if (rb_intern("sha224") == symid)
70
+ hlen = 224;
71
+ else if (rb_intern("sha256") == symid)
72
+ hlen = 256;
73
+ else if (rb_intern("sha384") == symid)
74
+ hlen = 384;
75
+ else if (rb_intern("sha512") == symid)
76
+ hlen = 512;
77
+ else
78
+ rb_raise(eDigestError, "invalid hash bit symbol (should be: :sha224, :sha256, :sha384, or :sha512");
79
+ }
80
+ else if (TYPE(obj) == T_FIXNUM) {
81
+ hlen = NUM2INT(obj);
82
+
83
+ if ((hlen != 224) && (hlen != 256) && (hlen != 384) && (hlen != 512))
84
+ rb_raise(rb_eArgError, "invalid hash bit length (should be: 224, 256, 384, or 512)");
85
+ }
86
+ else
87
+ rb_raise(eDigestError, "unknown type value");
88
+
89
+ return hlen;
90
+ }
91
+
92
+ static void free_allox(MDX *mdx)
93
+ {
94
+ if (mdx) {
95
+ if (mdx->state)
96
+ free(mdx->state);
97
+
98
+ free(mdx);
99
+ }
100
+
101
+ return;
102
+ }
103
+
104
+ static VALUE c_digest_alloc(VALUE klass)
17
105
  {
18
- int hlen = NUM2INT(hashbitlen);
106
+ MDX *mdx;
107
+ VALUE obj;
19
108
 
20
- if ((hlen != 224) && (hlen != 256) && (hlen != 384) && (hlen != 512))
21
- rb_raise(rb_eArgError, "invalid hashbit_len given (valid options: 224, 256, 384, or 512)");
109
+ mdx = (MDX *) malloc(sizeof(*mdx));
110
+ if (!mdx)
111
+ rb_raise(eDigestError, "failed to allocate object memory");
112
+
113
+ mdx->state = (hashState *) malloc(sizeof(*mdx->state));
114
+ memset(mdx->state, 0, sizeof(*mdx->state));
115
+
116
+ if (!mdx->state)
117
+ rb_raise(eDigestError, "failed to allocate state memory");
118
+
119
+ obj = Data_Wrap_Struct(klass, 0, free_allox, mdx);
120
+
121
+ return obj;
122
+ }
123
+
124
+ static VALUE c_digest_update(VALUE, VALUE);
125
+
126
+ // SHA3::Digest.new(type, [data]) -> self
127
+ static VALUE c_digest_init(int argc, VALUE *argv, VALUE self)
128
+ {
129
+ MDX *mdx;
130
+ VALUE hlen, data;
131
+
132
+ rb_scan_args(argc, argv, "02", &hlen, &data);
133
+ GETMDX(self, mdx);
134
+
135
+ if (!NIL_P(hlen))
136
+ mdx->hashbitlen = get_hlen(hlen);
137
+ else
138
+ mdx->hashbitlen = 256;
139
+
140
+ if (Init(mdx->state, mdx->hashbitlen) != SUCCESS)
141
+ rb_raise(eDigestError, "failed to initialize algorithm state");
142
+
143
+ if (!NIL_P(data))
144
+ return c_digest_update(self, data);
145
+
146
+ return self;
147
+ }
148
+
149
+ // SHA3::Digest.update(data) -> self
150
+ static VALUE c_digest_update(VALUE self, VALUE data)
151
+ {
152
+ MDX *mdx;
153
+ DataLength dlen;
22
154
 
23
155
  StringValue(data);
156
+ GETMDX(self, mdx);
24
157
 
25
- VALUE s = rb_str_new(0, hlen / 8);
158
+ dlen = (RSTRING_LEN(data) * 8);
26
159
 
27
- if (Hash(hlen, RSTRING_PTR(data), NUM2ULL(datalen), RSTRING_PTR(s)) != SUCCESS)
28
- rb_raise(rb_eException, "unable to generate hash");
160
+ if (Update(mdx->state, RSTRING_PTR(data), dlen) != SUCCESS)
161
+ rb_raise(eDigestError, "failed to update hash data");
29
162
 
30
- return s;
163
+ return self;
164
+ }
165
+
166
+ // SHA3::Digest.reset() -> self
167
+ static VALUE c_digest_reset(VALUE self)
168
+ {
169
+ MDX *mdx;
170
+
171
+ GETMDX(self, mdx);
172
+
173
+ memset(mdx->state, 0, sizeof(*mdx->state));
174
+
175
+ if (Init(mdx->state, mdx->hashbitlen) != SUCCESS)
176
+ rb_raise(eDigestError, "failed to reset internal state");
177
+
178
+ return self;
179
+ }
180
+
181
+ // SHA3::Digest.copy(obj) -> self
182
+ static VALUE c_digest_copy(VALUE self, VALUE obj)
183
+ {
184
+ MDX *mdx1, *mdx2;
185
+
186
+ rb_check_frozen(self);
187
+ if (self == obj)
188
+ return self;
189
+
190
+ GETMDX(self, mdx1);
191
+ SAFEGETMDX(obj, mdx2);
192
+
193
+ memcpy(mdx1->state, mdx2->state, sizeof(hashState));
194
+ mdx1->hashbitlen = mdx2->hashbitlen;
195
+
196
+ // Fetch the data again to make sure it was copied
197
+ GETMDX(self, mdx1);
198
+ SAFEGETMDX(obj, mdx2);
199
+ if ((mdx1->state != mdx2->state) && (mdx1->hashbitlen != mdx2->hashbitlen))
200
+ rb_raise(eDigestError, "failed to copy state");
201
+
202
+ return self;
203
+ }
204
+
205
+ // SHA3::Digest.digest_length -> Integer
206
+ static VALUE c_digest_length(VALUE self)
207
+ {
208
+ MDX *mdx;
209
+ GETMDX(self, mdx);
210
+
211
+ return ULL2NUM(mdx->hashbitlen / 8);
212
+ }
213
+
214
+ // SHA3::Digest.block_length -> Integer
215
+ static VALUE c_digest_block_length(VALUE self)
216
+ {
217
+ MDX *mdx;
218
+ GETMDX(self, mdx);
219
+
220
+ return ULL2NUM(200 - (2 * (mdx->hashbitlen / 8)));
221
+ }
222
+
223
+ // SHA3::Digest.name -> String
224
+ static VALUE c_digest_name(VALUE self)
225
+ {
226
+ return rb_str_new2("SHA3");
227
+ }
228
+
229
+ // SHA3::Digest.finish() -> String
230
+ static VALUE c_digest_finish(int argc, VALUE *argv, VALUE self)
231
+ {
232
+ MDX *mdx;
233
+ VALUE str;
234
+
235
+ rb_scan_args(argc, argv, "01", &str);
236
+ GETMDX(self, mdx);
237
+
238
+ if (NIL_P(str)) {
239
+ str = rb_str_new(0, mdx->hashbitlen / 8);
240
+ }
241
+ else {
242
+ StringValue(str);
243
+ rb_str_resize(str, mdx->hashbitlen / 8);
244
+ }
245
+
246
+ if (Final(mdx->state, RSTRING_PTR(str)) != SUCCESS)
247
+ rb_raise(eDigestError, "failed to finalize digest");
248
+
249
+ return str;
250
+ }
251
+
252
+ // SHA3::Digest.compute(type, data, [datalen]) -> String (bytes)
253
+ // TO-DO: styled output (hex)
254
+ VALUE c_digest_compute(int argc, VALUE *argv, VALUE self)
255
+ {
256
+ VALUE hlen, data, dlen, str;
257
+ int hashbitlen;
258
+ DataLength datalen;
259
+
260
+ rb_scan_args(argc, argv, "21", &hlen, &data, &dlen);
261
+
262
+ hashbitlen = get_hlen(hlen);
263
+
264
+ StringValue(data);
265
+
266
+ if (!NIL_P(dlen))
267
+ datalen = NUM2ULL(dlen);
268
+ else
269
+ datalen = (RSTRING_LEN(data) * 8);
270
+
271
+ str = rb_str_new(0, hashbitlen / 8);
272
+
273
+ if (Hash(hashbitlen, RSTRING_PTR(data), datalen, RSTRING_PTR(str)) != SUCCESS)
274
+ rb_raise(eDigestError, "failed to generate hash");
275
+
276
+ return str;
31
277
  }
32
278
 
33
279
  void Init_sha3_n()
34
280
  {
281
+ rb_require("digest");
282
+
35
283
  mSHA3 = rb_define_module("SHA3");
284
+ /* SHA3::Digest (class) */
285
+ cDigest = rb_define_class_under(mSHA3, "Digest", rb_path2class("Digest::Class"));
286
+ /* SHA3::Digest::DigestError (class) */
287
+ eDigestError = rb_define_class_under(cDigest, "DigestError", rb_eStandardError);
288
+
289
+ // SHA3::Digest (class) methods
290
+ rb_define_alloc_func(cDigest, c_digest_alloc);
291
+ rb_define_method(cDigest, "initialize", c_digest_init, -1);
292
+ rb_define_method(cDigest, "update", c_digest_update, 1);
293
+ rb_define_method(cDigest, "reset", c_digest_reset, 0);
294
+ rb_define_method(cDigest, "initialize_copy", c_digest_copy, 1);
295
+ rb_define_method(cDigest, "digest_length", c_digest_length, 0);
296
+ rb_define_method(cDigest, "block_length", c_digest_block_length, 0);
297
+ rb_define_method(cDigest, "name", c_digest_name, 0);
298
+ rb_define_private_method(cDigest, "finish", c_digest_finish, -1);
299
+
300
+ rb_define_alias(cDigest, "<<", "update");
301
+
302
+ // SHA3 (module) functions (support bit operations)
303
+ rb_define_singleton_method(cDigest, "compute", c_digest_compute, -1);
36
304
 
37
- rb_define_module_function(mSHA3, "digest", m_sha3_digest, 3);
305
+ return;
38
306
  }
data/ext/sha3/_sha3.h ADDED
@@ -0,0 +1,32 @@
1
+ #ifndef __SHA3_H_
2
+ #define __SHA3_H_
3
+
4
+ #include <ruby.h>
5
+ #include "KeccakNISTInterface.h"
6
+
7
+ // From ruby/ext/openssl/ossl_digest.c
8
+ #define GETMDX(obj, mdx) do { \
9
+ Data_Get_Struct((obj), MDX, (mdx)); \
10
+ if (!(mdx)) { \
11
+ rb_raise(rb_eRuntimeError, "Digest data not initialized!"); \
12
+ } \
13
+ } while (0)
14
+
15
+ #define SAFEGETMDX(obj, mdx) do { \
16
+ if (!rb_obj_is_kind_of(obj, cDigest)) { \
17
+ rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)",\
18
+ rb_obj_classname(obj), rb_class2name(cDigest)); \
19
+ } \
20
+ GETMDX(obj, mdx); \
21
+ } while(0)
22
+
23
+ VALUE mSHA3;
24
+ VALUE cDigest;
25
+ VALUE eDigestError;
26
+
27
+ typedef struct {
28
+ hashState *state;
29
+ int hashbitlen;
30
+ } MDX;
31
+
32
+ #endif
data/ext/sha3/extconf.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'mkmf'
2
2
 
3
- if 1.size == 4
3
+ case 1.size
4
+ when 4 # 32bit optimized code
4
5
  FileUtils.cp "#{$srcdir}/KeccakF-1600-opt32.c-arch", "#{$srcdir}/KeccakF-1600-opt.c"
5
- elsif
6
+ when 8 # 64bit optimized code
6
7
  FileUtils.cp "#{$srcdir}/KeccakF-1600-opt64.c-arch", "#{$srcdir}/KeccakF-1600-opt.c"
8
+ else # Ha? Use reference code
9
+ FileUtils.cp "#{$srcdir}/KeccakF-1600-reference.c-arch", "#{$srcdir}/KeccakF-1600-opt.c"
7
10
  end
8
11
 
9
12
  $CFLAGS = ' -fomit-frame-pointer -O3 -g0 -march=nocona '
data/lib/sha3.rb CHANGED
@@ -1,22 +1,2 @@
1
- require 'sha3/version'
2
1
  require 'sha3_n'
3
-
4
- module SHA3
5
- extend self
6
-
7
- def digest_224(data)
8
- SHA3::digest(data, data.length * 8, 224)
9
- end
10
-
11
- def digest_256(data)
12
- SHA3::digest(data, data.length * 8, 256)
13
- end
14
-
15
- def digest_384(data)
16
- SHA3::digest(data, data.length * 8, 384)
17
- end
18
-
19
- def digest_512(data)
20
- SHA3::digest(data, data.length * 8, 512)
21
- end
22
- end
2
+ require 'sha3/version'
data/lib/sha3/version.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  module SHA3
2
+ extend self
3
+
2
4
  # sha3 version
3
- VERSION = "0.1.1"
5
+ VERSION = "0.2.0"
6
+ KECCAK_VERSION = "3.2"
4
7
  end
8
+
data/sha3.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.name = "sha3"
7
7
  gem.version = SHA3::VERSION
8
8
  gem.summary = %q{SHA3 for Ruby}
9
- gem.description = %q{A native SHA3 gem}
9
+ gem.description = %q{SHA3 for Ruby is a native (C) implementation of Keccak (SHA3) cryptographic hashing algorithm. See https://github.com/johanns/sha3#readme for details.}
10
10
  gem.license = "MIT"
11
11
  gem.authors = ["Johanns Gregorian"]
12
12
  gem.email = "io+sha3@jsani.com"
@@ -0,0 +1,84 @@
1
+ # Based on python-sha3's / digest-sha3 test generator.
2
+
3
+ FILES = [
4
+ ['data/ShortMsgKAT_224.txt', 224],
5
+ ['data/ShortMsgKAT_256.txt', 256],
6
+ ['data/ShortMsgKAT_384.txt', 384],
7
+ ['data/ShortMsgKAT_512.txt', 512],
8
+ ['data/LongMsgKAT_224.txt', 224],
9
+ ]
10
+
11
+ def gen_digest_byte_tests
12
+ FILES.each do |path, hashlen|
13
+ name = File.basename(path).split('.')[0]
14
+
15
+ f = File.new("sha3_digest_#{name}_spec.rb", "w")
16
+ f.puts(
17
+ %Q{require 'spec_helper'
18
+ require 'sha3'
19
+
20
+ describe "SHA3::Digest.new(#{hashlen})" do
21
+ it "should match byte-length test vectors (#{name})." do
22
+ })
23
+ contents = File.read(path).split('Len = ')
24
+ contents.each do |test|
25
+ lines = test.split("\n")
26
+ if !lines.empty? && lines[0] !~ /^#/
27
+ length = lines[0].to_i
28
+ if length % 8 == 0 && length != 0
29
+ msg_raw = [lines[1].split(' = ').last].pack("H*")
30
+ md = lines[2].split(' = ').last.downcase
31
+ f.puts(
32
+ %Q{ SHA3::Digest.new(#{hashlen}, #{msg_raw.inspect}).hexdigest.should(eq("#{md}"))
33
+ })
34
+ end
35
+ end
36
+ end
37
+ f.puts(
38
+ %Q{ end
39
+ end
40
+ })
41
+ f.close
42
+ end
43
+ end
44
+
45
+ def gen_compute_bit_tests
46
+ FILES.each do |path, hashlen|
47
+ name = File.basename(path).split('.')[0]
48
+
49
+ f = File.new("sha3_compute_#{name}_spec.rb", "w")
50
+ f.puts(
51
+ %Q{require 'spec_helper'
52
+ require 'sha3'
53
+
54
+ describe "SHA3::Digest.compute(#{hashlen})" do
55
+ it "should match bit-length test vectors (#{name})." do
56
+ })
57
+ contents = File.read(path).split('Len = ')
58
+ contents.each do |test|
59
+ lines = test.split("\n")
60
+ if !lines.empty? && lines[0] !~ /^#/
61
+ length = lines[0].to_i
62
+ if length != 0
63
+ msg_raw = [lines[1].split(' = ').last].pack("H*")
64
+ md = lines[2].split(' = ').last.downcase
65
+ f.puts(
66
+ %Q{ SHA3::Digest.compute(#{hashlen}, #{msg_raw.inspect}, #{length}).unpack("H*").first.should(eq("#{md}"))
67
+ })
68
+ end
69
+ end
70
+ end
71
+ f.puts(
72
+ %Q{ end
73
+ end
74
+ })
75
+ f.close
76
+ end
77
+ end
78
+
79
+ def setup
80
+
81
+ end
82
+
83
+ gen_digest_byte_tests
84
+ gen_compute_bit_tests