sha3 2.2.2 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.rubocop.yml +66 -0
- data/ext/sha3/common.h +118 -0
- data/ext/sha3/cshake.c +16 -94
- data/ext/sha3/digest.c +101 -79
- data/ext/sha3/kmac.c +18 -97
- data/ext/sha3/sp800_185.c +47 -15
- data/lib/constants.rb +1 -1
- data/sha3.gemspec +4 -4
- data.tar.gz.sig +0 -0
- metadata +3 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9efe4158e87ea949852977b7791cf56838a9fefdbe226ebf7fdb4c5e962e927b
|
4
|
+
data.tar.gz: 6f41a24a48b714a33f846e6458aad350be5168f33202c51a95bda7a364cffc5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21086756d157c20bd8f74fde996cabfc8c2a8975b913cab0da03a311d41eb3d44427e344419344e7d8729b21edf0c1d550732c583df8a1f2797b700b64468464
|
7
|
+
data.tar.gz: fd6dacfcb827ecbdf8d3d60cd1b9dfacd6f50fc9c4440100890fbac7302d26f8119da33f95b67c270c73b6f75789a7b5e569e04c638a834dce9ff99a5b2050a7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.rubocop.yml
CHANGED
@@ -6,8 +6,74 @@ AllCops:
|
|
6
6
|
NewCops: enable
|
7
7
|
TargetRubyVersion: 2.7
|
8
8
|
|
9
|
+
Exclude:
|
10
|
+
- ext/**/*.rb
|
11
|
+
|
9
12
|
Layout/LineLength:
|
10
13
|
Max: 120
|
11
14
|
|
15
|
+
# Metrics
|
16
|
+
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Exclude:
|
19
|
+
- spec/**/*_spec.rb
|
20
|
+
|
21
|
+
Metrics/CyclomaticComplexity:
|
22
|
+
Exclude:
|
23
|
+
- spec/**/*_spec.rb
|
24
|
+
|
25
|
+
Metrics/PerceivedComplexity:
|
26
|
+
Exclude:
|
27
|
+
- spec/**/*_spec.rb
|
28
|
+
|
29
|
+
Metrics/MethodLength:
|
30
|
+
Max: 15
|
31
|
+
Exclude:
|
32
|
+
- spec/**/*_spec.rb
|
33
|
+
|
34
|
+
# Naming
|
35
|
+
|
36
|
+
Naming/ClassAndModuleCamelCase:
|
37
|
+
Enabled: false
|
38
|
+
|
12
39
|
Naming/VariableNumber:
|
13
40
|
EnforcedStyle: snake_case
|
41
|
+
Exclude:
|
42
|
+
- spec/**/*.rb
|
43
|
+
|
44
|
+
# Security
|
45
|
+
|
46
|
+
# Allow URI.open for test vector downloads
|
47
|
+
Security/Open:
|
48
|
+
Exclude:
|
49
|
+
- spec/sha3_digest_vectors_spec.rb
|
50
|
+
|
51
|
+
# RSpec configuration
|
52
|
+
|
53
|
+
RSpec/ExampleLength:
|
54
|
+
Max: 15
|
55
|
+
CountAsOne:
|
56
|
+
- array
|
57
|
+
- hash
|
58
|
+
- heredoc
|
59
|
+
|
60
|
+
RSpec/MultipleExpectations:
|
61
|
+
Max: 8
|
62
|
+
|
63
|
+
RSpec/SpecFilePathFormat:
|
64
|
+
Enabled: false
|
65
|
+
|
66
|
+
RSpec/LeakyConstantDeclaration:
|
67
|
+
Enabled: false
|
68
|
+
|
69
|
+
RSpec/BeforeAfterAll:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
RSpec/MultipleDescribes:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
RSpec/NamedSubject:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
RSpec/DescribeClass:
|
79
|
+
Enabled: false
|
data/ext/sha3/common.h
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
// Copyright (c) 2025 Johanns Gregorian <io+sha3@jsg.io>
|
2
|
+
|
3
|
+
#ifndef _SHA3_COMMON_H_
|
4
|
+
#define _SHA3_COMMON_H_
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#include "sp800_185.h"
|
9
|
+
|
10
|
+
#ifdef __cplusplus
|
11
|
+
extern "C" {
|
12
|
+
#endif
|
13
|
+
|
14
|
+
/* Common macros for SP800-185 based implementations (CSHAKE, KMAC) */
|
15
|
+
|
16
|
+
/* Define a simple method that just calls an sp800_185 function */
|
17
|
+
#define DEFINE_SP800_185_SIMPLE_METHOD(method_name, sp_func, get_ctx_func) \
|
18
|
+
static VALUE method_name(VALUE self, VALUE data) { \
|
19
|
+
sp800_185_context_t *context; \
|
20
|
+
get_ctx_func(self, &context); \
|
21
|
+
sp_func(context, data); \
|
22
|
+
return self; \
|
23
|
+
}
|
24
|
+
|
25
|
+
/* Define a method that returns a value from sp800_185 function */
|
26
|
+
#define DEFINE_SP800_185_RETURN_METHOD(method_name, sp_func, get_ctx_func) \
|
27
|
+
static VALUE method_name(VALUE self) { \
|
28
|
+
sp800_185_context_t *context; \
|
29
|
+
get_ctx_func(self, &context); \
|
30
|
+
return sp_func(context); \
|
31
|
+
}
|
32
|
+
|
33
|
+
/* Define a method with single VALUE parameter that returns VALUE */
|
34
|
+
#define DEFINE_SP800_185_VALUE_METHOD(method_name, sp_func, get_ctx_func) \
|
35
|
+
static VALUE method_name(VALUE self, VALUE param) { \
|
36
|
+
sp800_185_context_t *context; \
|
37
|
+
get_ctx_func(self, &context); \
|
38
|
+
return sp_func(context, param); \
|
39
|
+
}
|
40
|
+
|
41
|
+
/* Define a method with variable arguments */
|
42
|
+
#define DEFINE_SP800_185_VARARGS_METHOD(method_name, sp_func, get_ctx_func) \
|
43
|
+
static VALUE method_name(int argc, VALUE *argv, VALUE self) { \
|
44
|
+
sp800_185_context_t *context; \
|
45
|
+
get_ctx_func(self, &context); \
|
46
|
+
VALUE param = argc > 0 ? argv[0] : Qnil; \
|
47
|
+
return sp_func(context, param); \
|
48
|
+
}
|
49
|
+
|
50
|
+
/* Define common memory management functions */
|
51
|
+
#define DEFINE_SP800_185_MEMORY_FUNCS(prefix, context_type) \
|
52
|
+
static void prefix##_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); } \
|
53
|
+
\
|
54
|
+
static size_t prefix##_context_size(const void *ptr) { \
|
55
|
+
return sp800_185_context_size((const sp800_185_context_t *)ptr, sizeof(context_type)); \
|
56
|
+
}
|
57
|
+
|
58
|
+
/* Define common allocation function */
|
59
|
+
#define DEFINE_SP800_185_ALLOC(prefix, context_type, instance_type, error_class) \
|
60
|
+
static VALUE rb_##prefix##_alloc(VALUE klass) { \
|
61
|
+
context_type *context = (context_type *)sp800_185_alloc_context(sizeof(context_type), sizeof(instance_type)); \
|
62
|
+
\
|
63
|
+
if (!context) { \
|
64
|
+
rb_raise(error_class, "failed to allocate memory"); \
|
65
|
+
} \
|
66
|
+
\
|
67
|
+
VALUE obj = TypedData_Wrap_Struct(klass, &prefix##_data_type, context); \
|
68
|
+
return obj; \
|
69
|
+
}
|
70
|
+
|
71
|
+
/* Define common copy method */
|
72
|
+
#define DEFINE_SP800_185_COPY_METHOD(method_name, context_type, data_type, class_var) \
|
73
|
+
static VALUE method_name(VALUE self, VALUE other) { \
|
74
|
+
context_type *context, *other_context; \
|
75
|
+
\
|
76
|
+
rb_check_frozen(self); \
|
77
|
+
if (self == other) { \
|
78
|
+
return self; \
|
79
|
+
} \
|
80
|
+
\
|
81
|
+
if (!rb_obj_is_kind_of(other, class_var)) { \
|
82
|
+
rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other), \
|
83
|
+
rb_class2name(class_var)); \
|
84
|
+
} \
|
85
|
+
\
|
86
|
+
TypedData_Get_Struct(other, context_type, &data_type, other_context); \
|
87
|
+
TypedData_Get_Struct(self, context_type, &data_type, context); \
|
88
|
+
\
|
89
|
+
/* Copy the base context attributes */ \
|
90
|
+
context->base.functions = other_context->base.functions; \
|
91
|
+
context->base.output_length = other_context->base.output_length; \
|
92
|
+
context->base.error_class = other_context->base.error_class; \
|
93
|
+
\
|
94
|
+
/* Copy the algorithm-specific state */ \
|
95
|
+
if (context->base.functions && other_context->base.state) { \
|
96
|
+
memcpy(context->base.state, other_context->base.state, context->base.functions->state_size); \
|
97
|
+
} \
|
98
|
+
\
|
99
|
+
return self; \
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Ruby wrapper functions for SP800-185 operations */
|
103
|
+
VALUE sp800_185_rb_update(sp800_185_context_t *context, VALUE data);
|
104
|
+
VALUE sp800_185_rb_name(sp800_185_context_t *context);
|
105
|
+
VALUE sp800_185_rb_finish(sp800_185_context_t *context, VALUE output);
|
106
|
+
VALUE sp800_185_rb_digest(sp800_185_context_t *context, VALUE data);
|
107
|
+
VALUE sp800_185_rb_hexdigest(sp800_185_context_t *context, VALUE data);
|
108
|
+
VALUE sp800_185_rb_squeeze(sp800_185_context_t *context, VALUE length);
|
109
|
+
VALUE sp800_185_rb_hex_squeeze(sp800_185_context_t *context, VALUE length);
|
110
|
+
|
111
|
+
/* Helper function to register common methods */
|
112
|
+
void register_sp800_185_common_methods(VALUE klass);
|
113
|
+
|
114
|
+
#ifdef __cplusplus
|
115
|
+
}
|
116
|
+
#endif
|
117
|
+
|
118
|
+
#endif /* _SHA3_COMMON_H_ */
|
data/ext/sha3/cshake.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "cshake.h"
|
2
2
|
|
3
|
+
#include "common.h"
|
3
4
|
#include "sha3.h"
|
4
5
|
#include "sp800_185.h"
|
5
6
|
|
@@ -76,7 +77,7 @@ void Init_sha3_cshake(void) {
|
|
76
77
|
/*
|
77
78
|
* Document-class: SHA3::CSHAKE::Error
|
78
79
|
*
|
79
|
-
* All
|
80
|
+
* All CSHAKE methods raise this exception on error.
|
80
81
|
*
|
81
82
|
* It is a subclass of the StandardError class -- see the Ruby documentation
|
82
83
|
* for more information.
|
@@ -104,25 +105,11 @@ void Init_sha3_cshake(void) {
|
|
104
105
|
return;
|
105
106
|
}
|
106
107
|
|
107
|
-
|
108
|
+
/* Use common memory management functions */
|
109
|
+
DEFINE_SP800_185_MEMORY_FUNCS(sha3_cshake, sha3_cshake_context_t)
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
}
|
112
|
-
|
113
|
-
static VALUE rb_sha3_cshake_alloc(VALUE klass) {
|
114
|
-
sha3_cshake_context_t *context =
|
115
|
-
(sha3_cshake_context_t *)sp800_185_alloc_context(sizeof(sha3_cshake_context_t), sizeof(cSHAKE_Instance));
|
116
|
-
|
117
|
-
if (!context) {
|
118
|
-
rb_raise(_sha3_cshake_error_class, "failed to allocate memory");
|
119
|
-
}
|
120
|
-
|
121
|
-
// Create the Ruby object with TypedData - this will automatically handle freeing
|
122
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &sha3_cshake_data_type, context);
|
123
|
-
|
124
|
-
return obj;
|
125
|
-
}
|
111
|
+
/* Use common allocation function */
|
112
|
+
DEFINE_SP800_185_ALLOC(sha3_cshake, sha3_cshake_context_t, cSHAKE_Instance, _sha3_cshake_error_class)
|
126
113
|
|
127
114
|
/*
|
128
115
|
* :call-seq:
|
@@ -144,14 +131,14 @@ static VALUE rb_sha3_cshake_alloc(VALUE klass) {
|
|
144
131
|
* _optional_ The customization string to use
|
145
132
|
*
|
146
133
|
* = example
|
147
|
-
* # Initialize instance for
|
134
|
+
* # Initialize instance for fixed-length operation
|
148
135
|
* cshake = SHA3::CSHAKE.new(:cshake_128, 32, name: 'my-app')
|
149
136
|
* cshake << 'data...'
|
150
137
|
* cshake.hexdigest
|
151
138
|
*
|
152
139
|
* # Initialize instance for XOF operation (arbitrary-long output)
|
153
140
|
* cshake = SHA3::CSHAKE.new(:cshake_256, 0, customization: 'Email Signature')
|
154
|
-
*
|
141
|
+
* cshake.update('data...')
|
155
142
|
* cshake.squeeze(64)
|
156
143
|
*/
|
157
144
|
static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
|
@@ -233,31 +220,7 @@ static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
|
|
233
220
|
* = example
|
234
221
|
* cshake2 = cshake.dup
|
235
222
|
*/
|
236
|
-
|
237
|
-
sha3_cshake_context_t *context, *other_context;
|
238
|
-
|
239
|
-
rb_check_frozen(self);
|
240
|
-
if (self == other) {
|
241
|
-
return self;
|
242
|
-
}
|
243
|
-
|
244
|
-
if (!rb_obj_is_kind_of(other, _sha3_cshake_class)) {
|
245
|
-
rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
|
246
|
-
rb_class2name(_sha3_cshake_class));
|
247
|
-
}
|
248
|
-
|
249
|
-
TypedData_Get_Struct(other, sha3_cshake_context_t, &sha3_cshake_data_type, other_context);
|
250
|
-
TypedData_Get_Struct(self, sha3_cshake_context_t, &sha3_cshake_data_type, context);
|
251
|
-
|
252
|
-
// Copy the base context attributes
|
253
|
-
context->base.functions = other_context->base.functions;
|
254
|
-
context->base.output_length = other_context->base.output_length;
|
255
|
-
|
256
|
-
// Copy the algorithm-specific state
|
257
|
-
memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
|
258
|
-
|
259
|
-
return self;
|
260
|
-
}
|
223
|
+
DEFINE_SP800_185_COPY_METHOD(rb_sha3_cshake_copy, sha3_cshake_context_t, sha3_cshake_data_type, _sha3_cshake_class)
|
261
224
|
|
262
225
|
/*
|
263
226
|
* :call-seq:
|
@@ -272,13 +235,7 @@ static VALUE rb_sha3_cshake_copy(VALUE self, VALUE other) {
|
|
272
235
|
* cshake.update("more data")
|
273
236
|
* cshake << "more data" # alias for update
|
274
237
|
*/
|
275
|
-
|
276
|
-
sp800_185_context_t *context;
|
277
|
-
get_cshake_context(self, &context);
|
278
|
-
sp800_185_update(context, data);
|
279
|
-
|
280
|
-
return self;
|
281
|
-
}
|
238
|
+
DEFINE_SP800_185_SIMPLE_METHOD(rb_sha3_cshake_update, sp800_185_rb_update, get_cshake_context)
|
282
239
|
|
283
240
|
/*
|
284
241
|
* :call-seq:
|
@@ -286,12 +243,7 @@ static VALUE rb_sha3_cshake_update(VALUE self, VALUE data) {
|
|
286
243
|
*
|
287
244
|
* Returns the name of the CSHAKE instance.
|
288
245
|
*/
|
289
|
-
|
290
|
-
sp800_185_context_t *context;
|
291
|
-
get_cshake_context(self, &context);
|
292
|
-
|
293
|
-
return rb_str_new2(sp800_185_name(context));
|
294
|
-
}
|
246
|
+
DEFINE_SP800_185_RETURN_METHOD(rb_sha3_cshake_name, sp800_185_rb_name, get_cshake_context)
|
295
247
|
|
296
248
|
/*
|
297
249
|
* :call-seq:
|
@@ -305,13 +257,7 @@ static VALUE rb_sha3_cshake_name(VALUE self) {
|
|
305
257
|
* = example
|
306
258
|
* cshake.finish
|
307
259
|
*/
|
308
|
-
|
309
|
-
sp800_185_context_t *context;
|
310
|
-
get_cshake_context(self, &context);
|
311
|
-
|
312
|
-
VALUE output = argc > 0 ? argv[0] : Qnil;
|
313
|
-
return sp800_185_finish(context, output);
|
314
|
-
}
|
260
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_finish, sp800_185_rb_finish, get_cshake_context)
|
315
261
|
|
316
262
|
/*
|
317
263
|
* :call-seq:
|
@@ -326,14 +272,7 @@ static VALUE rb_sha3_cshake_finish(int argc, VALUE *argv, VALUE self) {
|
|
326
272
|
* cshake.digest
|
327
273
|
* cshake.digest("final chunk")
|
328
274
|
*/
|
329
|
-
|
330
|
-
sp800_185_context_t *context;
|
331
|
-
get_cshake_context(self, &context);
|
332
|
-
|
333
|
-
VALUE data = argc > 0 ? argv[0] : Qnil;
|
334
|
-
|
335
|
-
return sp800_185_digest(context, data);
|
336
|
-
}
|
275
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_digest, sp800_185_rb_digest, get_cshake_context)
|
337
276
|
|
338
277
|
/*
|
339
278
|
* :call-seq:
|
@@ -348,14 +287,7 @@ static VALUE rb_sha3_cshake_digest(int argc, VALUE *argv, VALUE self) {
|
|
348
287
|
* cshake.hexdigest
|
349
288
|
* cshake.hexdigest("final chunk")
|
350
289
|
*/
|
351
|
-
|
352
|
-
sp800_185_context_t *context;
|
353
|
-
get_cshake_context(self, &context);
|
354
|
-
|
355
|
-
VALUE data = argc > 0 ? argv[0] : Qnil;
|
356
|
-
|
357
|
-
return sp800_185_hexdigest(context, data);
|
358
|
-
}
|
290
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_hexdigest, sp800_185_rb_hexdigest, get_cshake_context)
|
359
291
|
|
360
292
|
/*
|
361
293
|
* :call-seq:
|
@@ -369,12 +301,7 @@ static VALUE rb_sha3_cshake_hexdigest(int argc, VALUE *argv, VALUE self) {
|
|
369
301
|
* = example
|
370
302
|
* cshake.squeeze(32)
|
371
303
|
*/
|
372
|
-
|
373
|
-
sp800_185_context_t *context;
|
374
|
-
get_cshake_context(self, &context);
|
375
|
-
|
376
|
-
return sp800_185_squeeze(context, length);
|
377
|
-
}
|
304
|
+
DEFINE_SP800_185_VALUE_METHOD(rb_sha3_cshake_squeeze, sp800_185_rb_squeeze, get_cshake_context)
|
378
305
|
|
379
306
|
/*
|
380
307
|
* :call-seq:
|
@@ -388,9 +315,4 @@ static VALUE rb_sha3_cshake_squeeze(VALUE self, VALUE length) {
|
|
388
315
|
* = example
|
389
316
|
* cshake.hex_squeeze(32)
|
390
317
|
*/
|
391
|
-
|
392
|
-
sp800_185_context_t *context;
|
393
|
-
get_cshake_context(self, &context);
|
394
|
-
|
395
|
-
return sp800_185_hex_squeeze(context, length);
|
396
|
-
}
|
318
|
+
DEFINE_SP800_185_VALUE_METHOD(rb_sha3_cshake_hex_squeeze, sp800_185_rb_hex_squeeze, get_cshake_context)
|
data/ext/sha3/digest.c
CHANGED
@@ -79,15 +79,16 @@ static ID _shake_128_id;
|
|
79
79
|
static ID _shake_256_id;
|
80
80
|
|
81
81
|
/* TypedData structure for sha3_digest_context_t */
|
82
|
-
const rb_data_type_t
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
82
|
+
const rb_data_type_t sha3_digest_data_type = {"SHA3::Digest",
|
83
|
+
{
|
84
|
+
NULL,
|
85
|
+
sha3_digest_free_context,
|
86
|
+
sha3_digest_context_size,
|
87
|
+
NULL,
|
88
|
+
},
|
89
|
+
NULL,
|
90
|
+
NULL,
|
91
|
+
RUBY_TYPED_FREE_IMMEDIATELY};
|
91
92
|
|
92
93
|
void Init_sha3_digest(void) {
|
93
94
|
rb_require("digest");
|
@@ -154,10 +155,14 @@ void Init_sha3_digest(void) {
|
|
154
155
|
|
155
156
|
// Static inline functions replacing macros
|
156
157
|
static inline void get_sha3_digest_context(VALUE obj, sha3_digest_context_t **context) {
|
157
|
-
TypedData_Get_Struct((obj), sha3_digest_context_t, &
|
158
|
+
TypedData_Get_Struct((obj), sha3_digest_context_t, &sha3_digest_data_type, (*context));
|
158
159
|
if (!(*context)) {
|
159
160
|
rb_raise(rb_eRuntimeError, "Digest data not initialized!");
|
160
161
|
}
|
162
|
+
|
163
|
+
if (!(*context)->state) {
|
164
|
+
rb_raise(rb_eRuntimeError, "Digest state not initialized!");
|
165
|
+
}
|
161
166
|
}
|
162
167
|
|
163
168
|
static inline void safe_get_sha3_digest_context(VALUE obj, sha3_digest_context_t **context) {
|
@@ -170,36 +175,36 @@ static inline void safe_get_sha3_digest_context(VALUE obj, sha3_digest_context_t
|
|
170
175
|
|
171
176
|
static inline int is_shake_algorithm(sha3_digest_algorithms alg) { return alg == SHAKE_128 || alg == SHAKE_256; }
|
172
177
|
|
173
|
-
int get_hashbit_length(VALUE obj, sha3_digest_algorithms *algorithm) {
|
174
|
-
if (TYPE(obj)
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
178
|
+
static int get_hashbit_length(VALUE obj, sha3_digest_algorithms *algorithm) {
|
179
|
+
if (TYPE(obj) != T_SYMBOL) {
|
180
|
+
rb_raise(_sha3_digest_error_class, "hash algorithm must be a symbol");
|
181
|
+
}
|
182
|
+
|
183
|
+
ID symid = SYM2ID(obj);
|
184
|
+
|
185
|
+
if (symid == _sha3_224_id) {
|
186
|
+
*algorithm = SHA3_224;
|
187
|
+
return 224;
|
188
|
+
} else if (symid == _sha3_256_id) {
|
189
|
+
*algorithm = SHA3_256;
|
190
|
+
return 256;
|
191
|
+
} else if (symid == _sha3_384_id) {
|
192
|
+
*algorithm = SHA3_384;
|
193
|
+
return 384;
|
194
|
+
} else if (symid == _sha3_512_id) {
|
195
|
+
*algorithm = SHA3_512;
|
196
|
+
return 512;
|
197
|
+
} else if (symid == _shake_128_id) {
|
198
|
+
*algorithm = SHAKE_128;
|
199
|
+
return 128;
|
200
|
+
} else if (symid == _shake_256_id) {
|
201
|
+
*algorithm = SHAKE_256;
|
202
|
+
return 256;
|
203
|
+
}
|
204
|
+
|
205
|
+
rb_raise(rb_eArgError,
|
206
|
+
"invalid hash algorithm symbol (should be: :sha3_224, "
|
207
|
+
":sha3_256, :sha3_384, :sha3_512, :shake_128, or :shake_256)");
|
203
208
|
|
204
209
|
return 0; // Never reached, but silences compiler warnings
|
205
210
|
}
|
@@ -208,9 +213,10 @@ static void sha3_digest_free_context(void *ptr) {
|
|
208
213
|
sha3_digest_context_t *context = (sha3_digest_context_t *)ptr;
|
209
214
|
if (context) {
|
210
215
|
if (context->state) {
|
211
|
-
|
216
|
+
ruby_xfree(context->state);
|
217
|
+
context->state = NULL;
|
212
218
|
}
|
213
|
-
|
219
|
+
ruby_xfree(context);
|
214
220
|
}
|
215
221
|
}
|
216
222
|
|
@@ -245,21 +251,22 @@ static HashReturn keccak_hash_initialize(sha3_digest_context_t *context) {
|
|
245
251
|
}
|
246
252
|
|
247
253
|
static VALUE rb_sha3_digest_alloc(VALUE klass) {
|
248
|
-
sha3_digest_context_t *context = (sha3_digest_context_t
|
254
|
+
sha3_digest_context_t *context = RB_ALLOC(sha3_digest_context_t);
|
249
255
|
if (!context) {
|
250
256
|
rb_raise(_sha3_digest_error_class, "failed to allocate object memory");
|
251
257
|
}
|
252
258
|
|
253
|
-
context->state = (Keccak_HashInstance
|
259
|
+
context->state = RB_ALLOC(Keccak_HashInstance);
|
254
260
|
if (!context->state) {
|
255
|
-
|
261
|
+
ruby_xfree(context);
|
256
262
|
rb_raise(_sha3_digest_error_class, "failed to allocate state memory");
|
257
263
|
}
|
264
|
+
memset(context->state, 0, sizeof(*context->state));
|
258
265
|
|
259
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &sha3_digest_data_type_t, context);
|
260
266
|
context->hashbitlen = 0;
|
261
|
-
context->algorithm = SHA3_256;
|
267
|
+
context->algorithm = SHA3_256;
|
262
268
|
|
269
|
+
VALUE obj = TypedData_Wrap_Struct(klass, &sha3_digest_data_type, context);
|
263
270
|
return obj;
|
264
271
|
}
|
265
272
|
|
@@ -342,7 +349,13 @@ static VALUE rb_sha3_digest_update(VALUE self, VALUE data) {
|
|
342
349
|
rb_raise(_sha3_digest_error_class, "cannot update with NULL data");
|
343
350
|
}
|
344
351
|
|
345
|
-
|
352
|
+
// Prevent integer overflow and validate size
|
353
|
+
size_t data_len = RSTRING_LEN(data);
|
354
|
+
if (data_len > SIZE_MAX / 8) {
|
355
|
+
rb_raise(_sha3_digest_error_class, "data too large (exceeds maximum size)");
|
356
|
+
}
|
357
|
+
|
358
|
+
dlen = (data_len * 8);
|
346
359
|
|
347
360
|
if (Keccak_HashUpdate(context->state, (BitSequence *)RSTRING_PTR(data), dlen) != KECCAK_SUCCESS) {
|
348
361
|
rb_raise(_sha3_digest_error_class, "failed to update hash data");
|
@@ -374,6 +387,10 @@ static VALUE rb_sha3_digest_reset(VALUE self) {
|
|
374
387
|
}
|
375
388
|
|
376
389
|
static int compare_contexts(const sha3_digest_context_t *context1, const sha3_digest_context_t *context2) {
|
390
|
+
if (!context1 || !context2 || !context1->state || !context2->state) {
|
391
|
+
return 0;
|
392
|
+
}
|
393
|
+
|
377
394
|
// First check the hashbitlen and algorithm
|
378
395
|
if (context1->hashbitlen != context2->hashbitlen || context1->algorithm != context2->algorithm) {
|
379
396
|
return 0;
|
@@ -429,7 +446,11 @@ static VALUE rb_sha3_digest_copy(VALUE self, VALUE other) {
|
|
429
446
|
}
|
430
447
|
|
431
448
|
safe_get_sha3_digest_context(other, &other_context);
|
432
|
-
|
449
|
+
safe_get_sha3_digest_context(self, &context);
|
450
|
+
|
451
|
+
if (!context || !other_context) {
|
452
|
+
rb_raise(_sha3_digest_error_class, "invalid context for copy");
|
453
|
+
}
|
433
454
|
|
434
455
|
context->hashbitlen = other_context->hashbitlen;
|
435
456
|
context->algorithm = other_context->algorithm;
|
@@ -489,17 +510,17 @@ static VALUE rb_sha3_digest_name(VALUE self) {
|
|
489
510
|
|
490
511
|
switch (context->algorithm) {
|
491
512
|
case SHA3_224:
|
492
|
-
return
|
513
|
+
return rb_str_new_cstr("SHA3-224");
|
493
514
|
case SHA3_256:
|
494
|
-
return
|
515
|
+
return rb_str_new_cstr("SHA3-256");
|
495
516
|
case SHA3_384:
|
496
|
-
return
|
517
|
+
return rb_str_new_cstr("SHA3-384");
|
497
518
|
case SHA3_512:
|
498
|
-
return
|
519
|
+
return rb_str_new_cstr("SHA3-512");
|
499
520
|
case SHAKE_128:
|
500
|
-
return
|
521
|
+
return rb_str_new_cstr("SHAKE128");
|
501
522
|
case SHAKE_256:
|
502
|
-
return
|
523
|
+
return rb_str_new_cstr("SHAKE256");
|
503
524
|
default:
|
504
525
|
rb_raise(_sha3_digest_error_class, "unknown algorithm");
|
505
526
|
}
|
@@ -560,15 +581,19 @@ static VALUE rb_sha3_digest_finish(int argc, VALUE *argv, VALUE self) {
|
|
560
581
|
static VALUE rb_sha3_digest_squeeze(VALUE self, VALUE length) {
|
561
582
|
sha3_digest_context_t *context;
|
562
583
|
VALUE str, copy;
|
563
|
-
|
584
|
+
long output_bytes;
|
564
585
|
|
565
586
|
Check_Type(length, T_FIXNUM);
|
566
|
-
output_bytes =
|
587
|
+
output_bytes = NUM2LONG(length);
|
567
588
|
|
568
589
|
if (output_bytes <= 0) {
|
569
590
|
rb_raise(_sha3_digest_error_class, "output length must be positive");
|
570
591
|
}
|
571
592
|
|
593
|
+
if (output_bytes > (1L << 20)) { // Limit to 1MB output
|
594
|
+
rb_raise(_sha3_digest_error_class, "output length too large (max 1MB)");
|
595
|
+
}
|
596
|
+
|
572
597
|
get_sha3_digest_context(self, &context);
|
573
598
|
|
574
599
|
// Only SHAKE algorithms support arbitrary-length output
|
@@ -578,6 +603,9 @@ static VALUE rb_sha3_digest_squeeze(VALUE self, VALUE length) {
|
|
578
603
|
|
579
604
|
// Create a copy of the digest object to avoid modifying the original
|
580
605
|
copy = rb_obj_clone(self);
|
606
|
+
if (NIL_P(copy)) {
|
607
|
+
rb_raise(_sha3_digest_error_class, "failed to clone digest object");
|
608
|
+
}
|
581
609
|
|
582
610
|
// Get the sha3_digest_context_t struct from the copy
|
583
611
|
sha3_digest_context_t *context_copy;
|
@@ -615,7 +643,7 @@ static VALUE rb_sha3_digest_hex_squeeze(VALUE self, VALUE length) {
|
|
615
643
|
// Get the binary output using the existing squeeze function
|
616
644
|
VALUE bin_str = rb_sha3_digest_squeeze(self, length);
|
617
645
|
// Use Ruby's built-in unpack method to convert to hex
|
618
|
-
return rb_funcall(bin_str, rb_intern("unpack1"), 1,
|
646
|
+
return rb_funcall(bin_str, rb_intern("unpack1"), 1, rb_str_new_cstr("H*"));
|
619
647
|
}
|
620
648
|
|
621
649
|
static VALUE prepare_shake_output(VALUE self, int argc, VALUE *argv, int hex_output) {
|
@@ -800,32 +828,26 @@ static VALUE rb_sha3_digest_self_digest(VALUE klass, VALUE name, VALUE data) {
|
|
800
828
|
* To squeeze a different length, use #hex_squeeze instance method.
|
801
829
|
*/
|
802
830
|
static VALUE rb_sha3_digest_self_hexdigest(VALUE klass, VALUE name, VALUE data) {
|
803
|
-
VALUE
|
831
|
+
VALUE digest;
|
804
832
|
|
805
|
-
|
806
|
-
|
833
|
+
if (NIL_P(name) || NIL_P(data)) {
|
834
|
+
rb_raise(_sha3_digest_error_class, "algorithm name and data cannot be nil");
|
835
|
+
}
|
807
836
|
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
if (symid == _shake_128_id || symid == _shake_256_id) {
|
812
|
-
/* Create a new digest instance with the specified algorithm */
|
813
|
-
VALUE digest = rb_class_new_instance(1, &name, klass);
|
837
|
+
if (TYPE(name) != T_SYMBOL) {
|
838
|
+
rb_raise(_sha3_digest_error_class, "algorithm name must be a symbol");
|
839
|
+
}
|
814
840
|
|
815
|
-
|
816
|
-
rb_sha3_digest_update(digest, data);
|
841
|
+
StringValue(data);
|
817
842
|
|
818
|
-
|
819
|
-
|
843
|
+
ID symid = SYM2ID(name);
|
844
|
+
digest = rb_class_new_instance(1, &name, klass);
|
845
|
+
rb_sha3_digest_update(digest, data);
|
820
846
|
|
821
|
-
|
822
|
-
|
823
|
-
|
847
|
+
if (symid == _shake_128_id || symid == _shake_256_id) {
|
848
|
+
int output_length = (symid == _shake_128_id) ? 16 : 32;
|
849
|
+
return rb_sha3_digest_hex_squeeze(digest, INT2NUM(output_length));
|
824
850
|
}
|
825
851
|
|
826
|
-
|
827
|
-
args[0] = data;
|
828
|
-
args[1] = name;
|
829
|
-
|
830
|
-
return rb_call_super(2, args);
|
852
|
+
return rb_funcall(digest, rb_intern("hexdigest"), 0);
|
831
853
|
}
|
data/ext/sha3/kmac.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "kmac.h"
|
2
2
|
|
3
|
+
#include "common.h"
|
3
4
|
#include "sha3.h"
|
4
5
|
#include "sp800_185.h"
|
5
6
|
|
@@ -42,7 +43,7 @@ static ID _kmac_128_id;
|
|
42
43
|
static ID _kmac_256_id;
|
43
44
|
|
44
45
|
/* TypedData structure for sha3_kmac_context_t */
|
45
|
-
const rb_data_type_t
|
46
|
+
const rb_data_type_t sha3_kmac_data_type = {
|
46
47
|
"SHA3::KMAC",
|
47
48
|
{
|
48
49
|
NULL, sha3_kmac_free_context, sha3_kmac_context_size, NULL, /* dcompact field */
|
@@ -55,7 +56,7 @@ const rb_data_type_t sha3_kmac_data_type_t = {
|
|
55
56
|
// Helper function to extract context from a Ruby object
|
56
57
|
void get_kmac_context(VALUE obj, sp800_185_context_t **context) {
|
57
58
|
sha3_kmac_context_t *kmac_ctx;
|
58
|
-
TypedData_Get_Struct(obj, sha3_kmac_context_t, &
|
59
|
+
TypedData_Get_Struct(obj, sha3_kmac_context_t, &sha3_kmac_data_type, kmac_ctx);
|
59
60
|
*context = &kmac_ctx->base;
|
60
61
|
}
|
61
62
|
|
@@ -104,25 +105,11 @@ void Init_sha3_kmac(void) {
|
|
104
105
|
return;
|
105
106
|
}
|
106
107
|
|
107
|
-
|
108
|
+
/* Use common memory management functions */
|
109
|
+
DEFINE_SP800_185_MEMORY_FUNCS(sha3_kmac, sha3_kmac_context_t)
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
}
|
112
|
-
|
113
|
-
static VALUE rb_sha3_kmac_alloc(VALUE klass) {
|
114
|
-
sha3_kmac_context_t *context =
|
115
|
-
(sha3_kmac_context_t *)sp800_185_alloc_context(sizeof(sha3_kmac_context_t), sizeof(KMAC_Instance));
|
116
|
-
|
117
|
-
if (!context) {
|
118
|
-
rb_raise(_sha3_kmac_error_class, "failed to allocate memory");
|
119
|
-
}
|
120
|
-
|
121
|
-
// Create the Ruby object with TypedData - this will automatically handle freeing
|
122
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &sha3_kmac_data_type_t, context);
|
123
|
-
|
124
|
-
return obj;
|
125
|
-
}
|
111
|
+
/* Use common allocation function */
|
112
|
+
DEFINE_SP800_185_ALLOC(sha3_kmac, sha3_kmac_context_t, KMAC_Instance, _sha3_kmac_error_class)
|
126
113
|
|
127
114
|
/*
|
128
115
|
* :call-seq:
|
@@ -179,7 +166,7 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
|
|
179
166
|
}
|
180
167
|
|
181
168
|
sha3_kmac_context_t *context;
|
182
|
-
TypedData_Get_Struct(self, sha3_kmac_context_t, &
|
169
|
+
TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type, context);
|
183
170
|
|
184
171
|
// Store the output length in bits
|
185
172
|
context->base.output_length = NUM2ULONG(output_length) * 8;
|
@@ -229,31 +216,7 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
|
|
229
216
|
* = example
|
230
217
|
* new_kmac = kmac.dup
|
231
218
|
*/
|
232
|
-
|
233
|
-
sha3_kmac_context_t *context, *other_context;
|
234
|
-
|
235
|
-
rb_check_frozen(self);
|
236
|
-
if (self == other) {
|
237
|
-
return self;
|
238
|
-
}
|
239
|
-
|
240
|
-
if (!rb_obj_is_kind_of(other, _sha3_kmac_class)) {
|
241
|
-
rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
|
242
|
-
rb_class2name(_sha3_kmac_class));
|
243
|
-
}
|
244
|
-
|
245
|
-
TypedData_Get_Struct(other, sha3_kmac_context_t, &sha3_kmac_data_type_t, other_context);
|
246
|
-
TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type_t, context);
|
247
|
-
|
248
|
-
// Copy the base context attributes
|
249
|
-
context->base.functions = other_context->base.functions;
|
250
|
-
context->base.output_length = other_context->base.output_length;
|
251
|
-
|
252
|
-
// Copy the algorithm-specific state
|
253
|
-
memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
|
254
|
-
|
255
|
-
return self;
|
256
|
-
}
|
219
|
+
DEFINE_SP800_185_COPY_METHOD(rb_sha3_kmac_copy, sha3_kmac_context_t, sha3_kmac_data_type, _sha3_kmac_class)
|
257
220
|
|
258
221
|
/*
|
259
222
|
* :call-seq:
|
@@ -268,13 +231,7 @@ static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
|
|
268
231
|
* kmac.update("more data")
|
269
232
|
* kmac << "more data" # alias for update
|
270
233
|
*/
|
271
|
-
|
272
|
-
sp800_185_context_t *context;
|
273
|
-
get_kmac_context(self, &context);
|
274
|
-
sp800_185_update(context, data);
|
275
|
-
|
276
|
-
return self;
|
277
|
-
}
|
234
|
+
DEFINE_SP800_185_SIMPLE_METHOD(rb_sha3_kmac_update, sp800_185_rb_update, get_kmac_context)
|
278
235
|
|
279
236
|
/*
|
280
237
|
* :call-seq:
|
@@ -285,12 +242,7 @@ static VALUE rb_sha3_kmac_update(VALUE self, VALUE data) {
|
|
285
242
|
* = example
|
286
243
|
* kmac.name #=> "KMAC128" or "KMAC256"
|
287
244
|
*/
|
288
|
-
|
289
|
-
sp800_185_context_t *context;
|
290
|
-
get_kmac_context(self, &context);
|
291
|
-
|
292
|
-
return rb_str_new2(sp800_185_name(context));
|
293
|
-
}
|
245
|
+
DEFINE_SP800_185_RETURN_METHOD(rb_sha3_kmac_name, sp800_185_rb_name, get_kmac_context)
|
294
246
|
|
295
247
|
/*
|
296
248
|
* :call-seq:
|
@@ -304,14 +256,7 @@ static VALUE rb_sha3_kmac_name(VALUE self) {
|
|
304
256
|
* = example
|
305
257
|
* kmac.finish
|
306
258
|
*/
|
307
|
-
|
308
|
-
sp800_185_context_t *context;
|
309
|
-
get_kmac_context(self, &context);
|
310
|
-
|
311
|
-
VALUE output = argc > 0 ? argv[0] : Qnil;
|
312
|
-
|
313
|
-
return sp800_185_finish(context, output);
|
314
|
-
}
|
259
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_finish, sp800_185_rb_finish, get_kmac_context)
|
315
260
|
|
316
261
|
/*
|
317
262
|
* :call-seq:
|
@@ -329,14 +274,7 @@ static VALUE rb_sha3_kmac_finish(int argc, VALUE *argv, VALUE self) {
|
|
329
274
|
* kmac.digest
|
330
275
|
* kmac.digest('final chunk')
|
331
276
|
*/
|
332
|
-
|
333
|
-
sp800_185_context_t *context;
|
334
|
-
get_kmac_context(self, &context);
|
335
|
-
|
336
|
-
VALUE data = argc > 0 ? argv[0] : Qnil;
|
337
|
-
|
338
|
-
return sp800_185_digest(context, data);
|
339
|
-
}
|
277
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_digest, sp800_185_rb_digest, get_kmac_context)
|
340
278
|
|
341
279
|
/*
|
342
280
|
* :call-seq:
|
@@ -354,14 +292,7 @@ static VALUE rb_sha3_kmac_digest(int argc, VALUE *argv, VALUE self) {
|
|
354
292
|
* kmac.hexdigest
|
355
293
|
* kmac.hexdigest('final chunk')
|
356
294
|
*/
|
357
|
-
|
358
|
-
sp800_185_context_t *context;
|
359
|
-
get_kmac_context(self, &context);
|
360
|
-
|
361
|
-
VALUE data = argc > 0 ? argv[0] : Qnil;
|
362
|
-
|
363
|
-
return sp800_185_hexdigest(context, data);
|
364
|
-
}
|
295
|
+
DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_hexdigest, sp800_185_rb_hexdigest, get_kmac_context)
|
365
296
|
|
366
297
|
/*
|
367
298
|
* :call-seq:
|
@@ -377,12 +308,7 @@ static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE *argv, VALUE self) {
|
|
377
308
|
* = example
|
378
309
|
* kmac.squeeze(128)
|
379
310
|
*/
|
380
|
-
|
381
|
-
sp800_185_context_t *context;
|
382
|
-
get_kmac_context(self, &context);
|
383
|
-
|
384
|
-
return sp800_185_squeeze(context, length);
|
385
|
-
}
|
311
|
+
DEFINE_SP800_185_VALUE_METHOD(rb_sha3_kmac_squeeze, sp800_185_rb_squeeze, get_kmac_context)
|
386
312
|
|
387
313
|
/*
|
388
314
|
* :call-seq:
|
@@ -398,12 +324,7 @@ static VALUE rb_sha3_kmac_squeeze(VALUE self, VALUE length) {
|
|
398
324
|
* = example
|
399
325
|
* kmac.hex_squeeze(128)
|
400
326
|
*/
|
401
|
-
|
402
|
-
sp800_185_context_t *context;
|
403
|
-
get_kmac_context(self, &context);
|
404
|
-
|
405
|
-
return sp800_185_hex_squeeze(context, length);
|
406
|
-
}
|
327
|
+
DEFINE_SP800_185_VALUE_METHOD(rb_sha3_kmac_hex_squeeze, sp800_185_rb_hex_squeeze, get_kmac_context)
|
407
328
|
|
408
329
|
/*
|
409
330
|
* :call-seq:
|
@@ -432,7 +353,7 @@ static VALUE rb_sha3_kmac_self_digest(int argc, VALUE *argv, VALUE klass) {
|
|
432
353
|
rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
|
433
354
|
|
434
355
|
Check_Type(output_length, T_FIXNUM);
|
435
|
-
if (!NIL_P(output_length) && output_length <=
|
356
|
+
if (!NIL_P(output_length) && NUM2INT(output_length) <= 0) {
|
436
357
|
rb_raise(rb_eArgError, "class method digest does not support XOF mode");
|
437
358
|
}
|
438
359
|
|
@@ -468,7 +389,7 @@ static VALUE rb_sha3_kmac_self_hexdigest(int argc, VALUE *argv, VALUE klass) {
|
|
468
389
|
rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
|
469
390
|
|
470
391
|
Check_Type(output_length, T_FIXNUM);
|
471
|
-
if (!NIL_P(output_length) && output_length <=
|
392
|
+
if (!NIL_P(output_length) && NUM2INT(output_length) <= 0) {
|
472
393
|
rb_raise(rb_eArgError, "class method hexdigest does not support XOF mode");
|
473
394
|
}
|
474
395
|
|
data/ext/sha3/sp800_185.c
CHANGED
@@ -74,12 +74,12 @@ const sp800_185_function_table_t *sp800_185_get_algorithm_by_name(const char *na
|
|
74
74
|
|
75
75
|
// Generic context allocation function
|
76
76
|
sp800_185_context_t *sp800_185_alloc_context(size_t context_size, size_t state_size) {
|
77
|
-
sp800_185_context_t *context = (sp800_185_context_t *)
|
77
|
+
sp800_185_context_t *context = (sp800_185_context_t *)ruby_xmalloc(context_size);
|
78
78
|
if (!context) return NULL;
|
79
79
|
|
80
|
-
context->state =
|
80
|
+
context->state = ruby_xcalloc(1, state_size);
|
81
81
|
if (!context->state) {
|
82
|
-
|
82
|
+
ruby_xfree(context);
|
83
83
|
return NULL;
|
84
84
|
}
|
85
85
|
|
@@ -92,9 +92,9 @@ sp800_185_context_t *sp800_185_alloc_context(size_t context_size, size_t state_s
|
|
92
92
|
void sp800_185_free_context(sp800_185_context_t *context) {
|
93
93
|
if (context) {
|
94
94
|
if (context->state) {
|
95
|
-
|
95
|
+
ruby_xfree(context->state);
|
96
96
|
}
|
97
|
-
|
97
|
+
ruby_xfree(context);
|
98
98
|
}
|
99
99
|
}
|
100
100
|
|
@@ -112,7 +112,7 @@ void *sp800_185_copy_state(sp800_185_context_t *context) {
|
|
112
112
|
if (context->functions->state_size <= 0) {
|
113
113
|
rb_raise(context->error_class, "invalid state size");
|
114
114
|
}
|
115
|
-
void *state_copy =
|
115
|
+
void *state_copy = ruby_xmalloc(context->functions->state_size);
|
116
116
|
|
117
117
|
if (!state_copy) {
|
118
118
|
rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
|
@@ -125,6 +125,12 @@ void *sp800_185_copy_state(sp800_185_context_t *context) {
|
|
125
125
|
|
126
126
|
VALUE sp800_185_update(sp800_185_context_t *context, VALUE data) {
|
127
127
|
StringValue(data);
|
128
|
+
|
129
|
+
// Check for NULL data pointer
|
130
|
+
if (RSTRING_PTR(data) == NULL && RSTRING_LEN(data) > 0) {
|
131
|
+
rb_raise(context->error_class, "cannot update with NULL data");
|
132
|
+
}
|
133
|
+
|
128
134
|
size_t data_len = (RSTRING_LEN(data) * 8);
|
129
135
|
|
130
136
|
if (data_len == 0) {
|
@@ -172,7 +178,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
|
|
172
178
|
}
|
173
179
|
|
174
180
|
// Create a copy of the state for processing
|
175
|
-
void *state_copy =
|
181
|
+
void *state_copy = ruby_xmalloc(context->functions->state_size);
|
176
182
|
if (!state_copy) {
|
177
183
|
rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
|
178
184
|
}
|
@@ -190,7 +196,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
|
|
190
196
|
result = context->functions->update(state_copy, (const BitSequence *)RSTRING_PTR(data), data_len);
|
191
197
|
|
192
198
|
if (result != 0) {
|
193
|
-
|
199
|
+
ruby_xfree(state_copy);
|
194
200
|
rb_raise(context->error_class, "failed to update %s state", context->functions->name);
|
195
201
|
}
|
196
202
|
}
|
@@ -201,7 +207,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
|
|
201
207
|
|
202
208
|
result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(output));
|
203
209
|
|
204
|
-
|
210
|
+
ruby_xfree(state_copy);
|
205
211
|
|
206
212
|
if (result != 0) {
|
207
213
|
rb_raise(context->error_class, "failed to finalize %s state", context->functions->name);
|
@@ -220,18 +226,23 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
|
|
220
226
|
rb_raise(context->error_class, "use digest methods for fixed-length output");
|
221
227
|
}
|
222
228
|
|
223
|
-
|
229
|
+
long output_byte_len;
|
224
230
|
VALUE str;
|
225
231
|
|
226
232
|
Check_Type(length, T_FIXNUM);
|
227
|
-
output_byte_len =
|
233
|
+
output_byte_len = NUM2LONG(length);
|
228
234
|
|
229
235
|
if (output_byte_len <= 0) {
|
230
|
-
rb_raise(context->error_class, "output length must be
|
236
|
+
rb_raise(context->error_class, "output length must be positive");
|
237
|
+
}
|
238
|
+
|
239
|
+
// Limit output to 1MB for safety
|
240
|
+
if (output_byte_len > (1L << 20)) {
|
241
|
+
rb_raise(context->error_class, "output length too large (max 1MB)");
|
231
242
|
}
|
232
243
|
|
233
244
|
// Create a copy of the state for processing
|
234
|
-
void *state_copy =
|
245
|
+
void *state_copy = ruby_xmalloc(context->functions->state_size);
|
235
246
|
if (!state_copy) {
|
236
247
|
rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
|
237
248
|
}
|
@@ -245,7 +256,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
|
|
245
256
|
result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(dummy_output));
|
246
257
|
|
247
258
|
if (result != 0) {
|
248
|
-
|
259
|
+
ruby_xfree(state_copy);
|
249
260
|
rb_raise(context->error_class, "failed to finalize %s state", context->functions->name);
|
250
261
|
}
|
251
262
|
|
@@ -255,7 +266,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
|
|
255
266
|
// Use the function table to call the appropriate squeeze function
|
256
267
|
result = context->functions->squeeze(state_copy, (BitSequence *)RSTRING_PTR(str), output_byte_len * 8);
|
257
268
|
|
258
|
-
|
269
|
+
ruby_xfree(state_copy);
|
259
270
|
|
260
271
|
if (result != 0) {
|
261
272
|
rb_raise(context->error_class, "failed to squeeze %s", context->functions->name);
|
@@ -268,3 +279,24 @@ VALUE sp800_185_hex_squeeze(sp800_185_context_t *context, VALUE length) {
|
|
268
279
|
VALUE binary_result = sp800_185_squeeze(context, length);
|
269
280
|
return rb_funcall(binary_result, rb_intern("unpack1"), 1, rb_str_new2("H*"));
|
270
281
|
}
|
282
|
+
|
283
|
+
/* Ruby wrapper functions for common method patterns */
|
284
|
+
|
285
|
+
VALUE sp800_185_rb_update(sp800_185_context_t *context, VALUE data) {
|
286
|
+
sp800_185_update(context, data);
|
287
|
+
return Qnil; // Caller will return self
|
288
|
+
}
|
289
|
+
|
290
|
+
VALUE sp800_185_rb_name(sp800_185_context_t *context) { return rb_str_new2(sp800_185_name(context)); }
|
291
|
+
|
292
|
+
VALUE sp800_185_rb_finish(sp800_185_context_t *context, VALUE output) { return sp800_185_finish(context, output); }
|
293
|
+
|
294
|
+
VALUE sp800_185_rb_digest(sp800_185_context_t *context, VALUE data) { return sp800_185_digest(context, data); }
|
295
|
+
|
296
|
+
VALUE sp800_185_rb_hexdigest(sp800_185_context_t *context, VALUE data) { return sp800_185_hexdigest(context, data); }
|
297
|
+
|
298
|
+
VALUE sp800_185_rb_squeeze(sp800_185_context_t *context, VALUE length) { return sp800_185_squeeze(context, length); }
|
299
|
+
|
300
|
+
VALUE sp800_185_rb_hex_squeeze(sp800_185_context_t *context, VALUE length) {
|
301
|
+
return sp800_185_hex_squeeze(context, length);
|
302
|
+
}
|
data/lib/constants.rb
CHANGED
data/sha3.gemspec
CHANGED
@@ -9,11 +9,11 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Johanns Gregorian']
|
10
10
|
spec.email = ['io+sha3@jsg.io']
|
11
11
|
|
12
|
-
spec.description = <<~
|
12
|
+
spec.description = <<~DESC
|
13
13
|
A high-performance native binding to the SHA3 (FIPS 202) cryptographic hashing algorithms, based on the XKCP - eXtended Keccak Code Package.
|
14
14
|
This gem provides support for the standard SHA-3 fixed-length functions (224, 256, 384, and 512 bits),
|
15
15
|
as well as the SHAKE128/SHAKE256 extendable-output functions (XOFs), cSHAKE128/256, and KMAC as specified in NIST SP 800-185.'
|
16
|
-
|
16
|
+
DESC
|
17
17
|
spec.summary = 'SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST SP 800-185), powered by XKCP.'
|
18
18
|
|
19
19
|
spec.homepage = 'https://github.com/johanns/sha3'
|
@@ -24,11 +24,11 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.metadata['homepage_uri'] = spec.homepage
|
25
25
|
spec.metadata['documentation_uri'] = 'https://docs.jsg.io/sha3/index.html'
|
26
26
|
|
27
|
-
spec.post_install_message = <<-
|
27
|
+
spec.post_install_message = <<-NOTICE
|
28
28
|
[NOTICE] SHA3 version 2.0 introduces breaking changes to the API.
|
29
29
|
Please review the changelog and ensure compatibility with your application.
|
30
30
|
If you need the previous behavior, lock your Gemfile to version '~> 1.0'."
|
31
|
-
|
31
|
+
NOTICE
|
32
32
|
|
33
33
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
34
34
|
`git ls-files -z`.split("\x0").reject do |f|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sha3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johanns Gregorian
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- Rakefile
|
63
63
|
- certs/io+sha3@jsg.io.pem
|
64
64
|
- doc/sha3.rb
|
65
|
+
- ext/sha3/common.h
|
65
66
|
- ext/sha3/config.h
|
66
67
|
- ext/sha3/cshake.c
|
67
68
|
- ext/sha3/cshake.h
|
@@ -130,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
131
|
- !ruby/object:Gem::Version
|
131
132
|
version: '0'
|
132
133
|
requirements: []
|
133
|
-
rubygems_version: 3.
|
134
|
+
rubygems_version: 3.7.1
|
134
135
|
specification_version: 4
|
135
136
|
summary: SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST
|
136
137
|
SP 800-185), powered by XKCP.
|
metadata.gz.sig
CHANGED
Binary file
|