Skip to content

Commit 64754bc

Browse files
committed
Added CSHAKEDigest, KMac, removed unused import from NewTspTest
1 parent a3e8674 commit 64754bc

File tree

6 files changed

+803
-1
lines changed

6 files changed

+803
-1
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using Org.BouncyCastle.Utilities;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Org.BouncyCastle.Crypto.Digests
8+
{
9+
/// <summary>
10+
/// Customizable SHAKE function.
11+
/// </summary>
12+
public class CSHAKEDigest : ShakeDigest
13+
{
14+
private static readonly byte[] padding = new byte[100];
15+
private readonly byte[] diff;
16+
17+
/// <summary>
18+
/// Base constructor
19+
/// </summary>
20+
/// <param name="bitLength">bit length of the underlying SHAKE function, 128 or 256.</param>
21+
/// <param name="N">the function name string, note this is reserved for use by NIST. Avoid using it if not required.</param>
22+
/// <param name="S">the customization string - available for local use.</param>
23+
public CSHAKEDigest(int bitLength, byte[] N, byte[] S) : base(bitLength)
24+
{
25+
if ((N == null || N.Length == 0) && (S == null || S.Length == 0))
26+
{
27+
diff = null;
28+
}
29+
else
30+
{
31+
diff = Arrays.ConcatenateAll(XofUtils.leftEncode(rate / 8), encodeString(N), encodeString(S));
32+
DiffPadAndAbsorb();
33+
}
34+
}
35+
36+
37+
// bytepad in SP 800-185
38+
private void DiffPadAndAbsorb()
39+
{
40+
int blockSize = rate / 8;
41+
Absorb(diff, 0, diff.Length);
42+
43+
int delta = diff.Length % blockSize;
44+
45+
// only add padding if needed
46+
if (delta != 0)
47+
{
48+
int required = blockSize - delta;
49+
50+
while (required > padding.Length)
51+
{
52+
Absorb(padding, 0, padding.Length);
53+
required -= padding.Length;
54+
}
55+
56+
Absorb(padding, 0, required);
57+
}
58+
}
59+
60+
private byte[] encodeString(byte[] str)
61+
{
62+
if (str == null || str.Length == 0)
63+
{
64+
return XofUtils.leftEncode(0);
65+
}
66+
67+
return Arrays.Concatenate(XofUtils.leftEncode(str.Length * 8L), str);
68+
}
69+
70+
public override string AlgorithmName => "CSHAKE" + fixedOutputLength;
71+
72+
public override int DoFinal(byte[] output, int outOff)
73+
{
74+
return DoFinal(output, outOff,GetDigestSize());
75+
}
76+
77+
public override int DoFinal(byte[] output, int outOff, int outLen)
78+
{
79+
int length = DoOutput(output, outOff, outLen);
80+
81+
Reset();
82+
83+
return length;
84+
}
85+
86+
public override int DoOutput(byte[] output, int outOff, int outLen)
87+
{
88+
if (diff != null)
89+
{
90+
if (!squeezing)
91+
{
92+
AbsorbBits(0x00, 2);
93+
}
94+
95+
Squeeze(output, outOff, ((long)outLen) * 8);
96+
97+
return outLen;
98+
}
99+
else
100+
{
101+
return base.DoOutput(output, outOff, outLen);
102+
}
103+
}
104+
105+
public void Reset()
106+
{
107+
base.Reset();
108+
109+
if (diff != null)
110+
{
111+
DiffPadAndAbsorb();
112+
}
113+
}
114+
}
115+
}

crypto/src/crypto/digests/XofUtils.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Org.BouncyCastle.Crypto.Digests
7+
{
8+
public class XofUtils
9+
{
10+
public static byte[] leftEncode(long strLen)
11+
{
12+
byte n = 1;
13+
14+
long v = strLen;
15+
while ((v >>= 8) != 0)
16+
{
17+
n++;
18+
}
19+
20+
byte[] b = new byte[n + 1];
21+
22+
b[0] = n;
23+
24+
for (int i = 1; i <= n; i++)
25+
{
26+
b[i] = (byte)(strLen >> (8 * (n - i)));
27+
}
28+
29+
return b;
30+
}
31+
32+
public static byte[] rightEncode(long strLen)
33+
{
34+
byte n = 1;
35+
36+
long v = strLen;
37+
while ((v >>= 8) != 0)
38+
{
39+
n++;
40+
}
41+
42+
byte[] b = new byte[n + 1];
43+
44+
b[n] = n;
45+
46+
for (int i = 0; i < n; i++)
47+
{
48+
b[i] = (byte)(strLen >> (8 * (n - i - 1)));
49+
}
50+
51+
return b;
52+
}
53+
}
54+
}

crypto/src/crypto/macs/KMac.cs

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
using Org.BouncyCastle.Crypto.Digests;
2+
using Org.BouncyCastle.Crypto.Parameters;
3+
using Org.BouncyCastle.Utilities;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
9+
namespace Org.BouncyCastle.Crypto.Macs
10+
{
11+
public class KMac : IMac, IXof
12+
{
13+
14+
private static readonly byte[] padding = new byte[100];
15+
16+
private readonly CSHAKEDigest cshake;
17+
private readonly int bitLength;
18+
private readonly int outputLength;
19+
20+
private byte[] key;
21+
private bool initialised;
22+
private bool firstOutput;
23+
24+
25+
public KMac(int bitLength, byte[] S)
26+
{
27+
this.cshake = new CSHAKEDigest(bitLength, Encoding.ASCII.GetBytes("KMAC"),S);
28+
this.bitLength = bitLength;
29+
this.outputLength = bitLength * 2 / 8;
30+
}
31+
32+
33+
public string AlgorithmName => "KMAC" + cshake.AlgorithmName.Substring(6);
34+
35+
public void BlockUpdate(byte[] input, int inOff, int len)
36+
{
37+
if (!initialised)
38+
{
39+
throw new InvalidOperationException("KMAC not initialized");
40+
}
41+
42+
cshake.BlockUpdate(input, inOff, len);
43+
}
44+
45+
public int DoFinal(byte[] output, int outOff)
46+
{
47+
if (firstOutput)
48+
{
49+
if (!initialised)
50+
{
51+
throw new InvalidOperationException("KMAC not initialized");
52+
}
53+
54+
byte[] encOut = XofUtils.rightEncode(GetMacSize() * 8);
55+
56+
cshake.BlockUpdate(encOut, 0, encOut.Length);
57+
}
58+
59+
int rv = cshake.DoFinal(output, outOff, GetMacSize());
60+
61+
Reset();
62+
63+
return rv;
64+
}
65+
66+
public int DoFinal(byte[] output, int outOff, int outLen)
67+
{
68+
if (firstOutput)
69+
{
70+
if (!initialised)
71+
{
72+
throw new InvalidOperationException("KMAC not initialized");
73+
}
74+
75+
byte[] encOut = XofUtils.rightEncode(outLen * 8);
76+
77+
cshake.BlockUpdate(encOut, 0, encOut.Length);
78+
}
79+
80+
int rv = cshake.DoFinal(output, outOff, outLen);
81+
82+
Reset();
83+
84+
return rv;
85+
}
86+
87+
public int DoOutput(byte[] output, int outOff, int outLen)
88+
{
89+
if (firstOutput)
90+
{
91+
if (!initialised)
92+
{
93+
throw new InvalidOperationException("KMAC not initialized");
94+
}
95+
96+
byte[] encOut = XofUtils.rightEncode(0);
97+
98+
cshake.BlockUpdate(encOut, 0, encOut.Length);
99+
100+
firstOutput = false;
101+
}
102+
103+
return cshake.DoOutput(output, outOff, outLen);
104+
}
105+
106+
public int GetByteLength()
107+
{
108+
return cshake.GetByteLength();
109+
}
110+
111+
public int GetDigestSize()
112+
{
113+
return outputLength;
114+
}
115+
116+
public int GetMacSize()
117+
{
118+
return outputLength;
119+
}
120+
121+
public void Init(ICipherParameters parameters)
122+
{
123+
KeyParameter kParam = (KeyParameter)parameters;
124+
this.key = Arrays.Clone(kParam.GetKey());
125+
this.initialised = true;
126+
Reset();
127+
}
128+
129+
public void Reset()
130+
{
131+
cshake.Reset();
132+
133+
if (key != null)
134+
{
135+
if (bitLength == 128)
136+
{
137+
bytePad(key, 168);
138+
}
139+
else
140+
{
141+
bytePad(key, 136);
142+
}
143+
}
144+
145+
firstOutput = true;
146+
}
147+
148+
private void bytePad(byte[] X, int w)
149+
{
150+
byte[] bytes = XofUtils.leftEncode(w);
151+
BlockUpdate(bytes, 0, bytes.Length);
152+
byte[] encX = encode(X);
153+
BlockUpdate(encX, 0, encX.Length);
154+
155+
int required = w - ((bytes.Length + encX.Length) % w);
156+
157+
if (required > 0 && required != w)
158+
{
159+
while (required > padding.Length)
160+
{
161+
BlockUpdate(padding, 0, padding.Length);
162+
required -= padding.Length;
163+
}
164+
165+
BlockUpdate(padding, 0, required);
166+
}
167+
}
168+
169+
private static byte[] encode(byte[] X)
170+
{
171+
return Arrays.Concatenate(XofUtils.leftEncode(X.Length * 8), X);
172+
}
173+
174+
public void Update(byte input)
175+
{
176+
if (!initialised)
177+
{
178+
throw new InvalidOperationException("KMAC not initialized");
179+
}
180+
181+
cshake.Update(input);
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)