@@ -116,75 +116,68 @@ static struct digest {
116
116
**
117
117
*/ REBNATIVE (checksum )
118
118
/*
119
- ** Computes checksum or hash value.
120
- **
121
- ** Note: Currently BINARY only.
122
- **
123
- ** Args:
124
- **
125
- ** data [any-string!] {Data to checksum}
126
- ** /part length
127
- ** /tcp {Returns an Internet TCP 16-bit checksum.}
128
- ** /secure {Returns a cryptographically secure checksum.}
129
- ** /hash {Returns a hash value}
130
- ** size [integer!] {Size of the hash table}
131
- ** /method {Method to use}
132
- ** word [word!] {Method: SHA1 MD5}
133
- ** /key {Returns keyed HMAC value}
134
- ** key-value [any-string! binary!] {Key to use}
135
- **
119
+ // checksum: native [
120
+ // {Computes a checksum, CRC, hash, or HMAC.}
121
+ // data [binary! string!] {If string, it will be UTF8 encoded}
122
+ // method [word!] {One of `system/catalog/checksums` and HASH}
123
+ // /with {Extra value for HMAC key or hash table size; not compatible with TCP/CRC24/CRC32/ADLER32 methods.}
124
+ // spec [any-string! binary! integer!] {String or binary for MD5/SHA* HMAC key, integer for hash table size.}
125
+ // /part {Limits to a given length}
126
+ // length
127
+ // ]
136
128
***********************************************************************/
137
129
{
138
- REBVAL * arg = D_ARG (ARG_CHECKSUM_DATA );
130
+ REBVAL * arg = D_ARG (ARG_CHECKSUM_DATA );
131
+ REBINT sym = VAL_WORD_CANON (D_ARG (ARG_CHECKSUM_METHOD ));
132
+ REBVAL * spec = D_ARG (ARG_CHECKSUM_SPEC );
139
133
REBINT sum ;
140
134
REBINT i ;
141
135
REBINT j ;
142
- REBSER * digest ;
143
- REBINT sym = SYM_SHA1 ;
144
- REBCNT len ;
136
+ REBSER * digest , * ser ;
137
+ REBCNT len , keylen ;
145
138
REBYTE * data ;
139
+ REBYTE * keycp ;
140
+
146
141
147
142
len = Partial1 (arg , D_ARG (ARG_CHECKSUM_LENGTH ));
148
143
149
144
if (IS_STRING (arg )) {
150
- // using `digest` just as a temp variable here!
151
- digest = Encode_UTF8_Value (arg , len , 0 );
152
- data = SERIES_DATA (digest );
153
- len = SERIES_LEN (digest ) - 1 ;
145
+ ser = Encode_UTF8_Value (arg , len , 0 );
146
+ data = SERIES_DATA (ser );
147
+ len = SERIES_LEN (ser ) - 1 ;
154
148
}
155
149
else {
156
150
data = VAL_BIN_DATA (arg );
157
151
}
158
152
159
-
160
-
161
- // Method word:
162
- if (D_REF (ARG_CHECKSUM_METHOD )) sym = VAL_WORD_CANON (D_ARG (ARG_CHECKSUM_WORD ));
163
-
164
- // If method, secure, or key... find matching digest:
165
- if (D_REF (ARG_CHECKSUM_METHOD ) || D_REF (ARG_CHECKSUM_SECURE ) || D_REF (ARG_CHECKSUM_KEY )) {
166
-
167
- if (sym == SYM_CRC32 || sym == SYM_ADLER32 ) {
168
- if (D_REF (ARG_CHECKSUM_SECURE ) || D_REF (ARG_CHECKSUM_KEY )) Trap0 (RE_BAD_REFINES );
169
- i = (sym == SYM_CRC32 ) ? CRC32 (data , len ) : z_adler32_z (0x00000001L , data , len );
170
- DS_RET_INT (i );
171
- return R_RET ;
172
- }
173
-
153
+ if (sym > SYM_CRC32 && sym <= SYM_SHA512 ) {
154
+ // O: could be optimized using index computed from `sym`
155
+ // find matching digest:
174
156
for (i = 0 ; i < sizeof (digests ) / sizeof (digests [0 ]); i ++ ) {
175
157
176
158
if (digests [i ].index == sym ) {
177
159
178
160
digest = Make_Series (digests [i ].len , 1 , FALSE);
179
161
LABEL_SERIES (digest , "checksum digest" );
180
162
181
- if (D_REF (ARG_CHECKSUM_KEY )) {
163
+ if (D_REF (ARG_CHECKSUM_WITH )) { // HMAC
164
+ if (IS_INTEGER (spec ))
165
+ Trap1 (RE_BAD_REFINE , D_ARG (ARG_CHECKSUM_SPEC ));
166
+
167
+ if (IS_BINARY (spec )) {
168
+ keycp = VAL_BIN_DATA (spec );
169
+ keylen = VAL_LEN (spec );
170
+ }
171
+ else {
172
+ // normalize to UTF8 first
173
+ ser = Encode_UTF8_Value (spec , VAL_LEN (spec ), 0 );
174
+ keycp = SERIES_DATA (ser );
175
+ keylen = SERIES_LEN (ser ) - 1 ;
176
+ }
182
177
REBYTE tmpdigest [128 ]; // Size must be max of all digest[].len;
183
178
REBYTE ipad [128 ],opad [128 ]; // Size must be max of all digest[].hmacblock;
184
179
void * ctx = Make_Mem (digests [i ].ctxsize ());
185
- REBVAL * key = D_ARG (ARG_CHECKSUM_KEY_VALUE );
186
- REBYTE * keycp = VAL_BIN_DATA (key );
187
- int keylen = VAL_LEN (key );
180
+
188
181
int blocklen = digests [i ].hmacblock ;
189
182
190
183
if (keylen > blocklen ) {
@@ -224,23 +217,34 @@ static struct digest {
224
217
return 0 ;
225
218
}
226
219
}
227
-
228
- Trap_Arg ( D_ARG ( ARG_CHECKSUM_WORD ) );
220
+ // used correct name, but diggest was not found (excluded from build)
221
+ Trap0 ( RE_FEATURE_NA );
229
222
}
230
- else if (D_REF (ARG_CHECKSUM_TCP )) { // /tcp
231
- i = Compute_IPC (data , len );
223
+
224
+ if (D_REF (ARG_CHECKSUM_WITH ) && ((sym > SYM_HASH && sym <= SYM_CRC32 ) || sym == SYM_TCP ))
225
+ Trap0 (RE_BAD_REFINES );
226
+
227
+ if (sym == SYM_CRC32 || sym == SYM_ADLER32 ) {
228
+ i = (sym == SYM_CRC32 ) ? CRC32 (data , len ) : z_adler32_z (0x00000001L , data , len );
232
229
}
233
- else if (D_REF (ARG_CHECKSUM_HASH )) { // /hash
234
- sum = VAL_INT32 (D_ARG (ARG_CHECKSUM_SIZE )); // /size
230
+ else if (sym == SYM_HASH ) { // /hash
231
+ if (!D_REF (ARG_CHECKSUM_WITH )) Trap0 (RE_MISSING_ARG );
232
+ if (!IS_INTEGER (spec )) Trap1 (RE_BAD_REFINE , D_ARG (ARG_CHECKSUM_SPEC ));
233
+ sum = VAL_INT32 (spec ); // size of the hash table
235
234
if (sum <= 1 ) sum = 1 ;
236
235
i = Hash_String (data , len ) % sum ;
237
236
}
238
- else {
237
+ else if ( sym == SYM_CRC24 ) {
239
238
i = Compute_CRC24 (data , len );
240
239
}
240
+ else if (sym == SYM_TCP ) {
241
+ i = Compute_IPC (data , len );
242
+ }
243
+ else {
244
+ Trap_Arg (D_ARG (ARG_CHECKSUM_METHOD ));
245
+ }
241
246
242
247
DS_RET_INT (i );
243
-
244
248
return R_RET ;
245
249
}
246
250
0 commit comments