1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.impl.ext.engines;
18
19 import io.github.tonywasher.joceanus.gordianknot.impl.ext.digests.GordianSkeinBase;
20 import io.github.tonywasher.joceanus.gordianknot.impl.ext.digests.GordianSkeinXof;
21 import io.github.tonywasher.joceanus.gordianknot.impl.ext.params.GordianSkeinParameters.GordianSkeinParametersBuilder;
22 import org.bouncycastle.crypto.CipherParameters;
23 import org.bouncycastle.crypto.DataLengthException;
24 import org.bouncycastle.crypto.OutputLengthException;
25 import org.bouncycastle.crypto.StreamCipher;
26 import org.bouncycastle.crypto.params.KeyParameter;
27 import org.bouncycastle.crypto.params.ParametersWithIV;
28 import org.bouncycastle.util.Memoable;
29
30
31
32
33 public class GordianSkeinXofEngine
34 implements StreamCipher, Memoable {
35
36
37
38 private int theIndex;
39
40
41
42
43 private final byte[] theKeyStream;
44
45
46
47
48 private final GordianSkeinXof theSkeinXof;
49
50
51
52
53 private GordianSkeinXof theResetState;
54
55
56
57
58
59
60 public GordianSkeinXofEngine(final int pLength) {
61 final GordianSkeinBase myBase = new GordianSkeinBase(pLength, pLength);
62 theSkeinXof = new GordianSkeinXof(myBase);
63 theKeyStream = new byte[myBase.getBlockSize()];
64 }
65
66
67
68
69
70
71 private GordianSkeinXofEngine(final GordianSkeinXofEngine pSource) {
72 theSkeinXof = new GordianSkeinXof(pSource.theSkeinXof);
73 theKeyStream = new byte[theSkeinXof.getByteLength()];
74 reset(pSource);
75 }
76
77
78
79
80
81
82
83
84 public void init(final boolean forEncryption,
85 final CipherParameters params) {
86
87
88
89
90
91
92 CipherParameters myParams = params;
93 byte[] newKey = null;
94 byte[] newIV = null;
95 if ((myParams instanceof ParametersWithIV)) {
96 final ParametersWithIV ivParams = (ParametersWithIV) myParams;
97 newIV = ivParams.getIV();
98 myParams = ivParams.getParameters();
99 }
100 if (myParams instanceof KeyParameter) {
101 final KeyParameter keyParam = (KeyParameter) myParams;
102 newKey = keyParam.getKey();
103 }
104 if (newKey == null || newIV == null) {
105 throw new IllegalArgumentException("A key and IV must be provided");
106 }
107
108
109 final GordianSkeinParametersBuilder myBuilder = new GordianSkeinParametersBuilder()
110 .setKey(newKey)
111 .setNonce(newIV)
112 .setMaxOutputLen(-1);
113 theSkeinXof.init(myBuilder.build());
114
115
116 theResetState = theSkeinXof.copy();
117
118
119 theIndex = 0;
120 makeStreamBlock();
121 }
122
123 @Override
124 public String getAlgorithmName() {
125 return theSkeinXof.getAlgorithmName();
126 }
127
128 @Override
129 public int processBytes(final byte[] in,
130 final int inOff,
131 final int len,
132 final byte[] out,
133 final int outOff) {
134
135 if (theResetState == null) {
136 throw new IllegalStateException(getAlgorithmName() + " not initialised");
137 }
138 if ((inOff + len) > in.length) {
139 throw new DataLengthException("input buffer too short");
140 }
141 if ((outOff + len) > out.length) {
142 throw new OutputLengthException("output buffer too short");
143 }
144
145
146 for (int i = 0; i < len; i++) {
147 out[i + outOff] = returnByte(in[i + inOff]);
148 }
149 return len;
150 }
151
152 @Override
153 public void reset() {
154 if (theResetState != null) {
155 theSkeinXof.reset(theResetState);
156 theIndex = 0;
157 makeStreamBlock();
158 }
159 }
160
161 @Override
162 public byte returnByte(final byte in) {
163 final byte out = (byte) (theKeyStream[theIndex] ^ in);
164 theIndex = (theIndex + 1) % theKeyStream.length;
165
166 if (theIndex == 0) {
167 makeStreamBlock();
168 }
169 return out;
170 }
171
172
173
174
175 private void makeStreamBlock() {
176
177 theSkeinXof.doOutput(theKeyStream, 0, theKeyStream.length);
178 }
179
180 @Override
181 public GordianSkeinXofEngine copy() {
182 return new GordianSkeinXofEngine(this);
183 }
184
185 @Override
186 public void reset(final Memoable pState) {
187 final GordianSkeinXofEngine e = (GordianSkeinXofEngine) pState;
188 if (theKeyStream.length != e.theKeyStream.length) {
189 throw new IllegalArgumentException();
190 }
191 theSkeinXof.reset(e.theSkeinXof);
192 System.arraycopy(e.theKeyStream, 0, theKeyStream, 0, theKeyStream.length);
193 theIndex = e.theIndex;
194 theResetState = e.theResetState;
195 }
196 }
197