summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-01-29 17:32:32 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-01-29 17:32:32 +0700
commit5ad15eeceb4678bce4fccc158312e89076ad2952 (patch)
treea235570743f236cc567502199f4a19a61ba32191
parentAdd contributor entry (diff)
downloadBouncyCastle.NET-ed25519-5ad15eeceb4678bce4fccc158312e89076ad2952.tar.xz
Add Prehash digest for safer raw signers
-rw-r--r--crypto/src/crypto/digests/Prehash.cs69
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs9
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs3
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs3
-rw-r--r--crypto/src/util/io/LimitedBuffer.cs58
5 files changed, 135 insertions, 7 deletions
diff --git a/crypto/src/crypto/digests/Prehash.cs b/crypto/src/crypto/digests/Prehash.cs
new file mode 100644
index 000000000..ae7b2ad89
--- /dev/null
+++ b/crypto/src/crypto/digests/Prehash.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    public sealed class Prehash
+        : IDigest
+    {
+        public static Prehash ForDigest(IDigest digest) => new Prehash(digest);
+
+        private readonly string m_algorithmName;
+        private readonly LimitedBuffer m_buf;
+
+        private Prehash(IDigest digest)
+        {
+            m_algorithmName = digest.AlgorithmName;
+            m_buf = new LimitedBuffer(digest.GetDigestSize());
+        }
+
+        public string AlgorithmName => m_algorithmName;
+
+        public int GetByteLength() => throw new NotSupportedException();
+
+        public int GetDigestSize() => m_buf.Limit;
+
+        public void Update(byte input) => m_buf.WriteByte(input);
+
+        public void BlockUpdate(byte[] input, int inOff, int inLen) => m_buf.Write(input, inOff, inLen);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public void BlockUpdate(ReadOnlySpan<byte> input) => m_buf.Write(input);
+#endif
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            try
+            {
+                if (GetDigestSize() != m_buf.Count)
+                    throw new InvalidOperationException("Incorrect prehash size");
+
+                return m_buf.CopyTo(output, outOff);
+            }
+            finally
+            {
+                Reset();
+            }
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            try
+            {
+                if (GetDigestSize() != m_buf.Count)
+                    throw new InvalidOperationException("Incorrect prehash size");
+
+                return m_buf.CopyTo(output);
+            }
+            finally
+            {
+                Reset();
+            }
+        }
+#endif
+
+        public void Reset() => m_buf.Reset();
+    }
+}
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 2e4c37772..7c2fcd071 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -35,19 +35,22 @@ namespace Org.BouncyCastle.Crypto.Signers
 
 		public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest digest)
 		{
-			return new PssSigner(cipher, new NullDigest(), digest, digest, digest.GetDigestSize(), null, TrailerImplicit);
+			return new PssSigner(cipher, Prehash.ForDigest(digest), digest, digest, digest.GetDigestSize(), null,
+				TrailerImplicit);
 		}
 
 		public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest contentDigest, IDigest mgfDigest,
 			int saltLen, byte trailer)
 		{
-			return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, saltLen, null, trailer);
+			return new PssSigner(cipher, Prehash.ForDigest(contentDigest), contentDigest, mgfDigest, saltLen, null,
+				trailer);
 		}
 
 		public static PssSigner CreateRawSigner(IAsymmetricBlockCipher cipher, IDigest contentDigest, IDigest mgfDigest,
 			byte[] salt, byte trailer)
 		{
-			return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, salt.Length, salt, trailer);
+			return new PssSigner(cipher, Prehash.ForDigest(contentDigest), contentDigest, mgfDigest, salt.Length, salt,
+				trailer);
 		}
 
 		public PssSigner(
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs
index 1b33573f6..5d8892f1f 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs
@@ -30,8 +30,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(m_signatureScheme);
             IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm);
 
-            PssSigner signer = PssSigner.CreateRawSigner(new RsaBlindedEngine(), digest, digest, digest.GetDigestSize(),
-                PssSigner.TrailerImplicit);
+            PssSigner signer = PssSigner.CreateRawSigner(new RsaBlindedEngine(), digest);
             signer.Init(true, new ParametersWithRandom(m_privateKey, m_crypto.SecureRandom));
             signer.BlockUpdate(hash, 0, hash.Length);
             try
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs
index 18c2082aa..da6c5b11e 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs
@@ -31,8 +31,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(m_signatureScheme);
             IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm);
 
-            PssSigner verifier = PssSigner.CreateRawSigner(new RsaEngine(), digest, digest, digest.GetDigestSize(),
-                PssSigner.TrailerImplicit);
+            PssSigner verifier = PssSigner.CreateRawSigner(new RsaEngine(), digest);
             verifier.Init(false, m_publicKey);
             verifier.BlockUpdate(hash, 0, hash.Length);
             return verifier.VerifySignature(digitallySigned.Signature);
diff --git a/crypto/src/util/io/LimitedBuffer.cs b/crypto/src/util/io/LimitedBuffer.cs
new file mode 100644
index 000000000..07c9969ad
--- /dev/null
+++ b/crypto/src/util/io/LimitedBuffer.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public sealed class LimitedBuffer
+        : BaseOutputStream
+    {
+        private readonly byte[] m_buf;
+        private int m_count;
+
+        public LimitedBuffer(int limit)
+        {
+            m_buf = new byte[limit];
+            m_count = 0;
+        }
+
+        public int CopyTo(byte[] buffer, int offset)
+        {
+            Array.Copy(m_buf, 0, buffer, offset, m_count);
+            return m_count;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int CopyTo(Span<byte> buffer)
+        {
+            m_buf.AsSpan(0, m_count).CopyTo(buffer);
+            return m_count;
+        }
+#endif
+
+        public int Count => m_count;
+
+        public int Limit => m_buf.Length;
+
+        public void Reset()
+        {
+            m_count = 0;
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            Array.Copy(buffer, offset, m_buf, m_count, count);
+            m_count += count;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override void Write(ReadOnlySpan<byte> buffer)
+        {
+            buffer.CopyTo(m_buf.AsSpan(m_count));
+        }
+#endif
+
+        public override void WriteByte(byte value)
+        {
+            m_buf[m_count++] = value;
+        }
+    }
+}