1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4 
5 #include "ppport.h"
6 
7 #ifndef bytes_from_utf8
8 
9 /* 5.6.0 has UTF-8 scalars, but lacks the utility bytes_from_utf8() */
10 
11 static U8 *
bytes_from_utf8(U8 * orig,STRLEN * len_p,bool * is_utf8_p)12 bytes_from_utf8(U8 *orig, STRLEN *len_p, bool *is_utf8_p)
13 {
14 	STRLEN orig_len = *len_p;
15 	U8 *orig_end = orig + orig_len;
16 	STRLEN new_len = orig_len;
17 	U8 *new;
18 	U8 *p, *q;
19 	if(!*is_utf8_p)
20 		return orig;
21 	for(p = orig; p != orig_end; ) {
22 		U8 fb = *p++, sb;
23 		if(fb <= 0x7f)
24 			continue;
25 		if(p == orig_end || !(fb >= 0xc2 && fb <= 0xc3))
26 			return orig;
27 		sb = *p++;
28 		if(!(sb >= 0x80 && sb <= 0xbf))
29 			return orig;
30 		new_len--;
31 	}
32 	if(new_len == orig_len) {
33 		*is_utf8_p = 0;
34 		return orig;
35 	}
36 	Newz(0, new, new_len+1, U8);
37 	for(p = orig, q = new; p != orig_end; ) {
38 		U8 fb = *p++;
39 		*q++ = fb <= 0x7f ? fb : ((fb & 0x03) << 6) | (*p++ & 0x3f);
40 	}
41 	*q = 0;
42 	*len_p = new_len;
43 	*is_utf8_p = 0;
44 	return new;
45 }
46 
47 #endif /* !bytes_from_utf8 */
48 
49 #include <./fcrypt/fcrypt.h>
50 
51 static void
sv_to_octets(U8 ** octets_p,STRLEN * len_p,bool * must_free_p,SV * sv)52 sv_to_octets(U8 **octets_p, STRLEN *len_p, bool *must_free_p, SV *sv)
53 {
54   U8 *in_str = SvPV(sv, *len_p);
55   bool is_utf8 = !!SvUTF8(sv);
56   *octets_p = bytes_from_utf8(in_str, len_p, &is_utf8);
57   if(is_utf8)
58     croak("input must contain only octets");
59   *must_free_p = *octets_p != in_str;
60 }
61 
62 static void
sv_to_cblock(des_cblock block,SV * in_block)63 sv_to_cblock(des_cblock block, SV *in_block)
64 {
65   U8 *in_octets;
66   STRLEN in_len;
67   bool must_free;
68   sv_to_octets(&in_octets, &in_len, &must_free, in_block);
69   if(in_len != 8)
70     croak("data block must be eight octets long");
71   memcpy(block, in_octets, 8);
72   if(must_free)
73     Safefree(in_octets);
74 }
75 
76 MODULE = Crypt::UnixCrypt_XS		PACKAGE = Crypt::UnixCrypt_XS
77 
78 char *
79 crypt( password, salt )
80   SV *password
81   SV *salt
82   CODE:
83     STRLEN password_len, salt_len;
84     U8 *password_octets, *salt_octets;
85     bool password_tofree, salt_tofree;
86     char outbuf[21];
87     sv_to_octets(&password_octets, &password_len, &password_tofree, password);
88     sv_to_octets(&salt_octets, &salt_len, &salt_tofree, salt);
89     des_fcrypt((char *)password_octets, password_len,
90 	(char *)salt_octets, salt_len, outbuf);
91     if(password_tofree)
92       Safefree(password_octets);
93     if(salt_tofree)
94       Safefree(salt_octets);
95     RETVAL = outbuf;
96   OUTPUT:
97     RETVAL
98 
99 SV *
100 crypt_rounds( password, nrounds, saltnum, in_block )
101   SV *password
102   unsigned long nrounds
103   unsigned long saltnum
104   SV *in_block
105   CODE:
106     STRLEN password_len;
107     U8 *password_octets;
108     bool password_tofree;
109     des_cblock key, block;
110     sv_to_octets(&password_octets, &password_len, &password_tofree, password);
111     sv_to_cblock(block, in_block);
112     trad_password_to_key(key, (char *)password_octets, password_len);
113     if(password_tofree)
114       Safefree(password_octets);
115     crypt_rounds(key, nrounds, saltnum, block);
116     RETVAL = newSVpvn(block, 8);
117   OUTPUT:
118     RETVAL
119 
120 SV *
121 fold_password( password )
122   SV *password
123   CODE:
124     STRLEN password_len;
125     U8 *password_octets;
126     bool password_tofree;
127     des_cblock key;
128     int i;
129     sv_to_octets(&password_octets, &password_len, &password_tofree, password);
130     ext_password_to_key(key, (char *)password_octets, password_len);
131     if(password_tofree)
132       Safefree(password_octets);
133     for(i=0; i<8; i++)
134       key[i] = (key[i] & 0xfe) >> 1;
135     RETVAL = newSVpvn(key, 8);
136   OUTPUT:
137     RETVAL
138 
139 SV *
140 base64_to_block( base64 )
141   SV *base64
142   CODE:
143     STRLEN base64_len;
144     U8 *base64_octets;
145     bool base64_tofree;
146     des_cblock block;
147     sv_to_octets(&base64_octets, &base64_len, &base64_tofree, base64);
148     if(base64_len != 11)
149       croak("data block in base 64 must be eleven characters long");
150     base64_to_block(block, (char *)base64_octets);
151     if(base64_tofree)
152       Safefree(base64_octets);
153     RETVAL = newSVpvn(block, 8);
154   OUTPUT:
155     RETVAL
156 
157 char *
158 block_to_base64( in_block )
159   SV *in_block
160   CODE:
161     des_cblock block;
162     char base64[12];
163     sv_to_cblock(block, in_block);
164     block_to_base64(block, base64);
165     RETVAL = base64;
166   OUTPUT:
167     RETVAL
168 
169 unsigned long
170 base64_to_int24( base64 )
171   SV *base64
172   CODE:
173     STRLEN base64_len;
174     U8 *base64_octets;
175     bool base64_tofree;
176     sv_to_octets(&base64_octets, &base64_len, &base64_tofree, base64);
177     if(base64_len != 4)
178       croak("24-bit integer in base 64 must be four characters long");
179     RETVAL = base64_to_int24((char *)base64_octets);
180     if(base64_tofree)
181       Safefree(base64_octets);
182   OUTPUT:
183     RETVAL
184 
185 char *
186 int24_to_base64( val )
187   unsigned long val;
188   CODE:
189     char base64[5];
190     int24_to_base64(val, base64);
191     RETVAL = base64;
192   OUTPUT:
193     RETVAL
194 
195 unsigned long
196 base64_to_int12( base64 )
197   SV *base64
198   CODE:
199     STRLEN base64_len;
200     U8 *base64_octets;
201     bool base64_tofree;
202     sv_to_octets(&base64_octets, &base64_len, &base64_tofree, base64);
203     if(base64_len != 2)
204       croak("12-bit integer in base 64 must be two characters long");
205     RETVAL = base64_to_int12((char *)base64_octets);
206     if(base64_tofree)
207       Safefree(base64_octets);
208   OUTPUT:
209     RETVAL
210 
211 char *
212 int12_to_base64( val )
213   unsigned long val;
214   CODE:
215     char base64[3];
216     int12_to_base64(val, base64);
217     RETVAL = base64;
218   OUTPUT:
219     RETVAL
220