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
  
 
#pike __REAL_VERSION__ 
#pragma strict_types 
#require constant(Crypto.CipherState) 
 
//! A wrapper class that connects several cipher algorithms into one 
//! algorithm. E.g. triple DES can be emulated with 
//! @expr{Crypto.Pipe(Crypto.DES, Crypto.DES, Crypto.DES)@}. 
 
protected array(.CipherState) ciphers = ({}); 
protected int _block_size = 1; 
protected int(0..1) reversed; 
 
protected int(0..1) is_crypto(object c) { 
  return c->block_size && c->key_size && c->set_encrypt_key && 
    c->set_decrypt_key && c->crypt && 1; 
} 
 
protected void create(program|object|array(program|mixed) ... c) { 
  if(!sizeof(c)) error("Too few arguments.\n"); 
  foreach(c, program|object|array cc) { 
    if(objectp(cc)) { 
      mixed mcc; 
      if(!is_crypto([object]cc) && callablep(cc)) { 
        mcc = cc(); 
        if(!objectp(mcc) && !is_crypto([object]mcc)) 
          error("Not a crypto object.\n"); 
        cc = [object]mcc; 
      } 
      ciphers += ({ [object(.CipherState)]cc }); 
    } 
    else if(programp(cc)) 
      ciphers += ({ cc() }); 
    else if(arrayp(cc)) { 
      array acc = [array]cc; 
      if(!sizeof(acc)) error("Empty array as argument.\n"); 
      if(!programp(acc[0])) error("First array element not program.\n"); 
      ciphers += ({ ([program]acc[0])(@acc[1..]) }); 
    } 
    else 
      error("Wrong type in argument.\n"); 
  } 
 
  foreach(ciphers, .CipherState c) { 
    array(int) a = Math.factor(_block_size); 
    array(int) b = Math.factor(c->block_size()); 
    array(int) common = a&b; 
 
    foreach(common, int x) { 
      int pos = search(a,x); 
      if(pos!=-1) 
        a[pos]=1; 
      pos = search(b,x); 
      if(pos!=-1) 
        b[pos]=1; 
    } 
 
    _block_size = `*( @(common+a+b) ); 
  } 
 
} 
 
string name() { 
  return "Pipe(" + ciphers->name()*", "+ ")"; 
} 
 
int block_size() { 
  return _block_size; 
} 
 
array(int) key_size() { 
  return ciphers->key_size(); 
} 
 
this_program set_encrypt_key(array(string(8bit))|string(8bit) ... keys) { 
  if(arrayp(keys[0])) 
    keys = [array(string(8bit))]keys[0]; 
  if(sizeof(keys)!=sizeof(ciphers)) 
    error("Wrong number of keys.\n"); 
  if(reversed) { 
    ciphers = reverse(ciphers); 
    reversed = 0; 
  } 
  foreach(ciphers; int num; .CipherState c) 
    c->set_encrypt_key( [string(8bit)]keys[num] ); 
  return this; 
} 
 
this_program set_decrypt_key(array(string(8bit))|string(8bit) ... keys) { 
  if(arrayp(keys[0])) 
    keys = [array(string(8bit))]keys[0]; 
  if(sizeof(keys)!=sizeof(ciphers)) 
    error("Wrong number of keys.\n"); 
  if(!reversed) { 
    ciphers = reverse(ciphers); 
    reversed = 1; 
  } 
  keys = reverse(keys); 
  foreach(ciphers; int num; .CipherState c) 
    c->set_decrypt_key( [string(8bit)]keys[num] ); 
  return this; 
} 
 
string(8bit) crypt(string(8bit) data) { 
  if(sizeof(data)%_block_size) 
    error("Data size not integral number of blocks.\n"); 
  foreach(ciphers, .CipherState c) 
    data = c->crypt(data); 
  return data; 
}