diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs
index e9e2253a0..f76304d48 100644
--- a/crypto/src/crypto/IXof.cs
+++ b/crypto/src/crypto/IXof.cs
@@ -9,14 +9,23 @@ namespace Org.BouncyCastle.Crypto
public interface IXof
: IDigest
{
- /**
- * Output the results of the final calculation for this digest to outLen number of bytes.
- *
- * @param out output array to write the output bytes to.
- * @param outOff offset to start writing the bytes at.
- * @param outLen the number of output bytes requested.
- * @return the number of bytes written
- */
+ /// <summary>
+ /// Output the results of the final calculation for this digest to outLen number of bytes.
+ /// </summary>
+ /// <param name="output">output array to write the output bytes to.</param>
+ /// <param name="outOff">offset to start writing the bytes at.</param>
+ /// <param name="outLen">the number of output bytes requested.</param>
+ /// <returns>the number of bytes written</returns>
int DoFinal(byte[] output, int outOff, int outLen);
+
+ /// <summary>
+ /// Start outputting the results of the final calculation for this digest. Unlike DoFinal, this method
+ /// will continue producing output until the Xof is explicitly reset, or signals otherwise.
+ /// </summary>
+ /// <param name="output">output array to write the output bytes to.</param>
+ /// <param name="outOff">offset to start writing the bytes at.</param>
+ /// <param name="outLen">the number of output bytes requested.</param>
+ /// <returns>the number of bytes written</returns>
+ int DoOutput(byte[] output, int outOff, int outLen);
}
}
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
index 2d6cf393c..20aa225b8 100644
--- a/crypto/src/crypto/digests/KeccakDigest.cs
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -248,11 +248,11 @@ namespace Org.BouncyCastle.Crypto.Digests
if ((bitsInQueue % 8) != 0)
{
- throw new InvalidOperationException("attempt to absorb with odd length queue.");
+ throw new InvalidOperationException("attempt to absorb with odd length queue");
}
if (squeezing)
{
- throw new InvalidOperationException("attempt to absorb while squeezing.");
+ throw new InvalidOperationException("attempt to absorb while squeezing");
}
i = 0;
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
index fd7d85681..a7bddccba 100644
--- a/crypto/src/crypto/digests/ShakeDigest.cs
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -53,15 +53,25 @@ namespace Org.BouncyCastle.Crypto.Digests
public virtual int DoFinal(byte[] output, int outOff, int outLen)
{
- Absorb(new byte[]{ 0x0F }, 0, 4);
-
- Squeeze(output, outOff, ((long)outLen) * 8);
+ DoOutput(output, outOff, outLen);
Reset();
return outLen;
}
+ public virtual int DoOutput(byte[] output, int outOff, int outLen)
+ {
+ if (!squeezing)
+ {
+ Absorb(new byte[] { 0x0F }, 0, 4);
+ }
+
+ Squeeze(output, outOff, ((long)outLen) * 8);
+
+ return outLen;
+ }
+
/*
* TODO Possible API change to support partial-byte suffixes.
*/
diff --git a/crypto/test/src/crypto/test/ShakeDigestTest.cs b/crypto/test/src/crypto/test/ShakeDigestTest.cs
index ef4696739..d8b2d55d6 100644
--- a/crypto/test/src/crypto/test/ShakeDigestTest.cs
+++ b/crypto/test/src/crypto/test/ShakeDigestTest.cs
@@ -199,6 +199,50 @@ namespace Org.BouncyCastle.Crypto.Tests
//Console.Error.WriteLine(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
//Console.Error.WriteLine(Hex.ToHexString(output).ToUpper());
}
+
+ if (partialBits == 0)
+ {
+ d = CreateDigest(v.Algorithm);
+
+ m = v.Message;
+
+ d.BlockUpdate(m, 0, m.Length);
+ d.DoOutput(output, 0, outLen / 2);
+ d.DoOutput(output, outLen / 2, output.Length - outLen / 2);
+
+ if (!Arrays.AreEqual(expected, output))
+ {
+ Fail(v.Algorithm + " " + v.Bits + "-bit test vector extended hash mismatch");
+ }
+
+ try
+ {
+ d.Update((byte)0x01);
+ Fail("no exception");
+ }
+ catch (InvalidOperationException e)
+ {
+ if (!"attempt to absorb while squeezing".Equals(e.Message))
+ {
+ Fail("wrong exception");
+ }
+ }
+
+ d = CreateDigest(v.Algorithm);
+
+ m = v.Message;
+
+ d.BlockUpdate(m, 0, m.Length);
+ d.DoOutput(output, 0, outLen / 2);
+ d.DoFinal(output, outLen / 2, output.Length - outLen / 2);
+
+ if (!Arrays.AreEqual(expected, output))
+ {
+ Fail(v.Algorithm + " " + v.Bits + "-bit test vector extended doFinal hash mismatch");
+ }
+
+ d.Update((byte)0x01); // this should be okay as we've reset on DoFinal()
+ }
}
private void SkipUntil(StreamReader r, string header)
|