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)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);
if (asnType != SnmpConstants.SMI_SEQUENCE)
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 = _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(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 (_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.");
// 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;
}