ln.snmp/channel/USMEndpoint.cs

146 lines
4.3 KiB
C#

using System;
using System.Net;
using ln.snmp.types;
using System.Text;
using System.Security.Cryptography;
using ln.snmp.asn1;
using System.Linq;
namespace ln.snmp.channel
{
public enum SnmpV3AuthMethod { MD5, SHA }
public enum SnmpV3PrivMethod { DES }
public enum SnmpAuthLevel : int { noAuthNoPriv = 0, authNoPriv = 0x01, authPriv = 0x03 }
public class USMEndpoint : SNMPInterface
{
public OctetString RemoteEngineID { get; set; }
public string Username { get; set; }
public string AuthKey { get; set; }
public string PrivKey { get; set; }
public SnmpV3AuthMethod AuthMethod { get; set; }
public SnmpV3PrivMethod PrivMethod { get; set; }
public override SnmpVersion SnmpVersion => SnmpVersion.V3;
public USMEndpoint(SNMPEngine snmpEngine,IPEndPoint remoteEndpoint)
:base(snmpEngine,remoteEndpoint)
{
}
public SnmpAuthLevel AuthLevel
{
get
{
if (PrivKey != null)
return SnmpAuthLevel.authPriv;
if (AuthKey != null)
return SnmpAuthLevel.authNoPriv;
return SnmpAuthLevel.noAuthNoPriv;
}
}
public override PDU snmpRequest(PDU pdu)
{
if ((RemoteEngineID == null)||(RemoteEngineID.Bytes.Length == 0))
{
QueryEngineID();
}
USMMessage request = new USMMessage();
ScopedPDU scopedPDU = new ScopedPDU();
request.MessageID = SNMPEngine.NextMessageID;
request.msgData = scopedPDU;
scopedPDU.contextEngineID = RemoteEngineID;
scopedPDU.PDU = pdu;
AuthenticateMessage(request);
SnmpMessage reply = SNMPEngine.SNMPRequest(RemoteEndpoint, request, SNMPEngine.Timeout);
USMMessage replyUSM = reply as USMMessage;
PDU responsePDU = (replyUSM.msgData as ScopedPDU).PDU;
return responsePDU;
}
public void QueryEngineID()
{
USMMessage queryMessage = new USMMessage();
queryMessage.MessageID = SNMPEngine.NextMessageID;
ScopedPDU scopedPDU = new ScopedPDU();
queryMessage.msgData = scopedPDU;
queryMessage.Dump();
SnmpMessage reply = SNMPEngine.SNMPRequest(RemoteEndpoint, queryMessage, SNMPEngine.Timeout);
USMMessage usmReply = reply as USMMessage;
RemoteEngineID = usmReply.SecurityParameters.msgAuthoritativeEngineID;
}
public bool AuthenticateMessage(USMMessage message)
{
message.msgGlobalData.msgFlags.Bytes = new byte[] { (byte)(int)AuthLevel };
message.SecurityParameters.msgUserName.StringValue = Username;
message.SecurityParameters.msgAuthoritativeEngineID = RemoteEngineID;
message.SecurityParameters.msgAuthenticationParameters.Bytes = new byte[12];
byte[] wholeMsg = ((ASN1Value)message).AsByteArray;
byte[] extendedAuthKey = new byte[64];
byte[] authKey = Encoding.ASCII.GetBytes(AuthKey);
//Array.Copy(authKey, extendedAuthKey, 16);
//byte[] K1 = new byte[64];
//for (int n = 0; n < 64; n++)
// K1[n] = (byte)(extendedAuthKey[n] ^ IPAD[n]);
//byte[] K2 = new byte[64];
//for (int n = 0; n < 64; n++)
//K2[n] = (byte)(extendedAuthKey[n] ^ OPAD[n]);
HMAC hmac = null;
switch (AuthMethod)
{
case SnmpV3AuthMethod.MD5:
hmac = HMACMD5.Create();
break;
case SnmpV3AuthMethod.SHA:
hmac = HMACSHA1.Create();
break;
}
hmac.Key = authKey;
byte[] mac = hmac.ComputeHash(wholeMsg);
message.SecurityParameters.msgAuthenticationParameters.Bytes = mac.Take(12).ToArray();
return true;
}
static byte[] IPAD = __PAD(0x36);
static byte[] OPAD = __PAD(0x5C);
public static byte[] __PAD(byte pad)
{
byte[] ipad = new byte[0x40];
for (int n = 0; n < ipad.Length; n++)
ipad[n] = pad;
return ipad;
}
}
}