1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5/* try to be compatible with older perls */
6/* SvPV_nolen() macro first defined in 5.005_55 */
7/* this is slow, not threadsafe, but works */
8#include "patchlevel.h"
9#if (PATCHLEVEL == 4) || ((PATCHLEVEL == 5) && (SUBVERSION < 55))
10static STRLEN nolen_na;
11# define SvPV_nolen(sv) SvPV ((sv), nolen_na)
12#endif
13
14#include "rijndael.h"
15
16typedef struct cryptstate {
17  RIJNDAEL_context ctx;
18  UINT8 iv[RIJNDAEL_BLOCKSIZE];
19  int mode;
20} *Crypt__Rijndael;
21
22MODULE = Crypt::Rijndael		PACKAGE = Crypt::Rijndael
23
24PROTOTYPES: ENABLE
25
26  # newCONSTSUB is here as of 5.004_70
27
28BOOT:
29{
30#if (PATCHLEVEL > 4) || ((PATCHLEVEL == 4) && (SUBVERSION >= 70))
31  HV *stash = gv_stashpv("Crypt::Rijndael", 0);
32
33  newCONSTSUB (stash, "keysize",    newSViv (32)        );
34  newCONSTSUB (stash, "blocksize",  newSViv (16)        );
35  newCONSTSUB (stash, "MODE_ECB",   newSViv (MODE_ECB)  );
36  newCONSTSUB (stash, "MODE_CBC",   newSViv (MODE_CBC)  );
37  newCONSTSUB (stash, "MODE_CFB",   newSViv (MODE_CFB)  );
38  newCONSTSUB (stash, "MODE_PCBC",  newSViv (MODE_PCBC) );
39  newCONSTSUB (stash, "MODE_OFB",   newSViv (MODE_OFB)  );
40  newCONSTSUB (stash, "MODE_CTR",   newSViv (MODE_CTR)  );
41#endif
42}
43
44#if (PATCHLEVEL < 4) || ((PATCHLEVEL == 4) && (SUBVERSION < 70))
45
46int
47keysize(...)
48  CODE:
49     RETVAL=32;
50  OUTPUT:
51     RETVAL
52
53int
54blocksize(...)
55  CODE:
56     RETVAL=16;
57  OUTPUT:
58     RETVAL
59
60int
61MODE_ECB(...)
62  CODE:
63     RETVAL=MODE_ECB;
64  OUTPUT:
65     RETVAL
66
67int
68MODE_CBC(...)
69  CODE:
70     RETVAL=MODE_CBC;
71  OUTPUT:
72     RETVAL
73
74int
75MODE_CFB(...)
76  CODE:
77     RETVAL=MODE_CFB;
78  OUTPUT:
79     RETVAL
80
81int
82MODE_PCBC(...)
83  CODE:
84     RETVAL=MODE_PCBC;
85  OUTPUT:
86     RETVAL
87
88int
89MODE_OFB(...)
90  CODE:
91     RETVAL=MODE_OFB;
92  OUTPUT:
93     RETVAL
94
95int
96MODE_CTR(...)
97  CODE:
98     RETVAL=MODE_CTR;
99  OUTPUT:
100     RETVAL
101
102#endif
103
104
105Crypt::Rijndael
106new(class, key, mode=MODE_ECB)
107        SV *	class
108        SV *	key
109        int	mode
110        CODE:
111        {
112          STRLEN keysize;
113
114          if (!SvPOK (key))
115            croak("key must be a string scalar");
116
117          keysize = SvCUR(key);
118
119          if (keysize != 16 && keysize != 24 && keysize != 32)
120            croak ("wrong key length: key must be 128, 192 or 256 bits long");
121          if (mode != MODE_ECB && mode != MODE_CBC && mode != MODE_CFB && mode != MODE_OFB && mode != MODE_CTR)
122            croak ("illegal mode, see documentation for valid modes");
123
124          Newz(0, RETVAL, 1, struct cryptstate);
125	  RETVAL->ctx.mode = RETVAL->mode = mode;
126	  /* set the IV to zero on initialization */
127	  memset(RETVAL->iv, 0, RIJNDAEL_BLOCKSIZE);
128          rijndael_setup(&RETVAL->ctx, keysize, (UINT8 *) SvPV_nolen(key));
129
130	}
131	OUTPUT:
132        RETVAL
133
134SV *
135set_iv(self, data)
136	Crypt::Rijndael self
137	SV *	data
138
139	CODE:
140	{
141	  SV *res;
142	  STRLEN size;
143	  void *rawbytes = SvPV(data,size);
144
145	  if( size !=  RIJNDAEL_BLOCKSIZE )
146	  	croak( "set_iv: initial value must be the blocksize (%d bytes), but was %d bytes", RIJNDAEL_BLOCKSIZE, size );
147	  memcpy(self->iv, rawbytes, RIJNDAEL_BLOCKSIZE);
148	}
149
150SV *
151encrypt(self, data)
152        Crypt::Rijndael self
153        SV *	data
154        ALIAS:
155        	decrypt = 1
156        CODE:
157        {
158          SV *res;
159          STRLEN size;
160          void *rawbytes = SvPV(data,size);
161
162          if (size) {
163	    if (size % RIJNDAEL_BLOCKSIZE)
164	      croak ("encrypt: datasize not multiple of blocksize (%d bytes)", RIJNDAEL_BLOCKSIZE);
165
166	    RETVAL = NEWSV (0, size);
167	    SvPOK_only (RETVAL);
168	    SvCUR_set (RETVAL, size);
169	    (ix ? block_decrypt : block_encrypt)
170	      (&self->ctx, rawbytes, size, (UINT8 *) SvPV_nolen(RETVAL), self->iv);
171          } else
172            RETVAL = newSVpv ("", 0);
173        }
174	OUTPUT:
175        RETVAL
176
177
178void
179DESTROY(self)
180        Crypt::Rijndael self
181        CODE:
182        Safefree(self);
183