< Summary

Information
Class: Renci.SshNet.Security.Cryptography.DsaDigitalSignature
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\DsaDigitalSignature.cs
Line coverage
71%
Covered lines: 62
Uncovered lines: 25
Coverable lines: 87
Total lines: 205
Line coverage: 71.2%
Branch coverage
63%
Covered branches: 19
Total branches: 30
Branch coverage: 63.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)50%275%
Verify(...)58.33%1279.31%
Sign(...)90%1092.85%
Dispose()100%10%
Dispose(...)33.33%626.66%
Finalize()100%1100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\DsaDigitalSignature.cs

#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3
 4using Renci.SshNet.Abstractions;
 5using Renci.SshNet.Common;
 6
 7namespace Renci.SshNet.Security.Cryptography
 8{
 9    /// <summary>
 10    /// Implements DSA digital signature algorithm.
 11    /// </summary>
 12    public class DsaDigitalSignature : DigitalSignature, IDisposable
 13    {
 14        private readonly DsaKey _key;
 15        private HashAlgorithm _hash;
 16        private bool _isDisposed;
 17
 18        /// <summary>
 19        /// Initializes a new instance of the <see cref="DsaDigitalSignature" /> class.
 20        /// </summary>
 21        /// <param name="key">The DSA key.</param>
 22        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
 1623        public DsaDigitalSignature(DsaKey key)
 1624        {
 1625            if (key is null)
 026            {
 027                throw new ArgumentNullException(nameof(key));
 28            }
 29
 1630            _key = key;
 31
 1632            _hash = CryptoAbstraction.CreateSHA1();
 1633        }
 34
 35        /// <summary>
 36        /// Verifies the signature.
 37        /// </summary>
 38        /// <param name="input">The input.</param>
 39        /// <param name="signature">The signature.</param>
 40        /// <returns>
 41        /// <see langword="true"/> if signature was successfully verified; otherwise <see langword="false"/>.
 42        /// </returns>
 43        /// <exception cref="InvalidOperationException">Invalid signature.</exception>
 44        public override bool Verify(byte[] input, byte[] signature)
 345        {
 346            var hashInput = _hash.ComputeHash(input);
 47
 348            var hm = new BigInteger(hashInput.Reverse().Concat(new byte[] { 0 }));
 49
 350            if (signature.Length != 40)
 051            {
 052                throw new InvalidOperationException("Invalid signature.");
 53            }
 54
 55            // Extract r and s numbers from the signature
 356            var rBytes = new byte[21];
 357            var sBytes = new byte[21];
 58
 18959            for (int i = 0, j = 20; i < 20; i++, j--)
 6060            {
 6061                rBytes[i] = signature[j - 1];
 6062                sBytes[i] = signature[j + 20 - 1];
 6063            }
 64
 365            var r = new BigInteger(rBytes);
 366            var s = new BigInteger(sBytes);
 67
 68            // Reject the signature if 0 < r < q or 0 < s < q is not satisfied.
 369            if (r <= 0 || r >= _key.Q)
 070            {
 071                return false;
 72            }
 73
 374            if (s <= 0 || s >= _key.Q)
 075            {
 076                return false;
 77            }
 78
 79            // Calculate w = sāˆ’1 mod q
 380            var w = BigInteger.ModInverse(s, _key.Q);
 81
 82            // Calculate u1 = H(m)·w mod q
 383            var u1 = (hm * w) % _key.Q;
 84
 85            // Calculate u2 = r * w mod q
 386            var u2 = (r * w) % _key.Q;
 87
 388            u1 = BigInteger.ModPow(_key.G, u1, _key.P);
 389            u2 = BigInteger.ModPow(_key.Y, u2, _key.P);
 90
 91            // Calculate v = ((g pow u1 * y pow u2) mod p) mod q
 392            var v = ((u1 * u2) % _key.P) % _key.Q;
 93
 94            // The signature is valid if v = r
 395            return v == r;
 396        }
 97
 98        /// <summary>
 99        /// Creates the signature.
 100        /// </summary>
 101        /// <param name="input">The input.</param>
 102        /// <returns>
 103        /// Signed input data.
 104        /// </returns>
 105        /// <exception cref="SshException">Invalid DSA key.</exception>
 106        public override byte[] Sign(byte[] input)
 1107        {
 1108            var hashInput = _hash.ComputeHash(input);
 109
 1110            var m = new BigInteger(hashInput.Reverse().Concat(new byte[] { 0 }));
 111
 112            BigInteger s;
 113            BigInteger r;
 114
 115            do
 1116            {
 1117                var k = BigInteger.Zero;
 118
 119                do
 1120                {
 121                    // Generate a random per-message value k where 0 < k < q
 1122                    var bitLength = _key.Q.BitLength;
 123
 1124                    if (_key.Q < BigInteger.Zero)
 0125                    {
 0126                        throw new SshException("Invalid DSA key.");
 127                    }
 128
 2129                    while (k <= 0 || k >= _key.Q)
 1130                    {
 1131                        k = BigInteger.Random(bitLength);
 1132                    }
 133
 134                    // Calculate r = ((g pow k) mod p) mod q
 1135                    r = BigInteger.ModPow(_key.G, k, _key.P) % _key.Q;
 136
 137                    // In the unlikely case that r = 0, start again with a different random k
 1138                }
 1139                while (r.IsZero);
 140
 141                // Calculate s = ((k pow āˆ’1)(H(m) + x*r)) mod q
 1142                k = BigInteger.ModInverse(k, _key.Q) * (m + (_key.X * r));
 143
 1144                s = k % _key.Q;
 145
 146                // In the unlikely case that s = 0, start again with a different random k
 1147            }
 1148            while (s.IsZero);
 149
 150            // The signature is (r, s)
 1151            var signature = new byte[40];
 152
 153            // issue #1918: pad part with zero's on the left if length is less than 20
 1154            var rBytes = r.ToByteArray().Reverse().TrimLeadingZeros();
 1155            Array.Copy(rBytes, 0, signature, 20 - rBytes.Length, rBytes.Length);
 156
 157            // issue #1918: pad part with zero's on the left if length is less than 20
 1158            var sBytes = s.ToByteArray().Reverse().TrimLeadingZeros();
 1159            Array.Copy(sBytes, 0, signature, 40 - sBytes.Length, sBytes.Length);
 160
 1161            return signature;
 1162        }
 163
 164        /// <summary>
 165        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 166        /// </summary>
 167        public void Dispose()
 0168        {
 0169            Dispose(disposing: true);
 0170            GC.SuppressFinalize(this);
 0171        }
 172
 173        /// <summary>
 174        /// Releases unmanaged and - optionally - managed resources.
 175        /// </summary>
 176        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langwor
 177        protected virtual void Dispose(bool disposing)
 16178        {
 16179            if (_isDisposed)
 0180            {
 0181                return;
 182            }
 183
 16184            if (disposing)
 0185            {
 0186                var hash = _hash;
 0187                if (hash != null)
 0188                {
 0189                    hash.Dispose();
 0190                    _hash = null;
 0191                }
 192
 0193                _isDisposed = true;
 0194            }
 16195        }
 196
 197        /// <summary>
 198        /// Finalizes an instance of the <see cref="DsaDigitalSignature"/> class.
 199        /// </summary>
 200        ~DsaDigitalSignature()
 32201        {
 16202            Dispose(disposing: false);
 32203        }
 204    }
 205}