프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

markus / MarkusAutoUpdate / src / NetSparkle / SignatureVerifiers / DSAChecker.cs @ d8f5045e

이력 | 보기 | 이력해설 | 다운로드 (7.45 KB)

1
using System;
2
using System.Diagnostics;
3
using System.Linq;
4
using System.IO;
5
using System.Reflection;
6
using System.Security.Cryptography;
7
using NetSparkleUpdater.Enums;
8
using NetSparkleUpdater.Interfaces;
9

    
10
namespace NetSparkleUpdater.SignatureVerifiers
11
{
12
    /// <summary>
13
    /// Class to verify a DSA signature
14
    /// </summary>
15
    public class DSAChecker : ISignatureVerifier
16
    {
17
        private DSACryptoServiceProvider _cryptoProvider;
18

    
19
        /// <summary>
20
        /// Determines if a public key exists
21
        /// </summary>
22
        /// <returns><c>bool</c></returns>
23
        public bool HasValidKeyInformation()
24
        {
25
            return _cryptoProvider != null;
26
        }
27

    
28
        /// <summary>
29
        /// Create a DSAChecker object from the given parameters
30
        /// </summary>
31
        /// <param name="mode">The security mode of the validator. Controls what needs to be set in order to validate
32
        /// an app cast and its items.</param>
33
        /// <param name="publicKey">the public key as string (will be preferred before the file)</param>
34
        /// <param name="publicKeyFile">the public key file</param>
35
        public DSAChecker(SecurityMode mode, string publicKey = null, string publicKeyFile = "NetSparkle_DSA.pub")
36
        {
37
            SecurityMode = mode;
38

    
39
            string key = publicKey;
40

    
41
            if (string.IsNullOrEmpty(key))
42
            {
43
                Stream data = TryGetResourceStream(publicKeyFile);
44
                if (data == null)
45
                {
46
                    data = TryGetFileResource(publicKeyFile, data);
47
                }
48

    
49
                if (data != null)
50
                {
51
                    using (StreamReader reader = new StreamReader(data))
52
                    {
53
                        key = reader.ReadToEnd();
54
                    }
55
                }
56
            }
57

    
58
            if (!string.IsNullOrEmpty(key))
59
            {
60
                try
61
                {
62
                    _cryptoProvider = new DSACryptoServiceProvider();
63
                    _cryptoProvider.FromXmlString(key);
64
                }
65
                catch
66
                {
67
                    _cryptoProvider = null;
68
                }
69
            }
70
        }
71

    
72
        /// <summary>
73
        /// <inheritdoc/>
74
        /// </summary>
75
        public SecurityMode SecurityMode { get; set; }
76

    
77
        private bool CheckSecurityMode(string signature, ref ValidationResult result)
78
        {
79
            switch (SecurityMode)
80
            {
81
                case SecurityMode.UseIfPossible:
82
                    // if we have a DSA key, we only accept non-null signatures
83
                    if (HasValidKeyInformation() && string.IsNullOrEmpty(signature))
84
                    {
85
                        result = ValidationResult.Invalid;
86
                        return false;
87
                    }
88
                    // if we don't have an dsa key, we accept any signature
89
                    if (!HasValidKeyInformation())
90
                    {
91
                        result = ValidationResult.Unchecked;
92
                        return false;
93
                    }
94
                    break;
95

    
96
                case SecurityMode.Strict:
97
                    // only accept if we have both a public key and a non-null signature
98
                    if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature))
99
                    {
100
                        result = ValidationResult.Invalid;
101
                        return false;
102
                    }
103
                    break;
104
                
105
                case SecurityMode.Unsafe:
106
                    // always accept anything
107
                    // If we don't have a signature, make sure to note this as "Unchecked" since we
108
                    // didn't end up checking anything due to a lack of public key/signature
109
                    if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature))
110
                    {
111
                        result = ValidationResult.Unchecked;
112
                        return false;
113
                    }
114
                    break;
115

    
116
                case SecurityMode.OnlyVerifySoftwareDownloads:
117
                    // If we don't have a signature, make sure to note this as "Unchecked" since we
118
                    // didn't end up checking anything due to a lack of public key/signature
119
                    if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature))
120
                    {
121
                        result = ValidationResult.Unchecked;
122
                        return false;
123
                    }
124
                    break;
125
            }
126
            return true;
127
        }
128

    
129
        /// <inheritdoc/>
130
        public ValidationResult VerifySignature(string signature, byte[] dataToVerify)
131
        {
132
            ValidationResult res = ValidationResult.Invalid;
133
            if (!CheckSecurityMode(signature, ref res))
134
            {
135
                return res;
136
            }
137

    
138
            // convert signature
139
            byte[] bHash = Convert.FromBase64String(signature);
140

    
141
            // verify
142
            return _cryptoProvider.VerifyData(dataToVerify, bHash) ? ValidationResult.Valid : ValidationResult.Invalid;
143
        }
144

    
145
        /// <inheritdoc/>
146
        public ValidationResult VerifySignatureOfFile(string signature, string binaryPath)
147
        {
148
            using (Stream inputStream = File.OpenRead(binaryPath))
149
            {
150
                return VerifySignature(signature, Utilities.ConvertStreamToByteArray(inputStream));
151
            }
152
        }
153

    
154
        /// <inheritdoc/>
155
        public ValidationResult VerifySignatureOfString(string signature, string data)
156
        {
157
            // creating stream from string
158
            using (var stream = new MemoryStream())
159
            using (var writer = new StreamWriter(stream))
160
            {
161
                writer.Write(data);
162
                writer.Flush();
163
                stream.Position = 0;
164

    
165
                return VerifySignature(signature, Utilities.ConvertStreamToByteArray(stream));
166
            }
167
        }
168

    
169
        /// <summary>
170
        /// Gets a file resource
171
        /// </summary>
172
        /// <param name="publicKey">the public key</param>
173
        /// <param name="data">the data stream</param>
174
        /// <returns>the data stream</returns>
175
        private static Stream TryGetFileResource(string publicKey, Stream data)
176
        {
177
            if (File.Exists(publicKey))
178
            {
179
                data = File.OpenRead(publicKey);
180
            }
181
            return data;
182
        }
183

    
184
        /// <summary>
185
        /// Get a resource stream
186
        /// </summary>
187
        /// <param name="publicKey">the public key</param>
188
        /// <returns>a stream</returns>
189
        private static Stream TryGetResourceStream(string publicKey)
190
        {
191
            Stream data = null;
192
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
193
            {
194
                string[] resources;
195
                try
196
                {
197
                    resources = asm.GetManifestResourceNames();
198
                }
199
                catch (NotSupportedException)
200
                {
201
                    continue;
202
                }
203
                var resourceName = resources.FirstOrDefault(s => s.IndexOf(publicKey, StringComparison.OrdinalIgnoreCase) > -1);
204
                if (!string.IsNullOrEmpty(resourceName))
205
                {
206
                    data = asm.GetManifestResourceStream(resourceName);
207
                    if (data != null)
208
                    {
209
                        break;
210
                    }
211
                }
212
            }
213
            return data;
214
        }
215
    }
216
}
클립보드 이미지 추가 (최대 크기: 500 MB)