1/* rijndael - An implementation of the Rijndael cipher.
2 * Copyright (C) 2000, 2001 Rafael R. Sevilla <sevillar@team.ph.inter.net>
3 *
4 * Currently maintained by brian d foy, <bdfoy@cpan.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "EXTERN.h"
22#include "perl.h"
23#include "XSUB.h"
24
25/* try to be compatible with older perls */
26/* SvPV_nolen() macro first defined in 5.005_55 */
27/* this is slow, not threadsafe, but works */
28#include "patchlevel.h"
29#if (PATCHLEVEL == 4) || ((PATCHLEVEL == 5) && (SUBVERSION < 55))
30static STRLEN nolen_na;
31# define SvPV_nolen(sv) SvPV ((sv), nolen_na)
32#endif
33
34#include "rijndael.h"
35
36typedef struct cryptstate {
37  RIJNDAEL_context ctx;
38  UINT8 iv[RIJNDAEL_BLOCKSIZE];
39  int mode;
40} *Crypt__Rijndael;
41
42MODULE = Crypt::Rijndael		PACKAGE = Crypt::Rijndael
43
44PROTOTYPES: ENABLE
45
46  # newCONSTSUB is here as of 5.004_70
47
48BOOT:
49{
50#if (PATCHLEVEL > 4) || ((PATCHLEVEL == 4) && (SUBVERSION >= 70))
51  HV *stash = gv_stashpv("Crypt::Rijndael", 0);
52
53  newCONSTSUB (stash, "keysize",    newSViv (32)        );
54  newCONSTSUB (stash, "blocksize",  newSViv (16)        );
55  newCONSTSUB (stash, "MODE_ECB",   newSViv (MODE_ECB)  );
56  newCONSTSUB (stash, "MODE_CBC",   newSViv (MODE_CBC)  );
57  newCONSTSUB (stash, "MODE_CFB",   newSViv (MODE_CFB)  );
58  newCONSTSUB (stash, "MODE_PCBC",  newSViv (MODE_PCBC) );
59  newCONSTSUB (stash, "MODE_OFB",   newSViv (MODE_OFB)  );
60  newCONSTSUB (stash, "MODE_CTR",   newSViv (MODE_CTR)  );
61#endif
62}
63
64#if (PATCHLEVEL < 4) || ((PATCHLEVEL == 4) && (SUBVERSION < 70))
65
66int
67keysize(...)
68  CODE:
69     RETVAL=32;
70  OUTPUT:
71     RETVAL
72
73int
74blocksize(...)
75  CODE:
76     RETVAL=16;
77  OUTPUT:
78     RETVAL
79
80int
81MODE_ECB(...)
82  CODE:
83     RETVAL=MODE_ECB;
84  OUTPUT:
85     RETVAL
86
87int
88MODE_CBC(...)
89  CODE:
90     RETVAL=MODE_CBC;
91  OUTPUT:
92     RETVAL
93
94int
95MODE_CFB(...)
96  CODE:
97     RETVAL=MODE_CFB;
98  OUTPUT:
99     RETVAL
100
101int
102MODE_PCBC(...)
103  CODE:
104     RETVAL=MODE_PCBC;
105  OUTPUT:
106     RETVAL
107
108int
109MODE_OFB(...)
110  CODE:
111     RETVAL=MODE_OFB;
112  OUTPUT:
113     RETVAL
114
115int
116MODE_CTR(...)
117  CODE:
118     RETVAL=MODE_CTR;
119  OUTPUT:
120     RETVAL
121
122#endif
123
124
125Crypt::Rijndael
126new(class, key, mode=MODE_ECB)
127        SV *	class
128        SV *	key
129        int	mode
130        CODE:
131        {
132          STRLEN keysize;
133
134          if (!SvPOK (key))
135            croak("key must be an untainted string scalar");
136
137          keysize = SvCUR(key);
138
139          if (keysize != 16 && keysize != 24 && keysize != 32)
140            croak ("wrong key length: key must be 128, 192 or 256 bits long");
141          if (mode != MODE_ECB && mode != MODE_CBC && mode != MODE_CFB && mode != MODE_OFB && mode != MODE_CTR)
142            croak ("illegal mode, see documentation for valid modes");
143
144          Newz(0, RETVAL, 1, struct cryptstate);
145	  RETVAL->ctx.mode = RETVAL->mode = mode;
146	  /* set the IV to zero on initialization */
147	  memset(RETVAL->iv, 0, RIJNDAEL_BLOCKSIZE);
148          rijndael_setup(&RETVAL->ctx, keysize, (UINT8 *) SvPV_nolen(key));
149
150	}
151	OUTPUT:
152        RETVAL
153
154SV *
155set_iv(self, data)
156	Crypt::Rijndael self
157	SV *	data
158
159	CODE:
160	{
161	  SV *res;
162	  STRLEN size;
163	  void *rawbytes = SvPV(data,size);
164
165	  if( size !=  RIJNDAEL_BLOCKSIZE )
166	  	croak( "set_iv: initial value must be the blocksize (%d bytes), but was %d bytes", RIJNDAEL_BLOCKSIZE, size );
167	  memcpy(self->iv, rawbytes, RIJNDAEL_BLOCKSIZE);
168	}
169
170SV *
171encrypt(self, data)
172        Crypt::Rijndael self
173        SV *	data
174        ALIAS:
175        	decrypt = 1
176        CODE:
177        {
178          SV *res;
179          STRLEN size;
180          void *rawbytes = SvPV(data,size);
181
182          if (size) {
183	    if (size % RIJNDAEL_BLOCKSIZE)
184	      croak ("encrypt: datasize not multiple of blocksize (%d bytes)", RIJNDAEL_BLOCKSIZE);
185
186	    RETVAL = NEWSV (0, size);
187	    SvPOK_only (RETVAL);
188	    SvCUR_set (RETVAL, size);
189	    (ix ? block_decrypt : block_encrypt)
190	      (&self->ctx, rawbytes, size, (UINT8 *) SvPV_nolen(RETVAL), self->iv);
191          } else
192            RETVAL = newSVpv ("", 0);
193        }
194	OUTPUT:
195        RETVAL
196
197
198void
199DESTROY(self)
200        Crypt::Rijndael self
201        CODE:
202        Safefree(self);
203