| | | 1 | | using System.Collections.Generic; |
| | | 2 | | using System.Text; |
| | | 3 | | |
| | | 4 | | using Renci.SshNet.Common; |
| | | 5 | | using Renci.SshNet.Security.Chaos.NaCl; |
| | | 6 | | using Renci.SshNet.Security.Cryptography; |
| | | 7 | | |
| | | 8 | | namespace Renci.SshNet.Security |
| | | 9 | | { |
| | | 10 | | /// <summary> |
| | | 11 | | /// Implements key support for host algorithm. |
| | | 12 | | /// </summary> |
| | | 13 | | public class KeyHostAlgorithm : HostAlgorithm |
| | | 14 | | { |
| | | 15 | | /// <summary> |
| | | 16 | | /// Gets the key used in this host key algorithm. |
| | | 17 | | /// </summary> |
| | | 18 | | /// <value> |
| | | 19 | | /// The key used in this host key algorithm. |
| | | 20 | | /// </value> |
| | 10435 | 21 | | public Key Key { get; private set; } |
| | | 22 | | |
| | | 23 | | /// <summary> |
| | | 24 | | /// Gets the signature implementation used in this host key algorithm. |
| | | 25 | | /// </summary> |
| | | 26 | | /// <value> |
| | | 27 | | /// The signature implementation used in this host key algorithm. |
| | | 28 | | /// </value> |
| | 4723 | 29 | | public DigitalSignature DigitalSignature { get; private set; } |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Gets the encoded public key data. |
| | | 33 | | /// </summary> |
| | | 34 | | /// <value> |
| | | 35 | | /// The encoded public key data. |
| | | 36 | | /// </value> |
| | | 37 | | public override byte[] Data |
| | | 38 | | { |
| | | 39 | | get |
| | 2590 | 40 | | { |
| | 2590 | 41 | | var keyFormatIdentifier = Key is RsaKey ? "ssh-rsa" : Name; |
| | 2590 | 42 | | return new SshKeyData(keyFormatIdentifier, Key.Public).GetBytes(); |
| | 2590 | 43 | | } |
| | | 44 | | } |
| | | 45 | | |
| | | 46 | | /// <summary> |
| | | 47 | | /// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class. |
| | | 48 | | /// </summary> |
| | | 49 | | /// <param name="name">The signature format identifier.</param> |
| | | 50 | | /// <param name="key"><inheritdoc cref="Key" path="/summary"/></param> |
| | | 51 | | /// <remarks> |
| | | 52 | | /// This constructor is typically passed a private key in order to create an encoded signature for later |
| | | 53 | | /// verification by the host. |
| | | 54 | | /// </remarks> |
| | | 55 | | public KeyHostAlgorithm(string name, Key key) |
| | 576 | 56 | | : base(name) |
| | 576 | 57 | | { |
| | 576 | 58 | | Key = key; |
| | 576 | 59 | | DigitalSignature = key.DigitalSignature; |
| | 576 | 60 | | } |
| | | 61 | | |
| | | 62 | | /// <summary> |
| | | 63 | | /// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class. |
| | | 64 | | /// </summary> |
| | | 65 | | /// <param name="name">The signature format identifier.</param> |
| | | 66 | | /// <param name="key"><inheritdoc cref="Key" path="/summary"/></param> |
| | | 67 | | /// <param name="digitalSignature"><inheritdoc cref="DigitalSignature" path="/summary"/></param> |
| | | 68 | | /// <remarks> |
| | | 69 | | /// <para> |
| | | 70 | | /// This constructor is typically passed a private key in order to create an encoded signature for later |
| | | 71 | | /// verification by the host. |
| | | 72 | | /// </para> |
| | | 73 | | /// The key used by <paramref name="digitalSignature"/> is intended to be equal to <paramref name="key"/>. |
| | | 74 | | /// This is not verified. |
| | | 75 | | /// </remarks> |
| | | 76 | | public KeyHostAlgorithm(string name, Key key, DigitalSignature digitalSignature) |
| | 1037 | 77 | | : base(name) |
| | 1037 | 78 | | { |
| | 1037 | 79 | | Key = key; |
| | 1037 | 80 | | DigitalSignature = digitalSignature; |
| | 1037 | 81 | | } |
| | | 82 | | |
| | | 83 | | /// <summary> |
| | | 84 | | /// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class |
| | | 85 | | /// with the given encoded public key data. The data will be decoded into <paramref name="key"/>. |
| | | 86 | | /// </summary> |
| | | 87 | | /// <param name="name">The signature format identifier.</param> |
| | | 88 | | /// <param name="key"><inheritdoc cref="Key" path="/summary"/></param> |
| | | 89 | | /// <param name="data">Host key encoded data.</param> |
| | | 90 | | /// <remarks> |
| | | 91 | | /// This constructor is typically passed a new or reusable <see cref="Security.Key"/> instance in |
| | | 92 | | /// order to verify an encoded signature sent by the host, created by the private counterpart |
| | | 93 | | /// to the host's public key, which is encoded in <paramref name="data"/>. |
| | | 94 | | /// </remarks> |
| | | 95 | | public KeyHostAlgorithm(string name, Key key, byte[] data) |
| | 12 | 96 | | : base(name) |
| | 12 | 97 | | { |
| | 12 | 98 | | Key = key; |
| | | 99 | | |
| | 12 | 100 | | var sshKey = new SshKeyData(); |
| | 12 | 101 | | sshKey.Load(data); |
| | 12 | 102 | | Key.Public = sshKey.Keys; |
| | | 103 | | |
| | 12 | 104 | | DigitalSignature = key.DigitalSignature; |
| | 12 | 105 | | } |
| | | 106 | | |
| | | 107 | | /// <summary> |
| | | 108 | | /// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class |
| | | 109 | | /// with the given encoded public key data. The data will be decoded into <paramref name="key"/>. |
| | | 110 | | /// </summary> |
| | | 111 | | /// <param name="name">The signature format identifier.</param> |
| | | 112 | | /// <param name="key"><inheritdoc cref="Key" path="/summary"/></param> |
| | | 113 | | /// <param name="data">Host key encoded data.</param> |
| | | 114 | | /// <param name="digitalSignature"><inheritdoc cref="DigitalSignature" path="/summary"/></param> |
| | | 115 | | /// <remarks> |
| | | 116 | | /// <para> |
| | | 117 | | /// This constructor is typically passed a new or reusable <see cref="Security.Key"/> instance in |
| | | 118 | | /// order to verify an encoded signature sent by the host, created by the private counterpart |
| | | 119 | | /// to the host's public key, which is encoded in <paramref name="data"/>. |
| | | 120 | | /// </para> |
| | | 121 | | /// The key used by <paramref name="digitalSignature"/> is intended to be equal to <paramref name="key"/>. |
| | | 122 | | /// This is not verified. |
| | | 123 | | /// </remarks> |
| | | 124 | | public KeyHostAlgorithm(string name, Key key, byte[] data, DigitalSignature digitalSignature) |
| | 1196 | 125 | | : base(name) |
| | 1196 | 126 | | { |
| | 1196 | 127 | | Key = key; |
| | | 128 | | |
| | 1196 | 129 | | var sshKey = new SshKeyData(); |
| | 1196 | 130 | | sshKey.Load(data); |
| | 1196 | 131 | | Key.Public = sshKey.Keys; |
| | | 132 | | |
| | 1196 | 133 | | DigitalSignature = digitalSignature; |
| | 1196 | 134 | | } |
| | | 135 | | |
| | | 136 | | /// <summary> |
| | | 137 | | /// Signs and encodes the specified data. |
| | | 138 | | /// </summary> |
| | | 139 | | /// <param name="data">The data to be signed.</param> |
| | | 140 | | /// <returns> |
| | | 141 | | /// The encoded signature. |
| | | 142 | | /// </returns> |
| | | 143 | | public override byte[] Sign(byte[] data) |
| | 689 | 144 | | { |
| | 689 | 145 | | return new SignatureKeyData(Name, DigitalSignature.Sign(data)).GetBytes(); |
| | 689 | 146 | | } |
| | | 147 | | |
| | | 148 | | /// <summary> |
| | | 149 | | /// Verifies the signature. |
| | | 150 | | /// </summary> |
| | | 151 | | /// <param name="data">The data to verify the signature against.</param> |
| | | 152 | | /// <param name="signature">The encoded signature data.</param> |
| | | 153 | | /// <returns> |
| | | 154 | | /// <see langword="true"/> if <paramref name="signature"/> is the result of signing <paramref name="data"/> |
| | | 155 | | /// with the corresponding private key to <see cref="Key"/>. |
| | | 156 | | /// </returns> |
| | | 157 | | public override bool VerifySignature(byte[] data, byte[] signature) |
| | 9 | 158 | | { |
| | 9 | 159 | | var signatureData = new SignatureKeyData(); |
| | 9 | 160 | | signatureData.Load(signature); |
| | | 161 | | |
| | 9 | 162 | | return DigitalSignature.Verify(data, signatureData.Signature); |
| | 9 | 163 | | } |
| | | 164 | | |
| | | 165 | | private sealed class SshKeyData : SshData |
| | | 166 | | { |
| | | 167 | | private byte[] _name; |
| | | 168 | | private List<byte[]> _keys; |
| | | 169 | | |
| | | 170 | | public BigInteger[] Keys |
| | | 171 | | { |
| | | 172 | | get |
| | 1208 | 173 | | { |
| | 1208 | 174 | | var keys = new BigInteger[_keys.Count]; |
| | | 175 | | |
| | 7254 | 176 | | for (var i = 0; i < _keys.Count; i++) |
| | 2419 | 177 | | { |
| | 2419 | 178 | | var key = _keys[i]; |
| | 2419 | 179 | | keys[i] = key.ToBigInteger2(); |
| | 2419 | 180 | | } |
| | | 181 | | |
| | 1208 | 182 | | return keys; |
| | 1208 | 183 | | } |
| | | 184 | | private set |
| | 2590 | 185 | | { |
| | 2590 | 186 | | _keys = new List<byte[]>(value.Length); |
| | | 187 | | |
| | 18138 | 188 | | foreach (var key in value) |
| | 5184 | 189 | | { |
| | 5184 | 190 | | var keyData = key.ToByteArray().Reverse(); |
| | 5184 | 191 | | if (Name == "ssh-ed25519") |
| | 4 | 192 | | { |
| | 4 | 193 | | keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); |
| | 4 | 194 | | } |
| | | 195 | | |
| | 5184 | 196 | | _keys.Add(keyData); |
| | 5184 | 197 | | } |
| | 2590 | 198 | | } |
| | | 199 | | } |
| | | 200 | | |
| | | 201 | | private string Name |
| | | 202 | | { |
| | 15552 | 203 | | get { return Utf8.GetString(_name, 0, _name.Length); } |
| | 7770 | 204 | | set { _name = Utf8.GetBytes(value); } |
| | | 205 | | } |
| | | 206 | | |
| | | 207 | | protected override int BufferCapacity |
| | | 208 | | { |
| | | 209 | | get |
| | 2590 | 210 | | { |
| | 2590 | 211 | | var capacity = base.BufferCapacity; |
| | 2590 | 212 | | capacity += 4; // Name length |
| | 2590 | 213 | | capacity += _name.Length; // Name |
| | | 214 | | |
| | 18138 | 215 | | foreach (var key in _keys) |
| | 5184 | 216 | | { |
| | 5184 | 217 | | capacity += 4; // Key length |
| | 5184 | 218 | | capacity += key.Length; // Key |
| | 5184 | 219 | | } |
| | | 220 | | |
| | 2590 | 221 | | return capacity; |
| | 2590 | 222 | | } |
| | | 223 | | } |
| | | 224 | | |
| | 1208 | 225 | | public SshKeyData() |
| | 1208 | 226 | | { |
| | 1208 | 227 | | } |
| | | 228 | | |
| | 2590 | 229 | | public SshKeyData(string name, params BigInteger[] keys) |
| | 2590 | 230 | | { |
| | 2590 | 231 | | Name = name; |
| | 2590 | 232 | | Keys = keys; |
| | 2590 | 233 | | } |
| | | 234 | | |
| | | 235 | | protected override void LoadData() |
| | 1208 | 236 | | { |
| | 1208 | 237 | | _name = ReadBinary(); |
| | 1208 | 238 | | _keys = new List<byte[]>(); |
| | | 239 | | |
| | 3627 | 240 | | while (!IsEndOfData) |
| | 2419 | 241 | | { |
| | 2419 | 242 | | _keys.Add(ReadBinary()); |
| | 2419 | 243 | | } |
| | 1208 | 244 | | } |
| | | 245 | | |
| | | 246 | | protected override void SaveData() |
| | 2590 | 247 | | { |
| | 2590 | 248 | | WriteBinaryString(_name); |
| | | 249 | | |
| | 18138 | 250 | | foreach (var key in _keys) |
| | 5184 | 251 | | { |
| | 5184 | 252 | | WriteBinaryString(key); |
| | 5184 | 253 | | } |
| | 2590 | 254 | | } |
| | | 255 | | } |
| | | 256 | | |
| | | 257 | | internal sealed class SignatureKeyData : SshData |
| | | 258 | | { |
| | | 259 | | /// <summary> |
| | | 260 | | /// Gets or sets the signature format identifier. |
| | | 261 | | /// </summary> |
| | | 262 | | /// <value> |
| | | 263 | | /// The signature format identifier. |
| | | 264 | | /// </value> |
| | 5673 | 265 | | public string AlgorithmName { get; set; } |
| | | 266 | | |
| | | 267 | | /// <summary> |
| | | 268 | | /// Gets the signature. |
| | | 269 | | /// </summary> |
| | | 270 | | /// <value> |
| | | 271 | | /// The signature. |
| | | 272 | | /// </value> |
| | 4482 | 273 | | public byte[] Signature { get; private set; } |
| | | 274 | | |
| | | 275 | | /// <summary> |
| | | 276 | | /// Gets the size of the message in bytes. |
| | | 277 | | /// </summary> |
| | | 278 | | /// <value> |
| | | 279 | | /// The size of the messages in bytes. |
| | | 280 | | /// </value> |
| | | 281 | | protected override int BufferCapacity |
| | | 282 | | { |
| | | 283 | | get |
| | 689 | 284 | | { |
| | 689 | 285 | | var capacity = base.BufferCapacity; |
| | 689 | 286 | | capacity += 4; // AlgorithmName length |
| | 689 | 287 | | capacity += Encoding.UTF8.GetByteCount(AlgorithmName); // AlgorithmName |
| | 689 | 288 | | capacity += 4; // Signature length |
| | 689 | 289 | | capacity += Signature.Length; // Signature |
| | 689 | 290 | | return capacity; |
| | 689 | 291 | | } |
| | | 292 | | } |
| | | 293 | | |
| | 1208 | 294 | | public SignatureKeyData() |
| | 1208 | 295 | | { |
| | 1208 | 296 | | } |
| | | 297 | | |
| | 689 | 298 | | public SignatureKeyData(string name, byte[] signature) |
| | 689 | 299 | | { |
| | 689 | 300 | | AlgorithmName = name; |
| | 689 | 301 | | Signature = signature; |
| | 689 | 302 | | } |
| | | 303 | | |
| | | 304 | | /// <summary> |
| | | 305 | | /// Called when type specific data need to be loaded. |
| | | 306 | | /// </summary> |
| | | 307 | | protected override void LoadData() |
| | 1208 | 308 | | { |
| | 1208 | 309 | | AlgorithmName = Encoding.UTF8.GetString(ReadBinary()); |
| | 1208 | 310 | | Signature = ReadBinary(); |
| | 1208 | 311 | | } |
| | | 312 | | |
| | | 313 | | /// <summary> |
| | | 314 | | /// Called when type specific data need to be saved. |
| | | 315 | | /// </summary> |
| | | 316 | | protected override void SaveData() |
| | 689 | 317 | | { |
| | 689 | 318 | | WriteBinaryString(Encoding.UTF8.GetBytes(AlgorithmName)); |
| | 689 | 319 | | WriteBinaryString(Signature); |
| | 689 | 320 | | } |
| | | 321 | | } |
| | | 322 | | } |
| | | 323 | | } |