프로젝트

일반

사용자정보

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

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

이력 | 보기 | 이력해설 | 다운로드 (7.69 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
using Org.BouncyCastle.Crypto.Signers;
10
using System.Text;
11
using Org.BouncyCastle.Crypto.Parameters;
12

    
13
namespace NetSparkleUpdater.SignatureVerifiers
14
{
15
    /// <summary>
16
    /// Class to verify a Ed25519 signature
17
    /// </summary>
18
    public class Ed25519Checker : ISignatureVerifier
19
    {
20
        private Ed25519Signer _signer;
21

    
22
        /// <summary>
23
        /// Determines if a public key exists
24
        /// </summary>
25
        /// <returns><c>bool</c></returns>
26
        public bool HasValidKeyInformation()
27
        {
28
            return _signer != null;
29
        }
30

    
31
        /// <summary>
32
        /// Create a Ed25519Checker object from the given parameters
33
        /// </summary>
34
        /// <param name="mode">The security mode of the validator. Controls what needs to be set in order to validate
35
        /// an app cast and its items.</param>
36
        /// <param name="publicKey">the base 64 public key as a string</param>
37
        /// <param name="publicKeyFile">the public key file</param>
38
        public Ed25519Checker(SecurityMode mode, string publicKey = null, string publicKeyFile = "NetSparkle_Ed25519.pub")
39
        {
40
            SecurityMode = mode;
41

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

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

    
59
            if (!string.IsNullOrEmpty(publicKey))
60
            {
61
                try
62
                {
63
                    _signer = new Ed25519Signer();
64
                    byte[] pubKeyBytes = Convert.FromBase64String(publicKey);
65
                    var cipherParams = new Ed25519PublicKeyParameters(pubKeyBytes, 0);
66
                    _signer.Init(false, cipherParams);
67
                }
68
                catch
69
                {
70
                    _signer = null;
71
                }
72
            }
73
        }
74

    
75
        /// <summary>
76
        /// <inheritdoc/>
77
        /// </summary>
78
        public SecurityMode SecurityMode { get; set; }
79

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

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

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

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

    
141
            // convert signature
142
            byte[] bHash = Convert.FromBase64String(signature);
143
            _signer.BlockUpdate(dataToVerify, 0, dataToVerify.Length);
144
            // verify
145
            return _signer.VerifySignature(bHash) ? ValidationResult.Valid : ValidationResult.Invalid;
146
        }
147

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

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

    
168
                return VerifySignature(signature, Utilities.ConvertStreamToByteArray(stream));
169
            }
170
        }
171

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

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