Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 34 additions & 24 deletions src/Renci.SshNet/Abstractions/CryptoAbstraction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,75 +84,85 @@ public static System.Security.Cryptography.RIPEMD160 CreateRIPEMD160()
}
#endif // FEATURE_HASH_RIPEMD160

public static System.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key)
public static HMAC CreateHMACMD5(byte[] key)
{
#pragma warning disable CA5351 // Do not use broken cryptographic algorithms
return new System.Security.Cryptography.HMACMD5(key);
return new HMAC(new System.Security.Cryptography.HMACMD5(key));
#pragma warning restore CA5351 // Do not use broken cryptographic algorithms
}

public static HMACMD5 CreateHMACMD5(byte[] key, int hashSize)
public static HMAC CreateHMACMD5(byte[] key, int hashSize)
{
#pragma warning disable CA5351 // Do not use broken cryptographic algorithms
return new HMACMD5(key, hashSize);
return new HMAC(new HMACMD5(key, hashSize));
#pragma warning restore CA5351 // Do not use broken cryptographic algorithms
}

public static System.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key)
public static HMAC CreateHMACSHA1(byte[] key)
{
#pragma warning disable CA5350 // Do not use weak cryptographic algorithms
return new System.Security.Cryptography.HMACSHA1(key);
return new HMAC(new System.Security.Cryptography.HMACSHA1(key));
#pragma warning restore CA5350 // Do not use weak cryptographic algorithms
}

public static HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize)
public static HMAC CreateHMACSHA1(byte[] key, int hashSize)
{
#pragma warning disable CA5350 // Do not use weak cryptographic algorithms
return new HMACSHA1(key, hashSize);
return new HMAC(new HMACSHA1(key, hashSize));
#pragma warning restore CA5350 // Do not use weak cryptographic algorithms
}

public static System.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key)
public static HMAC CreateHMACSHA256(byte[] key)
{
return new System.Security.Cryptography.HMACSHA256(key);
return new HMAC(new System.Security.Cryptography.HMACSHA256(key));
}

public static HMACSHA256 CreateHMACSHA256(byte[] key, int hashSize)
public static HMAC CreateHMACSHA256(byte[] key, int hashSize)
{
return new HMACSHA256(key, hashSize);
return new HMAC(new HMACSHA256(key, hashSize));
}

public static System.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key)
public static HMAC CreateHMACSHA256(byte[] key, bool etm)
{
return new System.Security.Cryptography.HMACSHA384(key);
return new HMAC(new System.Security.Cryptography.HMACSHA256(key), etm);
}

public static HMACSHA384 CreateHMACSHA384(byte[] key, int hashSize)
public static HMAC CreateHMACSHA384(byte[] key)
{
return new HMACSHA384(key, hashSize);
return new HMAC(new System.Security.Cryptography.HMACSHA384(key));
}

public static System.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key)
public static HMAC CreateHMACSHA384(byte[] key, int hashSize)
{
return new System.Security.Cryptography.HMACSHA512(key);
return new HMAC(new HMACSHA384(key, hashSize));
}

public static HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize)
public static HMAC CreateHMACSHA512(byte[] key)
{
return new HMACSHA512(key, hashSize);
return new HMAC(new System.Security.Cryptography.HMACSHA512(key));
}

public static HMAC CreateHMACSHA512(byte[] key, int hashSize)
{
return new HMAC(new HMACSHA512(key, hashSize));
}

public static HMAC CreateHMACSHA512(byte[] key, bool etm)
{
return new HMAC(new System.Security.Cryptography.HMACSHA512(key), etm);
}

#if FEATURE_HMAC_RIPEMD160
public static System.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key)
public static HMAC CreateHMACRIPEMD160(byte[] key)
{
#pragma warning disable CA5350 // Do not use weak cryptographic algorithms
return new System.Security.Cryptography.HMACRIPEMD160(key);
return new HMAC(new System.Security.Cryptography.HMACRIPEMD160(key));
#pragma warning restore CA5350 // Do not use weak cryptographic algorithms
}
#else
public static global::SshNet.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key)
public static HMAC CreateHMACRIPEMD160(byte[] key)
{
return new global::SshNet.Security.Cryptography.HMACRIPEMD160(key);
return new HMAC(new global::SshNet.Security.Cryptography.HMACRIPEMD160(key));
}
#endif // FEATURE_HMAC_RIPEMD160
}
Expand Down
4 changes: 4 additions & 0 deletions src/Renci.SshNet/ConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
#pragma warning disable IDE0200 // Remove unnecessary lambda expression; We want to prevent instantiating the HashAlgorithm objects.
HmacAlgorithms = new Dictionary<string, HashInfo>
{
/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
{ "hmac-sha2-256", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key)) },
{ "hmac-sha2-512", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key)) },
{ "hmac-sha2-512-96", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96)) },
Expand All @@ -386,6 +387,9 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
{ "hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96)) },
{ "hmac-md5", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key)) },
{ "hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96)) },
/* Encrypt-then-MAC variants */
{ "[email protected]", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, etm: true)) },
{ "[email protected]", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, etm: true)) },
};
#pragma warning restore IDE0200 // Remove unnecessary lambda expression

Expand Down
13 changes: 9 additions & 4 deletions src/Renci.SshNet/HashInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;

namespace Renci.SshNet
{
Expand All @@ -20,17 +20,22 @@ public class HashInfo
/// <summary>
/// Gets the cipher.
/// </summary>
public Func<byte[], HashAlgorithm> HashAlgorithm { get; private set; }
public Func<byte[], HMAC> HMAC { get; private set; }

/// <summary>
/// Gets a value indicating whether Encrypt-then-MAC or not.
/// </summary>
public bool ETM { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="HashInfo"/> class.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <param name="hash">The hash algorithm to use for a given key.</param>
public HashInfo(int keySize, Func<byte[], HashAlgorithm> hash)
public HashInfo(int keySize, Func<byte[], HMAC> hash)
{
KeySize = keySize;
HashAlgorithm = key => hash(key.Take(KeySize / 8));
HMAC = key => hash(key.Take(KeySize / 8));
}
}
}
10 changes: 7 additions & 3 deletions src/Renci.SshNet/Messages/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ protected override void WriteBytes(SshDataStream stream)
base.WriteBytes(stream);
}

internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor)
internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor, bool etm = false)
{
const int outboundPacketSequenceSize = 4;

Expand Down Expand Up @@ -78,7 +78,9 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor)
var packetLength = messageLength + 4 + 1;

// determine the padding length
var paddingLength = GetPaddingLength(paddingMultiplier, packetLength);
// in Encrypt-then-MAC mode, the length field is not encrypted, so we should keep it out of the
// padding length calculation
var paddingLength = GetPaddingLength(paddingMultiplier, etm ? packetLength - 4 : packetLength);

// add padding bytes
var paddingBytes = new byte[paddingLength];
Expand All @@ -104,7 +106,9 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor)
var packetLength = messageLength + 4 + 1;

// determine the padding length
var paddingLength = GetPaddingLength(paddingMultiplier, packetLength);
// in Encrypt-then-MAC mode, the length field is not encrypted, so we should keep it out of the
// padding length calculation
var paddingLength = GetPaddingLength(paddingMultiplier, etm ? packetLength - 4 : packetLength);

var packetDataLength = GetPacketDataLength(messageLength, paddingLength);

Expand Down
49 changes: 49 additions & 0 deletions src/Renci.SshNet/Security/Cryptography/HMAC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Security.Cryptography;

namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Represents the info for Message Authentication Code (MAC).
/// </summary>
public sealed class HMAC : IDisposable
{
/// <summary>
/// Initializes a new instance of the <see cref="HMAC"/> class.
/// </summary>
/// <param name="hashAlgorithm">The hash algorithm.</param>
public HMAC(HashAlgorithm hashAlgorithm)
: this(hashAlgorithm, etm: false)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="HMAC"/> class.
/// </summary>
/// <param name="hashAlgorithm">The hash algorithm.</param>
/// <param name="etm"><see langword="true"/> to enable encrypt-then-MAC, <see langword="false"/> to use encrypt-and-MAC.</param>
public HMAC(
HashAlgorithm hashAlgorithm,
bool etm)
{
HashAlgorithm = hashAlgorithm;
ETM = etm;
}

/// <inheritdoc/>
public void Dispose()
{
HashAlgorithm?.Dispose();
}

/// <summary>
/// Gets the hash algorithem.
/// </summary>
public HashAlgorithm HashAlgorithm { get; private set; }

/// <summary>
/// Gets a value indicating whether enable encryption-to-mac or encryption-then-mac.
/// </summary>
public bool ETM { get; private set; }
}
}
5 changes: 2 additions & 3 deletions src/Renci.SshNet/Security/IKeyExchange.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Security.Cryptography;

using Renci.SshNet.Common;
using Renci.SshNet.Compression;
Expand Down Expand Up @@ -69,15 +68,15 @@ public interface IKeyExchange : IDisposable
/// <returns>
/// The server hash algorithm.
/// </returns>
HashAlgorithm CreateServerHash();
HMAC CreateServerHash();

/// <summary>
/// Creates the client-side hash algorithm to use.
/// </summary>
/// <returns>
/// The client hash algorithm.
/// </returns>
HashAlgorithm CreateClientHash();
HMAC CreateClientHash();

/// <summary>
/// Creates the compression algorithm to use to deflate data.
Expand Down
11 changes: 5 additions & 6 deletions src/Renci.SshNet/Security/KeyExchange.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;

using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
Expand Down Expand Up @@ -103,7 +102,7 @@ from a in message.MacAlgorithmsClientToServer
select a).FirstOrDefault();
if (string.IsNullOrEmpty(clientHmacAlgorithmName))
{
throw new SshConnectionException("Server HMAC algorithm not found", DisconnectReason.KeyExchangeFailed);
throw new SshConnectionException("Client HMAC algorithm not found", DisconnectReason.KeyExchangeFailed);
}

session.ConnectionInfo.CurrentClientHmacAlgorithm = clientHmacAlgorithmName;
Expand Down Expand Up @@ -221,7 +220,7 @@ public Cipher CreateClientCipher()
/// <returns>
/// The server-side hash algorithm.
/// </returns>
public HashAlgorithm CreateServerHash()
public HMAC CreateServerHash()
{
// Resolve Session ID
var sessionId = Session.SessionId ?? ExchangeHash;
Expand All @@ -235,7 +234,7 @@ public HashAlgorithm CreateServerHash()
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentServerHmacAlgorithm));

return _serverHashInfo.HashAlgorithm(serverKey);
return _serverHashInfo.HMAC(serverKey);
}

/// <summary>
Expand All @@ -244,7 +243,7 @@ public HashAlgorithm CreateServerHash()
/// <returns>
/// The client-side hash algorithm.
/// </returns>
public HashAlgorithm CreateClientHash()
public HMAC CreateClientHash()
{
// Resolve Session ID
var sessionId = Session.SessionId ?? ExchangeHash;
Expand All @@ -258,7 +257,7 @@ public HashAlgorithm CreateClientHash()
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentClientHmacAlgorithm));

return _clientHashInfo.HashAlgorithm(clientKey);
return _clientHashInfo.HMAC(clientKey);
}

/// <summary>
Expand Down
Loading