From 5ad15eeceb4678bce4fccc158312e89076ad2952 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 29 Jan 2024 17:32:32 +0700 Subject: Add Prehash digest for safer raw signers --- crypto/src/crypto/digests/Prehash.cs | 69 ++++++++++++++++++++++ crypto/src/crypto/signers/PssSigner.cs | 9 ++- crypto/src/tls/crypto/impl/bc/BcTlsRsaPssSigner.cs | 3 +- .../src/tls/crypto/impl/bc/BcTlsRsaPssVerifier.cs | 3 +- crypto/src/util/io/LimitedBuffer.cs | 58 ++++++++++++++++++ 5 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 crypto/src/crypto/digests/Prehash.cs create mode 100644 crypto/src/util/io/LimitedBuffer.cs 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 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 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 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 buffer) + { + buffer.CopyTo(m_buf.AsSpan(m_count)); + } +#endif + + public override void WriteByte(byte value) + { + m_buf[m_count++] = value; + } + } +} -- cgit 1.4.1