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; } } }