* FileSystemInfo.cs: corrected COM visibility of UTC properties
[mono.git] / mcs / class / Mono.Security / Mono.Security.Cryptography / ARC4Managed.cs
1 //
2 // ARC4Managed.cs: Alleged RC4(tm) compatible symmetric stream cipher
3 //      RC4 is a trademark of RSA Security
4 //
5
6 using System;
7 using System.Security.Cryptography;
8
9 namespace Mono.Security.Cryptography {
10
11         // References:
12         // a.   Usenet 1994 - RC4 Algorithm revealed
13         //      http://www.qrst.de/html/dsds/rc4.htm
14
15         public class ARC4Managed : RC4, ICryptoTransform {
16
17                 private byte[] key;
18                 private byte[] state;
19                 private byte x;
20                 private byte y;
21                 private bool m_disposed;
22
23                 public ARC4Managed () : base () 
24                 {
25                         state = new byte [256];
26                         m_disposed = false;
27                 }
28
29                 ~ARC4Managed () 
30                 {
31                         Dispose (true);
32                 }
33                 
34                 protected override void Dispose (bool disposing) 
35                 {
36                         if (!m_disposed) {
37                                 x = 0;
38                                 y = 0;
39                                 if (key != null) {
40                                         Array.Clear (key, 0, key.Length);
41                                         key = null;
42                                 }
43                                 Array.Clear (state, 0, state.Length);
44                                 state = null;
45                                 GC.SuppressFinalize (this);
46                                 m_disposed = true;
47                         }
48                 }
49
50                 public override byte[] Key {
51                         get { return (byte[]) key.Clone (); }
52                         set { 
53                                 key = (byte[]) value.Clone ();
54                                 KeySetup (key);
55                         }
56                 }
57
58                 public bool CanReuseTransform {
59                         get { return false; }
60                 }
61
62                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgvIV)
63                 {
64                         Key = rgbKey;
65                         return (ICryptoTransform) this;
66                 }
67
68                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgvIV) 
69                 {
70                         Key = rgbKey;
71                         return CreateEncryptor ();
72                 }
73
74                 public override void GenerateIV () 
75                 {
76                         // not used for a stream cipher
77                         IV = new byte [0];
78                 }
79
80                 public override void GenerateKey () 
81                 {
82                         Key = KeyBuilder.Key (KeySizeValue >> 3);
83                 }
84
85                 public bool CanTransformMultipleBlocks {
86                         get { return true; }
87                 }
88
89                 public int InputBlockSize {
90                         get { return 1; }
91                 }
92
93                 public int OutputBlockSize {
94                         get { return 1; }
95                 }
96
97                 private void KeySetup (byte[] key) 
98                 {
99                         byte index1 = 0;
100                         byte index2 = 0;
101
102                         for (int counter = 0; counter < 256; counter++)
103                                 state [counter] = (byte) counter;    
104                         x = 0;
105                         y = 0;
106                         for (int counter = 0; counter < 256; counter++) {
107                                 index2 = (byte) (key [index1] + state [counter] + index2);
108                                 // swap byte
109                                 byte tmp = state [counter];
110                                 state [counter] = state [index2];
111                                 state [index2] = tmp;
112                                 index1 = (byte) ((index1 + 1) % key.Length);
113                         }
114                 }
115
116                 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
117                 {
118                         byte xorIndex;
119                         for (int counter = 0; counter < inputCount; counter ++) {               
120                                 x = (byte) (x + 1);
121                                 y = (byte) (state [x] + y);
122                                 // swap byte
123                                 byte tmp = state [x];
124                                 state [x] = state [y];
125                                 state [y] = tmp;
126
127                                 xorIndex = (byte) (state [x] + state [y]);
128                                 outputBuffer [outputOffset + counter] = (byte) (inputBuffer [inputOffset + counter] ^ state [xorIndex]);
129                         }
130                         return inputCount;
131                 }
132
133                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) 
134                 {
135                         byte[] output = new byte [inputCount];
136                         TransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
137                         return output;
138                 }
139         }
140 }