-
Notifications
You must be signed in to change notification settings - Fork 1
/
TribbleCypher.cs
156 lines (132 loc) · 5.43 KB
/
TribbleCypher.cs
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
#region Licence
/*
Babbacombe SockLib
https://github.com/trevorprinn/SockLib
Copyright © 2017 Babbacombe Computers Ltd.
This class was provided under LGPL by Green Box Intelligence Ltd
https://github.com/Rushyo
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/
#endregion
using System;
using System.Linq;
using System.Security.Cryptography;
using Babbacombe.SockLib;
using System.Threading;
namespace TribbleCipher {
public class Tribble<T> : SymmetricAlgorithm, ICryptoTransform where T : HashAlgorithm {
private Int64 _counter;
private Byte _position;
private readonly HashAlgorithm _hash;
private Byte[] _state;
private Byte[] _key;
protected Tribble(Byte[] key, T hash, Int64 counter, Byte position, Byte[] state) {
_position = position;
_counter = counter;
_hash = hash;
_state = state.ToArray();
_key = key.ToArray();
}
public Tribble(Byte[] key, T hash) {
if (typeof(T).IsSubclassOf(typeof(MD5)))
throw new NotSupportedException(@"Really? MD5?!? NO.");
if (hash == null)
throw new ArgumentNullException(@"hash");
if (key == null || key.Length != (hash.HashSize / 8))
throw new ArgumentException(@"Invalid key", @"key");
_hash = hash;
_state = key.ToArray();
_key = key.ToArray();
Next();
}
internal void Next() {
Byte[] counterBytes = BitConverter.GetBytes(_counter);
for (var i = 0; i < counterBytes.Length; i++)
_state[i] ^= counterBytes[i];
_state = _hash.ComputeHash(_state);
_counter++;
_position = 0;
}
public Byte[] XOR(Byte[] input) {
var output = new Byte[input.Length];
for (var i = 0; i < input.Length; i++) {
output[i] = (Byte)(input[i] ^ _state[_position]);
_position++;
if (_position % (_hash.HashSize / 8) == 0)
Next();
}
return output;
}
internal void Reset() {
_counter = 0;
_position = 0;
_state = _key.ToArray();
Next();
}
public new void Dispose() {
_hash.Dispose();
}
public Boolean CanReuseTransform {
get { return true; }
}
public Boolean CanTransformMultipleBlocks {
get { return true; }
}
public Int32 InputBlockSize {
get { return 1; }
}
public Int32 OutputBlockSize {
get { return 1; }
}
public Int32 TransformBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[] outputBuffer, Int32 outputOffset) {
Byte[] transformed = XOR(inputBuffer.Skip(inputOffset).Take(inputCount).ToArray());
Array.Copy(transformed, 0, outputBuffer, outputOffset, inputCount);
return inputCount;
}
public Byte[] TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) {
return XOR(inputBuffer.Skip(inputOffset).Take(inputCount).ToArray());
}
public override ICryptoTransform CreateDecryptor() {
return CreateDecryptor(_key, null);
}
public override ICryptoTransform CreateDecryptor(Byte[] rgbKey, Byte[] rgbIV) {
HashAlgorithm hashAlgorithm = HashAlgorithm.Create(typeof(T).Name);
if (hashAlgorithm == null)
throw new InvalidOperationException(@"Unknown hash algorithm");
if (rgbKey.Length != hashAlgorithm.HashSize / 8)
throw new ArgumentException("Invalid key", @"rgbKey");
return new Tribble<T>(rgbKey, (T)hashAlgorithm, _counter, _position, _state);
}
public override ICryptoTransform CreateEncryptor() {
return CreateDecryptor();
}
public override ICryptoTransform CreateEncryptor(Byte[] rgbKey, Byte[] rgbIV) {
return CreateDecryptor(rgbKey, rgbIV);
}
public override void GenerateIV() {
throw new NotImplementedException("IV is not used by this cipher");
}
public override void GenerateKey() {
HashAlgorithm hashAlgorithm = HashAlgorithm.Create(typeof(T).Name);
if (hashAlgorithm == null)
throw new InvalidOperationException(@"Unknown hash algorithm");
Int32 bytes = hashAlgorithm.HashSize / 8;
var key = new Byte[bytes];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
rng.GetBytes(key);
_key = key;
Reset();
}
}
}