/// <summary>
        /// Build cached authentication and privacy encryption keys if they are appropriate for the selected security mode.
        /// </summary>
        /// <remarks>
        /// This method should be called after discovery process has been completed and all security related values
        /// have been set. For noAuthNoPriv, none of the keys are generated. authNoPriv will result in authentication
        /// key cached. authPriv will generate authentication and privacy keys.
        ///
        /// For successful key caching you need to set both relevant protocols and secret values.
        /// </remarks>
        public void BuildCachedSecurityKeys()
        {
            _authenticationKey = _privacyKey = null;

            if (_engineId == null || _engineId.Length <= 0)
            {
                return;
            }

            if (_authenticationSecret == null || _authenticationSecret.Length <= 0)
            {
                return;
            }

            if (_authenticationProtocol != AuthenticationDigests.None)
            {
                IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(_authenticationProtocol);
                if (authProto != null)
                {
                    _authenticationKey = authProto.PasswordToKey(_authenticationSecret, _engineId);
                    if (_privacyProtocol != PrivacyProtocols.None && _privacySecret != null && _privacySecret.Length > 0)
                    {
                        IPrivacyProtocol privProto = SnmpSharpNet.PrivacyProtocol.GetInstance(_privacyProtocol);
                        if (privProto != null)
                        {
                            _privacyKey = privProto.PasswordToKey(_privacySecret, _engineId, authProto);
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>Generate privacy key from authentication password and engine id</summary>
        /// <returns>Privacy key on success or null on failure</returns>
        public byte[] GeneratePrivacyKey()
        {
            if (userSecurityModel.Authentication == AuthenticationDigests.None)
            {
                return(null);
            }

            if (userSecurityModel.Privacy == EPrivacyProtocols.None)
            {
                return(null);
            }

            if (userSecurityModel.PrivacySecret == null || userSecurityModel.PrivacySecret.Length <= 0)
            {
                return(null);
            }

            IAuthenticationDigest authProto = Authentication.GetInstance(userSecurityModel.Authentication);

            if (authProto != null)
            {
                IPrivacyProtocol privProto = PrivacyProtocol.GetInstance(userSecurityModel.Privacy);
                if (privProto != null)
                {
                    return(privProto.PasswordToKey(userSecurityModel.PrivacySecret, userSecurityModel.EngineId, authProto));
                }
            }

            return(null);
        }
Exemplo n.º 3
0
        /// <summary>Encode SNMP version 3 packet</summary>
        /// <remarks>
        /// Before encoding the packet into a byte array you need to ensure all required information is
        /// set. Examples of required information is request type, Vbs (Oid + values pairs), USM settings including
        /// SecretName, authentication method and secret (if needed), privacy method and secret (if needed), etc.
        /// </remarks>
        /// <returns>Byte array BER encoded SNMP packet.</returns>
        public override byte[] Encode()
        {
            byte[] pkey = null;
            byte[] akey = null;

            if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0)
            {
                IAuthenticationDigest auth = Authentication.GetInstance(userSecurityModel.Authentication);

                if (auth == null)
                {
                    throw new SnmpException(SnmpException.EErrorCode.UnsupportedNoAuthPriv, "Invalid authentication protocol.");
                }

                akey = auth.PasswordToKey(userSecurityModel.AuthenticationSecret, userSecurityModel.EngineId);

                if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0)
                {
                    IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy);
                    if (privacyProtocol == null)
                    {
                        throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported.");
                    }
                    pkey = privacyProtocol.PasswordToKey(userSecurityModel.PrivacySecret, userSecurityModel.EngineId, auth);
                }
            }

            return(Encode(akey, pkey));
        }
Exemplo n.º 4
0
        /// <summary>Build cached authentication and privacy encryption keys if they are appropriate for the selected security mode.</summary>
        /// <remarks>
        /// This method should be called after discovery process has been completed and all security related values
        /// have been set. For noAuthNoPriv, none of the keys are generated. authNoPriv will result in authentication
        /// key cached. authPriv will generate authentication and privacy keys.
        ///
        /// For successful key caching you need to set both relevant protocols and secret values.
        /// </remarks>
        public void BuildCachedSecurityKeys()
        {
            authenticationKey = privacyKey = null;

            if (engineId == null || engineId.Length <= 0)
            {
                return;
            }

            if (authenticationSecret == null || authenticationSecret.Length <= 0)
            {
                return;
            }

            if (authenticationProtocol != AuthenticationDigests.None)
            {
                IAuthenticationDigest authProto = Security.Authentication.GetInstance(authenticationProtocol);
                if (authProto != null)
                {
                    authenticationKey = authProto.PasswordToKey(authenticationSecret, engineId);
                    if (privacyProtocol != EPrivacyProtocols.None && privacySecret != null && privacySecret.Length > 0)
                    {
                        IPrivacyProtocol privProto = PrivacyProtocol.GetInstance(privacyProtocol);
                        if (privProto != null)
                        {
                            privacyKey = privProto.PasswordToKey(privacySecret, engineId, authProto);
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Generate privacy key from authentication password and engine id
        /// </summary>
        /// <returns>Privacy key on success or null on failure</returns>
        public byte[] GeneratePrivacyKey()
        {
            if (USM.Authentication == AuthenticationDigests.None)
            {
                return(null);
            }

            if (USM.Privacy == PrivacyProtocols.None)
            {
                return(null);
            }

            if (USM.PrivacySecret == null || USM.PrivacySecret.Length <= 0)
            {
                return(null);
            }

            IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(USM.Authentication);

            if (authProto != null)
            {
                IPrivacyProtocol privProto = SnmpSharpNet.PrivacyProtocol.GetInstance(USM.Privacy);
                if (privProto != null)
                {
                    return(privProto.PasswordToKey(USM.PrivacySecret, USM.EngineId, authProto));
                }
            }
            return(null);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will
        /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call.
        /// </summary>
        /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param>
        /// <param name="length">Buffer length</param>
        public override int Decode(byte[] berBuffer, int length)
        {
            byte[] pkey = null;
            byte[] akey = null;
            if (MsgFlags.Authentication && USM.EngineId.Length > 0)
            {
                IAuthenticationDigest auth = Authentication.GetInstance(USM.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "Invalid authentication protocol.");
                }

                akey = auth.PasswordToKey(USM.AuthenticationSecret, USM.EngineId);
                if (MsgFlags.Privacy && USM.EngineId.Length > 0)
                {
                    IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(USM.Privacy);
                    if (privacyProtocol == null)
                    {
                        throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported.");
                    }

                    pkey = privacyProtocol.PasswordToKey(USM.PrivacySecret, USM.EngineId, auth);
                }
            }
            return(Decode(berBuffer, length, akey, pkey));
        }
Exemplo n.º 7
0
        /// <summary>BER encode security model field.</summary>
        /// <remarks>
        /// USM security model is a SEQUENCE encoded inside a OCTETSTRING. To encode it, first encode the sequence
        /// of class values then "wrap" it inside a OCTETSTRING field
        /// </remarks>
        /// <param name="buffer">Buffer to store encoded USM security model header</param>
        public override void encode(MutableByte buffer)
        {
            MutableByte tmp = new MutableByte();

            // First encode all the values that will form the sequence
            _engineId.encode(tmp);
            // Encode engine boots
            _engineBoots.encode(tmp);
            // encode engine time
            _engineTime.encode(tmp);
            _securityName.encode(tmp);
            if (_authentication != AuthenticationDigests.None)
            {
                if (_authenticationParameters.Length <= 0)
                {
                    // If authentication is used, set authentication parameters field to 12 bytes set to 0x00
                    _authenticationParameters.Set(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
                }
            }
            else
            {
                _authenticationParameters.Reset();
            }
            _authenticationParameters.encode(tmp);
            if (_privacy != PrivacyProtocols.None)
            {
                if (_privacyParameters.Length <= 0)
                {
                    IPrivacyProtocol privProto = PrivacyProtocol.GetInstance(_privacy);
                    if (privProto != null)
                    {
                        byte[] parameter = new byte[privProto.PrivacyParametersLength];
                        for (int i = 0; i < privProto.PrivacyParametersLength; i++)
                        {
                            parameter[i] = 0x00; // This is not necessary since all array members are, by default, initialized to 0
                        }
                        _privacyParameters.Set(parameter);
                    }
                    else
                    {
                        throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Unrecognized privacy protocol specified.");
                    }
                }
            }
            else
            {
                _privacyParameters.Reset();
            }
            _privacyParameters.encode(tmp);
            MutableByte tmp1 = new MutableByte();

            BuildHeader(tmp1, SnmpConstants.SMI_SEQUENCE, tmp.Length);
            tmp1.Append(tmp);

            BuildHeader(buffer, OCTETSTRING, tmp1.Length);

            buffer.Append(tmp1);
        }
Exemplo n.º 8
0
        /// <summary>Encode SNMP version 3 packet</summary>
        /// <param name="authKey">Authentication key (not password)</param>
        /// <param name="privKey">Privacy key (not password)</param>
        /// <remarks>
        /// Before encoding the packet into a byte array you need to ensure all required information is
        /// set. Examples of required information is request type, Vbs (Oid + values pairs), USM settings including
        /// SecretName, authentication method and secret (if needed), privacy method and secret (if needed), etc.
        /// </remarks>
        /// <returns>Byte array BER encoded SNMP packet.</returns>
        public byte[] Encode(byte[] authKey, byte[] privKey)
        {
            MutableByte buffer = new MutableByte();

            // encode the global message data sequence header information
            MutableByte globalMessageData = new MutableByte();

            // if message id is 0 then generate a new, random message id
            if (messageId.Value == 0)
            {
                Random rand = new Random();
                messageId.Value = rand.Next(1, int.MaxValue);
            }

            // encode message id
            messageId.Encode(globalMessageData);

            // encode max message size
            maxMessageSize.Encode(globalMessageData);

            // message flags
            messageFlags.Encode(globalMessageData);

            // security model code
            securityModel.Value = userSecurityModel.Type;
            securityModel.Encode(globalMessageData);

            // add global message data to the main buffer
            // encode sequence header and add data
            AsnType.BuildHeader(buffer, SnmpConstants.SmiSequence, globalMessageData.Length);
            buffer.Append(globalMessageData);

            MutableByte packetHeader = new MutableByte(buffer);

            // before going down this road, check if this is a discovery packet
            OctetString savedUserName  = new OctetString();
            bool        privacy        = messageFlags.Privacy;
            bool        authentication = messageFlags.Authentication;
            bool        reportable     = messageFlags.Reportable;

            if (userSecurityModel.EngineId.Length <= 0)
            {
                // save USM settings prior to encoding a Discovery packet
                savedUserName.Set(userSecurityModel.SecurityName);
                userSecurityModel.SecurityName.Reset(); // delete security name for discovery packets
                messageFlags.Authentication = false;
                messageFlags.Privacy        = false;
                messageFlags.Reportable     = true;
            }

            userSecurityModel.Encode(buffer);

            if (userSecurityModel.EngineId.Length <= 0)
            {
                // restore saved USM values
                userSecurityModel.SecurityName.Set(savedUserName);
                messageFlags.Authentication = authentication;
                messageFlags.Privacy        = privacy;
                messageFlags.Reportable     = reportable;
            }

            // Check if privacy encryption is required
            MutableByte encodedPdu = new MutableByte();

            if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported.");
                }

                // Get BER encoded ScopedPdu
                MutableByte unencryptedPdu = new MutableByte();
                scopedPdu.Encode(unencryptedPdu);

                // we have to expand the key
                IAuthenticationDigest auth = Authentication.GetInstance(userSecurityModel.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.EErrorCode.UnsupportedNoAuthPriv, "Invalid authentication protocol. noAuthPriv mode not supported.");
                }

                byte[] encryptedBuffer = privacyProtocol.Encrypt(unencryptedPdu, 0, unencryptedPdu.Length, privKey, userSecurityModel.EngineBoots, userSecurityModel.EngineTime, out byte[] privacyParameters, auth);

                userSecurityModel.PrivacyParameters.Set(privacyParameters);

                OctetString encryptedOctetString = new OctetString(encryptedBuffer);
                encryptedOctetString.Encode(encodedPdu);

                // now redo packet encoding
                buffer.Reset();
                buffer.Set(packetHeader);
                userSecurityModel.Encode(buffer);

                int preEncodedLength = encodedPdu.Length;
                buffer.Append(encodedPdu);

                if (maxMessageSize.Value != 0)
                {
                    // verify compliance with maximum message size
                    if ((encodedPdu.Length - preEncodedLength) > maxMessageSize)
                    {
                        throw new SnmpException(SnmpException.EErrorCode.MaximumMessageSizeExceeded, "ScopedPdu exceeds maximum message size.");
                    }
                }
            }
            else
            {
                scopedPdu.Encode(encodedPdu);
                buffer.Append(encodedPdu);
            }

            Encode(buffer);

            if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0)
            {
                userSecurityModel.Authenticate(authKey, ref buffer);

                // Now re-encode the packet with the authentication information
                userSecurityModel.Encode(packetHeader);
                packetHeader.Append(encodedPdu);

                Encode(packetHeader);
                buffer = packetHeader;
            }

            return(buffer);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will
        /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call.
        /// </summary>
        /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param>
        /// <param name="length">Buffer length</param>
        /// <param name="authKey">Authentication key (not password)</param>
        /// <param name="privKey">Privacy key (not password)</param>
        /// <returns>The length of the decoded segment</returns>
        public int Decode(byte[] berBuffer, int length, byte[] authKey, byte[] privKey)
        {
            MutableByte buffer = new MutableByte(berBuffer, length);

            int offset = 0;

            // let base class parse first sequence and SNMP version number
            offset = base.Decode(buffer, length);

            // check for correct SNMP protocol version
            if (protocolVersion != (int)ESnmpVersion.Ver3)
            {
                throw new SnmpInvalidVersionException("Expecting SNMP version 3.");
            }

            // now grab the global message data sequence header information
            byte asnType = AsnType.ParseHeader(buffer, ref offset, out int len);

            if (asnType != SnmpConstants.SmiSequence)
            {
                throw new SnmpDecodingException("Invalid sequence type in global message data sequence.");
            }

            // check that packet size can accommodate the length specified in the header
            if (len > (buffer.Length - offset))
            {
                throw new OverflowException("Packet is too small to contain the data described in the header.");
            }

            // retrieve message id
            offset = messageId.Decode(buffer, offset);

            // max message size
            offset = maxMessageSize.Decode(buffer, offset);

            // message flags
            offset = messageFlags.Decode(buffer, offset);

            // verify that a valid authentication/privacy configuration is present in the packet
            if (messageFlags.Authentication == false && messageFlags.Privacy == true)
            {
                throw new SnmpException(SnmpException.EErrorCode.UnsupportedNoAuthPriv, "SNMP version 3 noAuthPriv security combination is not supported.");
            }

            // security model code
            offset = securityModel.Decode(buffer, offset);

            // we only support USM. code = 0x03
            if (securityModel.Value != userSecurityModel.Type)
            {
                throw new SnmpException(SnmpException.EErrorCode.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model.");
            }

            // parse user security model
            offset = userSecurityModel.Decode(buffer, offset);

            // Authenticate message if authentication flag is set and packet is not a discovery packet
            if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0)
            {
                // Authenticate packet
                if (userSecurityModel.AuthenticationParameters.Length != 12)
                {
                    throw new SnmpAuthenticationException("Invalid authentication parameter field length.");
                }
                if (!userSecurityModel.IsAuthentic(authKey, buffer))
                {
                    throw new SnmpAuthenticationException("Authentication of the incoming packet failed.");
                }
            }

            // Decode ScopedPdu if it is privacy protected and packet is not a discovery packet
            if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy);

                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported.");
                }

                if (userSecurityModel.PrivacyParameters.Length != privacyProtocol.PrivacyParametersLength)
                {
                    throw new SnmpException(SnmpException.EErrorCode.InvalidPrivacyParameterLength, "Invalid privacy parameters field length.");
                }

                // Initialize a temporary OctetString class to hold encrypted ScopedPdu
                OctetString encryptedScopedPdu = new OctetString();
                offset = encryptedScopedPdu.Decode(buffer, offset);

                // decode encrypted packet
                byte[] decryptedScopedPdu = privacyProtocol.Decrypt(encryptedScopedPdu, 0, encryptedScopedPdu.Length, privKey, userSecurityModel.EngineBoots, userSecurityModel.EngineTime, userSecurityModel.PrivacyParameters);
                int    tempOffset         = 0;
                offset = scopedPdu.Decode(decryptedScopedPdu, tempOffset);
            }
            else
            {
                offset = scopedPdu.Decode(buffer, offset);
            }

            return(offset);
        }
        /// <summary>
        /// Encode SNMP version 3 packet
        /// </summary>
        /// <remarks>
        /// Before encoding the packet into a byte array you need to ensure all required information is
        /// set. Examples of required information is request type, Vbs (Oid + values pairs), USM settings including
        /// SecretName, authentication method and secret (if needed), privacy method and secret (if needed), etc.
        /// </remarks>
        /// <returns>Byte array BER encoded SNMP packet.</returns>
        public override byte[] encode()
        {
            MutableByte buffer = new MutableByte();
            // encode the global message data sequence header information

            MutableByte globalMessageData = new MutableByte();

            // if message id is 0 then generate a new, random message id
            if (_messageId.Value == 0)
            {
                Random rand = new Random();
                _messageId.Value = rand.Next(1, Int32.MaxValue);
            }

            // encode message id
            _messageId.encode(globalMessageData);

            // encode max message size
            _maxMessageSize.encode(globalMessageData);

            // message flags
            _msgFlags.encode(globalMessageData);

            // security model code
            _securityModel.Value = _userSecurityModel.Type;
            _securityModel.encode(globalMessageData);

            // add global message data to the main buffer
            // encode sequence header and add data
            AsnType.BuildHeader(buffer, SnmpConstants.SMI_SEQUENCE, globalMessageData.Length);
            buffer.Append(globalMessageData);

            MutableByte packetHeader = new MutableByte(buffer);

            // before going down this road, check if this is a discovery packet
            OctetString savedUserName  = new OctetString();
            bool        privacy        = _msgFlags.Privacy;
            bool        authentication = _msgFlags.Authentication;
            bool        reportable     = _msgFlags.Reportable;

            if (_userSecurityModel.EngineId.Length <= 0)
            {
                // save USM settings prior to encoding a Discovery packet
                savedUserName.Set(_userSecurityModel.SecurityName);
                _userSecurityModel.SecurityName.Reset();                 // delete security name for discovery packets
                _msgFlags.Authentication = false;
                _msgFlags.Privacy        = false;
                _msgFlags.Reportable     = true;
            }

            _userSecurityModel.encode(buffer);

            if (_userSecurityModel.EngineId.Length <= 0)
            {
                // restore saved USM values
                _userSecurityModel.SecurityName.Set(savedUserName);
                _msgFlags.Authentication = authentication;
                _msgFlags.Privacy        = privacy;
                _msgFlags.Reportable     = reportable;
            }

            // Check if privacy encryption is required
            MutableByte encodedPdu = new MutableByte();

            if (_msgFlags.Privacy && _userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(_userSecurityModel.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported.");
                }

                // Get BER encoded ScopedPdu
                MutableByte unencryptedPdu = new MutableByte();
                _scopedPdu.encode(unencryptedPdu);

                byte[] privacyParameters = null;
                // we have to expand the key
                IAuthenticationDigest auth = Authentication.GetInstance(_userSecurityModel.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "Invalid authentication protocol. noAuthPriv mode not supported.");
                }

                byte[] pkey = privacyProtocol.PasswordToKey(_userSecurityModel.PrivacySecret, _userSecurityModel.EngineId, auth);

                byte[] encryptedBuffer = privacyProtocol.Encrypt(unencryptedPdu, 0, unencryptedPdu.Length, pkey, _userSecurityModel.EngineBoots, _userSecurityModel.EngineTime, out privacyParameters, auth);

                _userSecurityModel.PrivacyParameters.Set(privacyParameters);
                OctetString encryptedOctetString = new OctetString(encryptedBuffer);
                encryptedOctetString.encode(encodedPdu);
                // now redo packet encoding
                buffer.Reset();
                buffer.Set(packetHeader);
                _userSecurityModel.encode(buffer);
                int preEncodedLength = encodedPdu.Length;
                buffer.Append(encodedPdu);
                if (_maxMessageSize.Value != 0)
                {
                    // verify compliance with maximum message size
                    if ((encodedPdu.Length - preEncodedLength) > _maxMessageSize)
                    {
                        throw new SnmpException(SnmpException.MaximumMessageSizeExceeded, "ScopedPdu exceeds maximum message size.");
                    }
                }
            }
            else
            {
                _scopedPdu.encode(encodedPdu);
                buffer.Append(encodedPdu);
            }

            int preVersionLength = buffer.Length;

            base.encode(buffer);

            int versionHeaderLength = buffer.Length - preVersionLength;

            if (_msgFlags.Authentication && _userSecurityModel.EngineId.Length > 0)
            {
                _userSecurityModel.Authenticate(ref buffer);
                // Now re-encode the packet with the authentication information
                _userSecurityModel.encode(packetHeader);
                packetHeader.Append(encodedPdu);
                base.encode(packetHeader);
                buffer = packetHeader;
            }
            return(buffer);
        }
        /// <summary>
        /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will
        /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call.
        /// </summary>
        /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param>
        /// <param name="length">Buffer length</param>
        public override int decode(byte[] berBuffer, int length)
        {
            MutableByte buffer = new MutableByte(berBuffer, length);

            int offset = 0;

            // let base class parse first sequence and SNMP version number
            offset = base.decode(buffer, length);

            // check for correct SNMP protocol version
            if (_protocolVersion != (int)SnmpVersion.Ver3)
            {
                throw new SnmpInvalidVersionException("Expecting SNMP version 3.");
            }

            // now grab the global message data sequence header information
            int  len     = 0;
            byte asnType = AsnType.ParseHeader(buffer, ref offset, out len);

            // check that packet size can accommodate the length specified in the header
            if (len > (buffer.Length - offset))
            {
                throw new OverflowException("Packet is too small to contain the data described in the header.");
            }

            // retrieve message id
            offset = _messageId.decode(buffer, offset);

            // max message size
            offset = _maxMessageSize.decode(buffer, offset);

            // message flags
            offset = _msgFlags.decode(buffer, offset);

            // verify that a valid authentication/privacy configuration is present in the packet
            if (_msgFlags.Authentication == false && _msgFlags.Privacy == true)
            {
                throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "SNMP version 3 noAuthPriv security combination is not supported.");
            }

            // security model code
            offset = _securityModel.decode(buffer, offset);

            // we only support USM. code = 0x03
            if (_securityModel.Value != _userSecurityModel.Type)
            {
                throw new SnmpException(SnmpException.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model.");
            }

            // parse user security model
            offset = _userSecurityModel.decode(buffer, offset);

            // Authenticate message if authentication flag is set and packet is not a discovery packet
            if (_msgFlags.Authentication && _userSecurityModel.EngineId.Length > 0)
            {
                // Authenticate packet
                if (_userSecurityModel.AuthenticationParameters.Length != 12)
                {
                    throw new SnmpAuthenticationException("Invalid authentication parameter field length.");
                }
                if (!_userSecurityModel.IsAuthentic(buffer))
                {
                    throw new SnmpAuthenticationException("Authentication of the incoming packet failed.");
                }
            }

            // Decode ScopedPdu if it is privacy protected and packet is not a discovery packet
            if (_msgFlags.Privacy && _userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(_userSecurityModel.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported.");
                }
                if (_userSecurityModel.PrivacyParameters.Length != privacyProtocol.PrivacyParametersLength)
                {
                    throw new SnmpException(SnmpException.InvalidPrivacyParameterLength, "Invalid privacy parameters field length.");
                }

                // build privacy key
                IAuthenticationDigest auth = Authentication.GetInstance(_userSecurityModel.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "Invalid authentication protocol.");
                }

                byte[] pkey = auth.PasswordToKey(_userSecurityModel.PrivacySecret, _userSecurityModel.EngineId);

                // extend key if it is too short
                if (pkey.Length < privacyProtocol.MinimumKeyLength)
                {
                    pkey = privacyProtocol.ExtendShortKey(pkey, new OctetString(_userSecurityModel.PrivacySecret), _userSecurityModel.EngineId, auth);
                }

                // Initialize a temporary OctetString class to hold encrypted ScopedPdu
                OctetString encryptedScopedPdu = new OctetString();
                offset = encryptedScopedPdu.decode(buffer, offset);

                // decode encrypted packet
                byte[] decryptedScopedPdu = privacyProtocol.Decrypt(encryptedScopedPdu, 0, encryptedScopedPdu.Length, pkey, _userSecurityModel.EngineBoots, _userSecurityModel.EngineTime, _userSecurityModel.PrivacyParameters);
                int    tempOffset         = 0;
                offset = _scopedPdu.decode(decryptedScopedPdu, tempOffset);
            }
            else
            {
                offset = _scopedPdu.decode(buffer, offset);
            }
            return(offset);
        }