This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Update Archive-Tar to CPAN version 2.22
[perl5.git] / cpan / Digest-SHA / SHA.xs
1 #define PERL_NO_GET_CONTEXT
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5
6 #ifdef SvPVbyte
7         #if PERL_REVISION == 5 && PERL_VERSION < 8
8                 #undef SvPVbyte
9                 #define SvPVbyte(sv, lp) \
10                         (sv_utf8_downgrade((sv), 0), SvPV((sv), (lp)))
11         #endif
12 #else
13         #define SvPVbyte SvPV
14 #endif
15
16 #ifndef dTHX
17         #define pTHX_
18         #define aTHX_
19 #endif
20
21 #ifndef PerlIO
22         #define PerlIO                          FILE
23         #define PerlIO_read(f, buf, count)      fread(buf, 1, count, f)
24 #endif
25
26 #ifndef sv_derived_from
27         #include "src/sdf.c"
28 #endif
29
30 #ifndef Newx
31         #define Newx(ptr, num, type)    New(0, ptr, num, type)
32         #define Newxz(ptr, num, type)   Newz(0, ptr, num, type)
33 #endif
34
35 #include "src/sha.c"
36
37 static const int ix2alg[] =
38         {1,1,1,224,224,224,256,256,256,384,384,384,512,512,512,
39         512224,512224,512224,512256,512256,512256};
40
41 #ifndef INT2PTR
42 #define INT2PTR(p, i) (p) (i)
43 #endif
44
45 #define MAX_WRITE_SIZE 16384
46 #define IO_BUFFER_SIZE 4096
47
48 static SHA *getSHA(pTHX_ SV *self)
49 {
50         if (!sv_isobject(self) || !sv_derived_from(self, "Digest::SHA"))
51                 return(NULL);
52         return INT2PTR(SHA *, SvIV(SvRV(self)));
53 }
54
55 MODULE = Digest::SHA            PACKAGE = Digest::SHA
56
57 PROTOTYPES: ENABLE
58
59 int
60 shainit(s, alg)
61         SHA *   s
62         int     alg
63
64 void
65 sharewind(s)
66         SHA *   s
67
68 unsigned long
69 shawrite(bitstr, bitcnt, s)
70         unsigned char * bitstr
71         unsigned long   bitcnt
72         SHA *   s
73
74 SV *
75 newSHA(classname, alg)
76         char *  classname
77         int     alg
78 PREINIT:
79         SHA *state;
80 CODE:
81         Newxz(state, 1, SHA);
82         if (!shainit(state, alg)) {
83                 Safefree(state);
84                 XSRETURN_UNDEF;
85         }
86         RETVAL = newSV(0);
87         sv_setref_pv(RETVAL, classname, (void *) state);
88         SvREADONLY_on(SvRV(RETVAL));
89 OUTPUT:
90         RETVAL
91
92 SV *
93 clone(self)
94         SV *    self
95 PREINIT:
96         SHA *state;
97         SHA *clone;
98 CODE:
99         if ((state = getSHA(aTHX_ self)) == NULL)
100                 XSRETURN_UNDEF;
101         Newx(clone, 1, SHA);
102         RETVAL = newSV(0);
103         sv_setref_pv(RETVAL, sv_reftype(SvRV(self), 1), (void *) clone);
104         SvREADONLY_on(SvRV(RETVAL));
105         Copy(state, clone, 1, SHA);
106 OUTPUT:
107         RETVAL
108
109 void
110 DESTROY(s)
111         SHA *   s
112 CODE:
113         Safefree(s);
114         
115 SV *
116 sha1(...)
117 ALIAS:
118         Digest::SHA::sha1 = 0
119         Digest::SHA::sha1_hex = 1
120         Digest::SHA::sha1_base64 = 2
121         Digest::SHA::sha224 = 3
122         Digest::SHA::sha224_hex = 4
123         Digest::SHA::sha224_base64 = 5
124         Digest::SHA::sha256 = 6
125         Digest::SHA::sha256_hex = 7
126         Digest::SHA::sha256_base64 = 8
127         Digest::SHA::sha384 = 9
128         Digest::SHA::sha384_hex = 10
129         Digest::SHA::sha384_base64 = 11
130         Digest::SHA::sha512 = 12
131         Digest::SHA::sha512_hex = 13
132         Digest::SHA::sha512_base64 = 14
133         Digest::SHA::sha512224 = 15
134         Digest::SHA::sha512224_hex = 16
135         Digest::SHA::sha512224_base64 = 17
136         Digest::SHA::sha512256 = 18
137         Digest::SHA::sha512256_hex = 19
138         Digest::SHA::sha512256_base64 = 20
139 PREINIT:
140         int i;
141         UCHR *data;
142         STRLEN len;
143         SHA sha;
144         char *result;
145 CODE:
146         if (!shainit(&sha, ix2alg[ix]))
147                 XSRETURN_UNDEF;
148         for (i = 0; i < items; i++) {
149                 data = (UCHR *) (SvPVbyte(ST(i), len));
150                 while (len > MAX_WRITE_SIZE) {
151                         shawrite(data, MAX_WRITE_SIZE << 3, &sha);
152                         data += MAX_WRITE_SIZE;
153                         len  -= MAX_WRITE_SIZE;
154                 }
155                 shawrite(data, len << 3, &sha);
156         }
157         shafinish(&sha);
158         len = 0;
159         if (ix % 3 == 0) {
160                 result = (char *) shadigest(&sha);
161                 len = sha.digestlen;
162         }
163         else if (ix % 3 == 1)
164                 result = shahex(&sha);
165         else
166                 result = shabase64(&sha);
167         RETVAL = newSVpv(result, len);
168 OUTPUT:
169         RETVAL
170
171 SV *
172 hmac_sha1(...)
173 ALIAS:
174         Digest::SHA::hmac_sha1 = 0
175         Digest::SHA::hmac_sha1_hex = 1
176         Digest::SHA::hmac_sha1_base64 = 2
177         Digest::SHA::hmac_sha224 = 3
178         Digest::SHA::hmac_sha224_hex = 4
179         Digest::SHA::hmac_sha224_base64 = 5
180         Digest::SHA::hmac_sha256 = 6
181         Digest::SHA::hmac_sha256_hex = 7
182         Digest::SHA::hmac_sha256_base64 = 8
183         Digest::SHA::hmac_sha384 = 9
184         Digest::SHA::hmac_sha384_hex = 10
185         Digest::SHA::hmac_sha384_base64 = 11
186         Digest::SHA::hmac_sha512 = 12
187         Digest::SHA::hmac_sha512_hex = 13
188         Digest::SHA::hmac_sha512_base64 = 14
189         Digest::SHA::hmac_sha512224 = 15
190         Digest::SHA::hmac_sha512224_hex = 16
191         Digest::SHA::hmac_sha512224_base64 = 17
192         Digest::SHA::hmac_sha512256 = 18
193         Digest::SHA::hmac_sha512256_hex = 19
194         Digest::SHA::hmac_sha512256_base64 = 20
195 PREINIT:
196         int i;
197         UCHR *key = (UCHR *) "";
198         UCHR *data;
199         STRLEN len = 0;
200         HMAC hmac;
201         char *result;
202 CODE:
203         if (items > 0) {
204                 key = (UCHR *) (SvPVbyte(ST(items-1), len));
205         }
206         if (hmacinit(&hmac, ix2alg[ix], key, len) == NULL)
207                 XSRETURN_UNDEF;
208         for (i = 0; i < items - 1; i++) {
209                 data = (UCHR *) (SvPVbyte(ST(i), len));
210                 while (len > MAX_WRITE_SIZE) {
211                         hmacwrite(data, MAX_WRITE_SIZE << 3, &hmac);
212                         data += MAX_WRITE_SIZE;
213                         len  -= MAX_WRITE_SIZE;
214                 }
215                 hmacwrite(data, len << 3, &hmac);
216         }
217         hmacfinish(&hmac);
218         len = 0;
219         if (ix % 3 == 0) {
220                 result = (char *) hmacdigest(&hmac);
221                 len = hmac.digestlen;
222         }
223         else if (ix % 3 == 1)
224                 result = hmachex(&hmac);
225         else
226                 result = hmacbase64(&hmac);
227         RETVAL = newSVpv(result, len);
228 OUTPUT:
229         RETVAL
230
231 int
232 hashsize(self)
233         SV *    self
234 ALIAS:
235         Digest::SHA::hashsize = 0
236         Digest::SHA::algorithm = 1
237 PREINIT:
238         SHA *state;
239 CODE:
240         if ((state = getSHA(aTHX_ self)) == NULL)
241                 XSRETURN_UNDEF;
242         RETVAL = ix ? state->alg : (int) (state->digestlen << 3);
243 OUTPUT:
244         RETVAL
245
246 void
247 add(self, ...)
248         SV *    self
249 PREINIT:
250         int i;
251         UCHR *data;
252         STRLEN len;
253         SHA *state;
254 PPCODE:
255         if ((state = getSHA(aTHX_ self)) == NULL)
256                 XSRETURN_UNDEF;
257         for (i = 1; i < items; i++) {
258                 data = (UCHR *) (SvPVbyte(ST(i), len));
259                 while (len > MAX_WRITE_SIZE) {
260                         shawrite(data, MAX_WRITE_SIZE << 3, state);
261                         data += MAX_WRITE_SIZE;
262                         len  -= MAX_WRITE_SIZE;
263                 }
264                 shawrite(data, len << 3, state);
265         }
266         XSRETURN(1);
267
268 SV *
269 digest(self)
270         SV *    self
271 ALIAS:
272         Digest::SHA::digest = 0
273         Digest::SHA::hexdigest = 1
274         Digest::SHA::b64digest = 2
275 PREINIT:
276         STRLEN len;
277         SHA *state;
278         char *result;
279 CODE:
280         if ((state = getSHA(aTHX_ self)) == NULL)
281                 XSRETURN_UNDEF;
282         shafinish(state);
283         len = 0;
284         if (ix == 0) {
285                 result = (char *) shadigest(state);
286                 len = state->digestlen;
287         }
288         else if (ix == 1)
289                 result = shahex(state);
290         else
291                 result = shabase64(state);
292         RETVAL = newSVpv(result, len);
293         sharewind(state);
294 OUTPUT:
295         RETVAL
296
297 SV *
298 _getstate(self)
299         SV *    self
300 PREINIT:
301         SHA *state;
302         UCHR buf[256];
303         UCHR *ptr = buf;
304 CODE:
305         if ((state = getSHA(aTHX_ self)) == NULL)
306                 XSRETURN_UNDEF;
307         Copy(digcpy(state), ptr, state->alg <= SHA256 ? 32 : 64, UCHR);
308         ptr += state->alg <= SHA256 ? 32 : 64;
309         Copy(state->block, ptr, state->alg <= SHA256 ? 64 : 128, UCHR);
310         ptr += state->alg <= SHA256 ? 64 : 128;
311         ptr = w32mem(ptr, state->blockcnt);
312         ptr = w32mem(ptr, state->lenhh);
313         ptr = w32mem(ptr, state->lenhl);
314         ptr = w32mem(ptr, state->lenlh);
315         ptr = w32mem(ptr, state->lenll);
316         RETVAL = newSVpv((char *) buf, (STRLEN) (ptr - buf));
317 OUTPUT:
318         RETVAL
319
320 void
321 _putstate(self, packed_state)
322         SV *    self
323         SV *    packed_state
324 PREINIT:
325         UINT bc;
326         STRLEN len;
327         SHA *state;
328         UCHR *data;
329 PPCODE:
330         if ((state = getSHA(aTHX_ self)) == NULL)
331                 XSRETURN_UNDEF;
332         data = (UCHR *) SvPV(packed_state, len);
333         if (len != (state->alg <= SHA256 ? 116U : 212U))
334                 XSRETURN_UNDEF;
335         data = statecpy(state, data);
336         Copy(data, state->block, state->blocksize >> 3, UCHR);
337         data += (state->blocksize >> 3);
338         bc = memw32(data), data += 4;
339         if (bc >= (state->alg <= SHA256 ? 512U : 1024U))
340                 XSRETURN_UNDEF;
341         state->blockcnt = bc;
342         state->lenhh = memw32(data), data += 4;
343         state->lenhl = memw32(data), data += 4;
344         state->lenlh = memw32(data), data += 4;
345         state->lenll = memw32(data);
346         XSRETURN(1);
347
348 void
349 _addfilebin(self, f)
350         SV *            self
351         PerlIO *        f
352 PREINIT:
353         SHA *state;
354         int n;
355         UCHR in[IO_BUFFER_SIZE];
356 PPCODE:
357         if (!f || (state = getSHA(aTHX_ self)) == NULL)
358                 XSRETURN_UNDEF;
359         while ((n = PerlIO_read(f, in, sizeof(in))) > 0)
360                 shawrite(in, (ULNG) n << 3, state);
361         XSRETURN(1);
362
363 void
364 _addfileuniv(self, f)
365         SV *            self
366         PerlIO *        f
367 PREINIT:
368         UCHR c;
369         int n;
370         int cr = 0;
371         UCHR *src, *dst;
372         UCHR in[IO_BUFFER_SIZE+1];
373         SHA *state;
374 PPCODE:
375         if (!f || (state = getSHA(aTHX_ self)) == NULL)
376                 XSRETURN_UNDEF;
377         while ((n = PerlIO_read(f, in+1, IO_BUFFER_SIZE)) > 0) {
378                 for (dst = in, src = in + 1; n; n--) {
379                         c = *src++;
380                         if (!cr) {
381                                 if (c == '\015')
382                                         cr = 1;
383                                 else
384                                         *dst++ = c;
385                         }
386                         else {
387                                 if (c == '\015')
388                                         *dst++ = '\012';
389                                 else if (c == '\012') {
390                                         *dst++ = '\012';
391                                         cr = 0;
392                                 }
393                                 else {
394                                         *dst++ = '\012';
395                                         *dst++ = c;
396                                         cr = 0;
397                                 }
398                         }
399                 }
400                 shawrite(in, (ULNG) (dst - in) << 3, state);
401         }
402         if (cr) {
403                 in[0] = '\012';
404                 shawrite(in, 1 << 3, state);
405         }
406         XSRETURN(1);