-
Notifications
You must be signed in to change notification settings - Fork 19
015: Implement hmac sha1
One thing about programming, it's all about the patterns. So, follow previous pages, let's create a folder called MACAlgorithms and create an interface IMACAlgorithm that implements from IAlgorithm.
public interface IMACAlgorithm : IAlgorithm { uint KeySize { get; } uint DigestLength { get; } void SetKey(byte[] key); byte[] ComputeHash(uint packetNumber, byte[] data); }
This has a KeySize and DigestLength property to help with the MAC hash creation. It also allows the client code to SetKey() and ComputeHash() for a given packet number and data. Now create a class HMACSHA1 that implements IMACAlgorithm:
public class HMACSHA1 : IMACAlgorithm { public uint DigestLength { get { throw new NotImplementedException(); } } public uint KeySize { get { throw new NotImplementedException(); } } public string Name { get { throw new NotImplementedException(); } } public byte[] ComputeHash(uint packetNumber, byte[] data) { throw new NotImplementedException(); } public void SetKey(byte[] key) { throw new NotImplementedException(); } }
All we need to do now is fill in the values for the hmac-sha1. The comments in the code link to relevant documents:
public class HMACSHA1 : IMACAlgorithm { System.Security.Cryptography.HMACSHA1 m_HMAC = null; public uint KeySize { get { // https://tools.ietf.org/html/rfc4253#section-6.4 // According to this, the KeySize is 20 return 20; } } public uint DigestLength { get { // https://tools.ietf.org/html/rfc4253#section-6.4 // According to this, the DigestLength is 20 return 20; } } public string Name { get { return "hmac-sha1"; } } public void SetKey(byte[] key) { m_HMAC = new System.Security.Cryptography.HMACSHA1(key); } public byte[] ComputeHash(uint packetNumber, byte[] data) { if (m_HMAC == null) throw new SSHServerException(DisconnectReason.SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "SetKey must be called before attempting to ComputeHash."); using (ByteWriter writer = new ByteWriter()) { writer.WriteUInt32(packetNumber); writer.WriteRawBytes(data); return m_HMAC.ComputeHash(writer.ToByteArray()); } } }
Now open Server and add the SupportedMACAlgorithms:
public static IReadOnlyList<Type> SupportedMACAlgorithms { get; private set; } = new List<Type>() { typeof(HMACSHA1) };
And open Client and add the supported algorithms to the KEX packet:
m_KexInitServerToClient.MacAlgorithmsClientToServer.AddRange(Server.GetNames(Server.SupportedMACAlgorithms)); m_KexInitServerToClient.MacAlgorithmsServerToClient.AddRange(Server.GetNames(Server.SupportedMACAlgorithms));
Once again, if you run the server, the output is the same, but the OpenSSH results are amazing:
debug2: KEX algorithms: diffie-hellman-group14-sha1 debug2: host key algorithms: ssh-rsa debug2: ciphers ctos: 3des-cbc debug2: ciphers stoc: 3des-cbc debug2: MACs ctos: hmac-sha1 debug2: MACs stoc: hmac-sha1 ... debug1: kex: algorithm: diffie-hellman-group14-sha1 debug1: kex: host key algorithm: ssh-rsa Unable to negotiate with 127.0.0.1 port 22: no matching compression method found. Their offer:
It clearly sees our offer of hmac-sha1, but is sad because we haven't provided a compression! We are getting very close now to providing all of the pieces needed. The code at this point is tagged with Implement_hmac-sh1. In the next section, we'll implement no compression.
If you'd like to give me a tip, donate at:
- Bitcoin (BTC): 1NdnffxFC7G7qMrvUYc1x4R5sqXuJhVFR7
- Etherium (ETH): 0xcF0a3f130ba0f8c4CC3A02F782805A448D45388f
- Litecoin (LTC): LV7JL8yA4fAZ3Lib9VoX1tuFPmPVrfFueT