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 org.bouncycastle.crypto.engines.ChaChaEngine;
20 import org.bouncycastle.crypto.engines.Salsa20Engine;
21 import org.bouncycastle.util.Pack;
22
23
24
25
26 @SuppressWarnings("checkstyle:MagicNumber")
27 public class GordianXChaCha20Engine
28 extends ChaChaEngine {
29
30 @Override
31 public String getAlgorithmName() {
32 return "XChaCha20";
33 }
34
35 @Override
36 protected int getNonceSize() {
37 return 24;
38 }
39
40
41
42
43
44
45 @Override
46 protected void setKey(final byte[] keyBytes,
47 final byte[] ivBytes) {
48 if (keyBytes == null) {
49 throw new IllegalArgumentException(getAlgorithmName() + " doesn't support re-init with null key");
50 }
51
52 if (keyBytes.length != 32) {
53 throw new IllegalArgumentException(getAlgorithmName() + " requires a 256 bit key");
54 }
55
56
57 super.setKey(keyBytes, ivBytes);
58
59
60 Pack.littleEndianToInt(ivBytes, 0, engineState, 12, 4);
61
62
63 final int[] hChaCha20Out = new int[engineState.length];
64 chachaCore(Salsa20Engine.DEFAULT_ROUNDS, engineState, hChaCha20Out);
65
66
67 engineState[4] = hChaCha20Out[0] - engineState[0];
68 engineState[5] = hChaCha20Out[1] - engineState[1];
69 engineState[6] = hChaCha20Out[2] - engineState[2];
70 engineState[7] = hChaCha20Out[3] - engineState[3];
71
72 engineState[8] = hChaCha20Out[12] - engineState[12];
73 engineState[9] = hChaCha20Out[13] - engineState[13];
74 engineState[10] = hChaCha20Out[14] - engineState[14];
75 engineState[11] = hChaCha20Out[15] - engineState[15];
76
77
78 Pack.littleEndianToInt(ivBytes, 16, engineState, 14, 2);
79 }
80 }