1
// ---------------------------------------------------------------------------
3
// - afnix:sec module - RC2 block cipher class implementation -
4
// ---------------------------------------------------------------------------
5
// - This program is free software; you can redistribute it and/or modify -
6
// - it provided that this copyright notice is kept intact. -
8
// - This program is distributed in the hope that it will be useful, but -
9
// - without any warranty; without even the implied warranty of -
10
// - merchantability or fitness for a particular purpose. In no event shall -
11
// - the copyright holder be liable for any direct, indirect, incidental or -
12
// - special damages arising in any way out of the use of this software. -
13
// ---------------------------------------------------------------------------
14
// - copyright (c) 1999-2011 amaury darsch -
15
// ---------------------------------------------------------------------------
19
#include "Integer.hpp"
20
#include "Cryptics.hxx"
21
#include "QuarkZone.hpp"
25
// -------------------------------------------------------------------------
26
// - private section -
27
// -------------------------------------------------------------------------
29
// RC2 block cipher constants
30
static const char* RC2_ALGO_NAME = "RC2";
31
static const long RC2_BLOK_SIZE = 8;
32
static const long RC2_WORD_SIZE = RC2_BLOK_SIZE / 2;
34
// RC2 valid key constants
35
static const long RC2_VKEY_BITS = 1024;
36
static const long RC2_VKEY_SIZE = RC2_VKEY_BITS / 8;
38
// RC2 effective key constants
39
static const long RC2_EKEY_BITS = 1024;
40
static const long RC2_EKEY_SIZE = RC2_EKEY_BITS / 8;
41
static const long RC2_EKEY_WLEN = RC2_EKEY_SIZE / 2;
44
static t_byte RC2_PI[256]={
45
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed,
46
0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
47
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
48
0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
49
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13,
50
0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
51
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b,
52
0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
53
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
54
0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
55
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1,
56
0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
57
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57,
58
0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
59
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
60
0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
61
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7,
62
0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
63
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74,
64
0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
65
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
66
0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
67
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a,
68
0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
69
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae,
70
0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
71
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
72
0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
73
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0,
74
0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
75
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77,
76
0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad
79
// this procedure expand the key into an effective key
80
static void rc2_key_expand (t_word* rkey, const Key& key, const long klen) {
81
// basic check as usual
82
if (rkey == nilp) return;
83
// check the supplied key size
84
long blen = key.getsize ();
85
if (blen >= RC2_EKEY_SIZE) {
86
throw Exception ("key-error", "invalid key size");
89
t_byte bkey[RC2_EKEY_SIZE];
90
for (long i = 0; i < blen; i++) bkey[i] = key.getbyte (i);
91
// compute effective key length
92
long t8 = (klen + 7) / 8;
93
long te = 1 << (8 + klen - 8 * t8);
94
t_byte tm = 0xFF % te;
95
// key expansion first loop
96
for (long i = blen; i < RC2_EKEY_SIZE; i++) {
97
t_byte k = bkey[i-1] + bkey[i-blen];
100
bkey[RC2_EKEY_SIZE - t8] = RC2_PI[bkey[RC2_EKEY_SIZE - t8] & tm];
101
// key expansion second loop
102
for (long i = RC2_EKEY_SIZE - t8 - 1; i >= 0; i--) {
103
bkey[i] = RC2_PI[bkey[i+1] ^ bkey[i+t8]];
106
for (long i = 0, j = 0; i < RC2_EKEY_SIZE-1; i += 2, j++) {
113
// this procedure bind an input buffer to the state word
114
static inline void rc2_bi_to_r (t_word* r, const t_byte* bi) {
115
// check result and input buffer
116
if ((r == nilp) || (bi == nilp)) return;
117
// bind the word from the input bytes
118
for (long i = 0, j = 0; i < RC2_BLOK_SIZE; i += 2, j++) {
125
// this procedure bind a state word to an output buffer
126
static inline void rc2_r_to_bo (t_byte* bo, const t_word* r) {
127
// check result and buffer
128
if ((bo == nilp) || (r == nilp)) return;
129
// bind the byte from the words
130
for (long i = 0, j = 0; i < RC2_BLOK_SIZE; i += 2, j++) {
131
bo[i] = (t_byte) r[j];
132
bo[i+1] = (t_byte) (r[j] >> 8);
136
// this procedure do an encryption mix up
137
static long rc2_enc_mix_up (t_word* r, const t_word* ekey,
138
const long j, const long i) {
140
long i1 = i - 1; long i2 = i - 2; long i3 = i - 3;
144
r[i] = r[i] + ekey[j] + (r[i1] & r[i2]) + ((~r[i1]) & r[i3]);
145
// compute rotation index
146
long k = (i == 0) ? 1 : (i == 1) ? 2 : (i == 2) ? 3 : 5;
147
r[i] = wrotl (r[i], k);
148
// update index result
152
// this procedure performs an encryption mixing round
153
static long rc2_enc_mix (t_word* r, const t_word* ekey, const long j) {
155
long result = rc2_enc_mix_up (r, ekey, j, 0);
157
result = rc2_enc_mix_up (r, ekey, result, 1);
159
result = rc2_enc_mix_up (r, ekey, result, 2);
161
result = rc2_enc_mix_up (r, ekey, result, 3);
166
// this procedure do an encryption mash up
167
static void rc2_enc_mash_up (t_word* r, const t_word* ekey, const long i) {
172
r[i] = r[i] + ekey[r[i1] & 63];
175
// this procedure performs an encryption mash round
176
static void rc2_enc_mash (t_word* r, const t_word* ekey) {
177
rc2_enc_mash_up (r, ekey, 0);
178
rc2_enc_mash_up (r, ekey, 1);
179
rc2_enc_mash_up (r, ekey, 2);
180
rc2_enc_mash_up (r, ekey, 3);
183
// this procedure performs an encryption round
184
static void rc2_enc (t_word* r, const t_word* ekey) {
185
// 0: initialize index
187
// 1: five mixing round
188
j = rc2_enc_mix (r, ekey, j);
189
j = rc2_enc_mix (r, ekey, j);
190
j = rc2_enc_mix (r, ekey, j);
191
j = rc2_enc_mix (r, ekey, j);
192
j = rc2_enc_mix (r, ekey, j);
193
// 2: one mashing round
194
rc2_enc_mash (r, ekey);
195
// 3: six mixing round
196
j = rc2_enc_mix (r, ekey, j);
197
j = rc2_enc_mix (r, ekey, j);
198
j = rc2_enc_mix (r, ekey, j);
199
j = rc2_enc_mix (r, ekey, j);
200
j = rc2_enc_mix (r, ekey, j);
201
j = rc2_enc_mix (r, ekey, j);
202
// 4: one mashing round
203
rc2_enc_mash (r, ekey);
204
// 5: five mixing rounds
205
j = rc2_enc_mix (r, ekey, j);
206
j = rc2_enc_mix (r, ekey, j);
207
j = rc2_enc_mix (r, ekey, j);
208
j = rc2_enc_mix (r, ekey, j);
209
j = rc2_enc_mix (r, ekey, j);
210
// basic verififcation
212
throw Exception ("internal-error", "invalid rc2 round index");
216
// this procedure do a decryption mix up
217
static long rc2_dec_mix_up (t_word* r, const t_word* ekey,
218
const long j, const long i) {
219
// compute rotation index
220
long k = (i == 0) ? 1 : (i == 1) ? 2 : (i == 2) ? 3 : 5;
221
r[i] = wrotr (r[i], k);
223
long i1 = i - 1; long i2 = i - 2; long i3 = i - 3;
227
r[i] = r[i] - ekey[j] - (r[i1] & r[i2]) - ((~r[i1]) & r[i3]);
228
// update index result
232
// this procedure performs a decryption mixing round
233
static long rc2_dec_mix (t_word* r, const t_word* ekey, const long j) {
235
long result = rc2_dec_mix_up (r, ekey, j, 3);
237
result = rc2_dec_mix_up (r, ekey, result, 2);
239
result = rc2_dec_mix_up (r, ekey, result, 1);
241
result = rc2_dec_mix_up (r, ekey, result, 0);
246
// this procedure do a decryption mash up
247
static void rc2_dec_mash_up (t_word* r, const t_word* ekey, const long i) {
252
r[i] = r[i] - ekey[r[i1] & 63];
255
// this procedure performs a decryption mash round
256
static void rc2_dec_mash (t_word* r, const t_word* ekey) {
257
rc2_dec_mash_up (r, ekey, 3);
258
rc2_dec_mash_up (r, ekey, 2);
259
rc2_dec_mash_up (r, ekey, 1);
260
rc2_dec_mash_up (r, ekey, 0);
263
// this procedure perform an decryption round
264
static void rc2_dec (t_word* r, const t_word* ekey) {
265
// 0: initialize index
267
// 1: five mixing round
268
j = rc2_dec_mix (r, ekey, j);
269
j = rc2_dec_mix (r, ekey, j);
270
j = rc2_dec_mix (r, ekey, j);
271
j = rc2_dec_mix (r, ekey, j);
272
j = rc2_dec_mix (r, ekey, j);
273
// 2: one mashing round
274
rc2_dec_mash (r, ekey);
275
// 3: six mixing round
276
j = rc2_dec_mix (r, ekey, j);
277
j = rc2_dec_mix (r, ekey, j);
278
j = rc2_dec_mix (r, ekey, j);
279
j = rc2_dec_mix (r, ekey, j);
280
j = rc2_dec_mix (r, ekey, j);
281
j = rc2_dec_mix (r, ekey, j);
282
// 4: one mashing round
283
rc2_dec_mash (r, ekey);
284
// 5: five mixing rounds
285
j = rc2_dec_mix (r, ekey, j);
286
j = rc2_dec_mix (r, ekey, j);
287
j = rc2_dec_mix (r, ekey, j);
288
j = rc2_dec_mix (r, ekey, j);
289
j = rc2_dec_mix (r, ekey, j);
290
// basic verififcation
292
throw Exception ("internal-error", "invalid rc2 round index");
296
// -------------------------------------------------------------------------
298
// -------------------------------------------------------------------------
300
// create a cipher by key
302
Rc2::Rc2 (const Key& key) : BlockCipher (RC2_ALGO_NAME, RC2_BLOK_SIZE) {
303
// initialize the effective key length
304
d_klen = RC2_EKEY_BITS;
305
// initialize the cipher
306
p_rkey = new t_word[RC2_EKEY_WLEN];
311
// create a cipher by key and flag
313
Rc2::Rc2 (const Key& key,
314
const bool rflg) : BlockCipher (RC2_ALGO_NAME, RC2_BLOK_SIZE) {
315
// initialize the effective key length
316
d_klen = RC2_EKEY_BITS;
317
// initialize the cipher
318
p_rkey = new t_word[RC2_EKEY_WLEN];
321
// set the reverse flag
325
// destroy this cipher
331
// return the class name
333
String Rc2::repr (void) const {
339
void Rc2::reset (void) {
342
// reset the block cipher
343
BlockCipher::reset ();
345
for (long i = 0; i < RC2_EKEY_WLEN; i++) {
349
rc2_key_expand (p_rkey, d_ckey, d_klen);
357
// set the effective key length
359
void Rc2::setklen (const long klen) {
362
if ((klen <= 0) || (klen > RC2_EKEY_BITS)) {
364
throw Exception ("key-error", "invalid effective key size");
366
// set the key and reset
377
// get the effective key length
379
long Rc2::getklen (void) const {
382
long result = d_klen;
391
// encode a block buffer into another one
393
void Rc2::encode (t_byte* bo, const t_byte* bi) {
396
// bind the round state
397
t_word r[RC2_WORD_SIZE] = {0x0000, 0x0000, 0x0000, 0x0000};
399
// encode the state round
401
// bind the output buffer
410
// decode a block buffer into another one
412
void Rc2::decode (t_byte* bo, const t_byte* bi) {
415
// bind the round state
416
t_word r[RC2_WORD_SIZE] = {0x0000, 0x0000, 0x0000, 0x0000};
418
// decode the state round
420
// bind the output buffer
429
// -------------------------------------------------------------------------
431
// -------------------------------------------------------------------------
434
static const long QUARK_ZONE_LENGTH = 2;
435
static QuarkZone zone (QUARK_ZONE_LENGTH);
437
// the object supported quarks
438
static const long QUARK_SETKLEN = zone.intern ("set-effective-key");
439
static const long QUARK_GETKLEN = zone.intern ("get-effective-key");
441
// create a new object in a generic way
443
Object* Rc2::mknew (Vector* argv) {
444
long argc = (argv == nilp) ? 0 : argv->length ();
445
// check for 1 argument
448
Object* obj = argv->get (0);
449
Key* key = dynamic_cast <Key*> (obj);
450
if (key != nilp) return new Rc2 (*key);
451
throw Exception ("argument-error", "invalid arguments with RC2");
453
// check for 2 arguments
456
Object* obj = argv->get (0);
457
Key* key = dynamic_cast <Key*> (obj);
459
throw Exception ("argument-error", "invalid arguments with RC2");
461
// get the reverse flag and object
462
bool rflg = argv->getbool (1);
463
return new Rc2 (*key, rflg);
465
throw Exception ("argument-error", "too many arguments with RC2");
468
// return true if the given quark is defined
470
bool Rc2::isquark (const long quark, const bool hflg) const {
472
if (zone.exists (quark) == true) {
476
bool result = hflg ? BlockCipher::isquark (quark, hflg) : false;
481
// apply this object with a set of arguments and a quark
483
Object* Rc2::apply (Runnable* robj, Nameset* nset, const long quark,
485
// get the number of arguments
486
long argc = (argv == nilp) ? 0 : argv->length ();
488
// check for 0 argument
490
if (quark == QUARK_GETKLEN) return new Integer (getklen ());
492
// check for 1 argument
494
if (quark == QUARK_SETKLEN) {
495
long klen = argv->getlong (0);
500
// call the block cipher method
501
return BlockCipher::apply (robj, nset, quark, argv);