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
37static 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
48static 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
55MODULE = Digest::SHA		PACKAGE = Digest::SHA
56
57PROTOTYPES: ENABLE
58
59int
60shainit(s, alg)
61	SHA *	s
62	int	alg
63
64void
65sharewind(s)
66	SHA *	s
67
68unsigned long
69shawrite(bitstr, bitcnt, s)
70	unsigned char *	bitstr
71	unsigned long	bitcnt
72	SHA *	s
73
74SV *
75newSHA(classname, alg)
76	char *	classname
77	int 	alg
78PREINIT:
79	SHA *state;
80CODE:
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));
89OUTPUT:
90	RETVAL
91
92SV *
93clone(self)
94	SV *	self
95PREINIT:
96	SHA *state;
97	SHA *clone;
98CODE:
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);
106OUTPUT:
107	RETVAL
108
109void
110DESTROY(s)
111	SHA *	s
112CODE:
113	Safefree(s);
114
115SV *
116sha1(...)
117ALIAS:
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
139PREINIT:
140	int i;
141	UCHR *data;
142	STRLEN len;
143	SHA sha;
144	char *result;
145CODE:
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, (ULNG) 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);
168OUTPUT:
169	RETVAL
170
171SV *
172hmac_sha1(...)
173ALIAS:
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
195PREINIT:
196	int i;
197	UCHR *key = (UCHR *) "";
198	UCHR *data;
199	STRLEN len = 0;
200	HMAC hmac;
201	char *result;
202CODE:
203	if (items > 0) {
204		key = (UCHR *) (SvPVbyte(ST(items-1), len));
205	}
206	if (hmacinit(&hmac, ix2alg[ix], key, (UINT) 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, (ULNG) 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);
228OUTPUT:
229	RETVAL
230
231int
232hashsize(self)
233	SV *	self
234ALIAS:
235	Digest::SHA::hashsize = 0
236	Digest::SHA::algorithm = 1
237PREINIT:
238	SHA *state;
239CODE:
240	if ((state = getSHA(aTHX_ self)) == NULL)
241		XSRETURN_UNDEF;
242	RETVAL = ix ? state->alg : (int) (state->digestlen << 3);
243OUTPUT:
244	RETVAL
245
246void
247add(self, ...)
248	SV *	self
249PREINIT:
250	int i;
251	UCHR *data;
252	STRLEN len;
253	SHA *state;
254PPCODE:
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, (ULNG) len << 3, state);
265	}
266	XSRETURN(1);
267
268SV *
269digest(self)
270	SV *	self
271ALIAS:
272	Digest::SHA::digest = 0
273	Digest::SHA::hexdigest = 1
274	Digest::SHA::b64digest = 2
275PREINIT:
276	STRLEN len;
277	SHA *state;
278	char *result;
279CODE:
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);
294OUTPUT:
295	RETVAL
296
297SV *
298_getstate(self)
299	SV *	self
300PREINIT:
301	SHA *state;
302	UCHR buf[256];
303	UCHR *ptr = buf;
304CODE:
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));
317OUTPUT:
318	RETVAL
319
320void
321_putstate(self, packed_state)
322	SV *	self
323	SV *	packed_state
324PREINIT:
325	UINT bc;
326	STRLEN len;
327	SHA *state;
328	UCHR *data;
329PPCODE:
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
348void
349_addfilebin(self, f)
350	SV *		self
351	PerlIO *	f
352PREINIT:
353	SHA *state;
354	int n;
355	UCHR in[IO_BUFFER_SIZE];
356PPCODE:
357	if (!f || (state = getSHA(aTHX_ self)) == NULL)
358		XSRETURN_UNDEF;
359	while ((n = (int) PerlIO_read(f, in, sizeof(in))) > 0)
360		shawrite(in, (ULNG) n << 3, state);
361	XSRETURN(1);
362
363void
364_addfileuniv(self, f)
365	SV *		self
366	PerlIO *	f
367PREINIT:
368	UCHR c;
369	int n;
370	int cr = 0;
371	UCHR *src, *dst;
372	UCHR in[IO_BUFFER_SIZE+1];
373	SHA *state;
374PPCODE:
375	if (!f || (state = getSHA(aTHX_ self)) == NULL)
376		XSRETURN_UNDEF;
377	while ((n = (int) 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, 1UL << 3, state);
405	}
406	XSRETURN(1);
407