-
Notifications
You must be signed in to change notification settings - Fork 1
/
README
320 lines (250 loc) · 11.6 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
NAME
Crypt::Skip32 - 32-bit block cipher based on Skipjack
SYNOPSIS
use Crypt::Skip32;
my $cipher = new Crypt::Skip32 $key;
my $ciphertext = $cipher->encrypt($plaintext);
my $plaintext = $cipher->decrypt($ciphertext);
my $blocksize = $cipher->blocksize;
my $keysize = $cipher->keysize;
DESCRIPTION
SKIP32 is a 80-bit key, 32-bit block cipher based on Skipjack. The Perl
code for the algorithm is a direct translation from C to Perl of
skip32.c by Greg Rose found here:
http://www.qualcomm.com.au/PublicationsDocs/skip32.c
This cipher can be handy for scrambling small (32-bit) values when you
would like to obscure them while keeping the encrypted output size small
(also only 32 bits).
One example where Crypt::Skip32 has been useful: You have numeric
database record ids which increment sequentially. You would like to use
them in URLs, but you don't want to make it obvious how many X's you
have in the database by putting the ids directly in the URLs.
You can use Crypt::Skip32 to scramble ids and put the resulting 32-bit
value in URLs (perhaps as 8 hex digits or some other shorter encoding).
When a user requests a URL, you can unscramble the id to retrieve the
object from the database.
Warning: A 32-bit value can only go a little over 4 billion (American).
Plan ahead if what you need to encrypt might eventually go over this
limit.
FUNCTIONS
new
my $cipher = new Crypt::Skip32 $key;
Creates a new Crypt::Skip32 block cipher object, using $key, where
$key is a key of "keysize" bytes (10).
encrypt
my $ciphertext = $cipher->encrypt($plaintext);
Encrypt $plaintext and return the $ciphertext. The $plaintext must
be of "blocksize" bytes (4).
See the EXAMPLE below for hints on how to take a plain integer,
encrypt it, and encode it for use in URLs and other non-binary
formats.
decrypt
my $plaintext = $cipher->decrypt($ciphertext);
Decrypt $ciphertext and return the $plaintext. The $ciphertext must
be of "blocksize" bytes (4).
blocksize
my $blocksize = $cipher->blocksize;
my $blocksize = Crypt::Skip32->blocksize;
Returns the size (in bytes) of the block cipher. This is always 4
bytes (for 32 bits).
keysize
my $keysize = $cipher->keysize;
my $keysize = Crypt::Skip32->keysize;
Returns the size (in bytes) of the key. This is always 10 bytes (for
80 bits).
NOTES
If Crypt::Skip32::XS is installed, this module will use it and the
constructor will return an object of that type, though the interface is
identical. You can stick with the pure Perl version by setting the
CRYPT_SKIP32_PP environment variable before using this module.
If reporting a bug, please try to determine (if possible) if it is this
module or the XS one, and report it to the corresponding maintainer.
EXAMPLE
This sample code demonstrates how Crypt::Skip32 can be used to encrypt
unsigned integers and encode them for use in web URLs, form values, and
other places where short encrypted text might be useful.
use Crypt::Skip32;
# Create a cipher. Change the long hex string to your secret key.
my $key = pack("H20", "112233445566778899AA");
my $cipher = new Crypt::Skip32 $key; # Always 10 bytes!
# Encrypt an unsigned integer (under 2^32) into an 8-digit hex string.
my $number = 3493209676;
my $plaintext = pack("N", $number);
my $ciphertext = $cipher->encrypt($plaintext); # Always 4 bytes!
my $cipherhex = unpack("H8", $ciphertext);
print "$number encrypted and converted to hex: $cipherhex\n";
# Decrypt an encrypted, hexified unsigned integer.
my $ciphertext2 = pack("H8", $cipherhex);
my $plaintext2 = $cipher->decrypt($ciphertext2); # Always 4 bytes!
my $number2 = unpack("N", $plaintext2);
print "$cipherhex converted back and decrypted: $number2\n";
The above code generates the output:
3493209676 encrypted and converted to hex: 6da27100
6da27100 converted back and decrypted: 3493209676
CAVEATS
This initial alpha Perl implementation of Crypt::Skip32 has not been
extentively reviewed by cryptographic experts, nor has it been tested
extensively on many different platforms. It is recommended that this
code not be used for applications which require a high level of
security.
Reviewers and testers welcomed.
Though this module has been coded to follow a Crypt::CBC usable
interface, it is not intended for use in encrypting long chunks of text.
For those purposes, it is suggested you use another high quality, proven
cipher with a longer block size.
INSTALLATION
If your Linux distro does not have a prepared package for this module,
then the preferred method for installation is directly from the CPAN
using a command like:
sudo cpan Crypt::Skip32
SOURCE
The source for this module is being maintained on github:
https://github.com/alestic/Crypt-Skip32
Forks and patches will be reviewed, but please be aware that the
targeted functionality of this particular module is very narrow.
Feel free to build other abstractions on top of this module if you want
to make it easier to use or to create a particular application for its
use.
BUGS
Problems and feature requests can be submitted through the github
"issues" link:
https://github.com/alestic/Crypt-Skip32/issues
A gentle reminder sent directly to the author (below) may also help
increase awareness and attention.
SEE ALSO
The original SKIP32 implementation in C by Greg Rose:
http://www.qualcomm.com.au/PublicationsDocs/skip32.c
The 80-bit key, 64-bit block Skipjack cipher created by the NSA (Perl
code maintained by Julius C. Duque): Crypt::Skipjack
Crypt::Skip32::XS
AUTHOR
Perl code maintained by Eric Hammond <[email protected]>
http://www.anvilon.com
Original SKIP32 C code written 1999-04-27 by Greg Rose, based on an
implementation of the Skipjack algorithm written by Panu Rissanen.
CREDITS
The following have contributed to the Perl version:
John Laur
Joe Edmonds
gray
And, of course, this is entirely based on the C version written by:
Greg Rose
COPYRIGHT AND LICENSE
Copyright (C) 2007-2019 Eric Hammond <[email protected]>
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself, either Perl version 5.8.8 or, at
your option, any later version of Perl 5 you may have available.
The original C version of SKIP32 by Greg Rose (see below) is explicitly
"not copyright, no rights reserved". Even so, permission was requested
and granted to make a Perl version available on the CPAN.
ORIGINAL C SOURCE
/*
SKIP32 -- 32 bit block cipher based on SKIPJACK.
Written by Greg Rose, QUALCOMM Australia, 1999/04/27.
In common: F-table, G-permutation, key schedule.
Different: 24 round feistel structure.
Based on: Unoptimized test implementation of SKIPJACK algorithm
Panu Rissanen <[email protected]>
SKIPJACK and KEA Algorithm Specifications
Version 2.0
29 May 1998
Not copyright, no rights reserved.
*/
typedef unsigned char BYTE; /* 8 bits */
typedef unsigned short WORD; /* 16 bits */
const BYTE ftable[256] = {
0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9,
0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28,
0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53,
0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2,
0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8,
0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90,
0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76,
0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d,
0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18,
0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4,
0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40,
0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5,
0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2,
0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8,
0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac,
0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46
};
WORD
g(BYTE *key, int k, WORD w)
{
BYTE g1, g2, g3, g4, g5, g6;
g1 = (w>>8)&0xff;
g2 = w&0xff;
g3 = ftable[g2 ^ key[(4*k)%10]] ^ g1;
g4 = ftable[g3 ^ key[(4*k+1)%10]] ^ g2;
g5 = ftable[g4 ^ key[(4*k+2)%10]] ^ g3;
g6 = ftable[g5 ^ key[(4*k+3)%10]] ^ g4;
return ((g5<<8) + g6);
}
void
skip32(BYTE key[10], BYTE buf[4], int encrypt)
{
int k; /* round number */
int i; /* round counter */
int kstep;
WORD wl, wr;
/* sort out direction */
if (encrypt)
kstep = 1, k = 0;
else
kstep = -1, k = 23;
/* pack into words */
wl = (buf[0] << 8) + buf[1];
wr = (buf[2] << 8) + buf[3];
/* 24 feistel rounds, doubled up */
for (i = 0; i < 24/2; ++i) {
wr ^= g(key, k, wl) ^ k;
k += kstep;
wl ^= g(key, k, wr) ^ k;
k += kstep;
}
/* implicitly swap halves while unpacking */
buf[0] = wr >> 8; buf[1] = wr & 0xFF;
buf[2] = wl >> 8; buf[3] = wl & 0xFF;
}
#include <stdio.h>
int main(int ac, char *av[])
{
BYTE in[4] = { 0x33,0x22,0x11,0x00 };
BYTE key[10] = { 0x00,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11 };
int i, encrypt;
int bt;
if (ac == 1) {
skip32(key, in, 1);
printf("%02x%02x%02x%02x\n", in[0], in[1], in[2], in[3]);
if (in[0] != 0x81 || in[1] != 0x9d || in[2] != 0x5f || in[3] != 0x1f) {
printf("819d5f1f is the answer! Didn't encrypt correctly!\n");
return 1;
}
skip32(key, in, 0);
if (in[0] != 0x33 || in[1] != 0x22 || in[2] != 0x11 || in[3] != 0x00) {
printf("%02x%02x%02x%02x\n", in[0], in[1], in[2], in[3]);
printf("33221100 is the answer! Didn't decrypt correctly!\n");
return 1;
}
}
else if (ac != 4) {
fprintf(stderr, "usage: %s e/d kkkkkkkkkkkkkkkkkkkk dddddddd\n", av[0]);
return 1;
}
else {
encrypt = av[1][0] == 'e';
for (i = 0; i < 10; ++i) {
sscanf(&av[2][i*2], "%02x", &bt);
key[i] = bt;
}
for (i = 0; i < 4; ++i) {
sscanf(&av[3][i*2], "%02x", &bt);
in[i] = bt;
}
skip32(key, in, encrypt);
printf("%02x%02x%02x%02x\n", in[0], in[1], in[2], in[3]);
}
return 0;
}