/// <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);
        }
Exemple #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);
        }
        /// <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));
        }
        /// <summary>
        /// Authenticate SNMP version 3 message.
        ///
        /// Before calling this member, entire SNMP version 3 packet needs to be encoded. After authentication
        /// process is completed, authenticationParameters value in the USM header is updated and SNMPv3 packet
        /// needs to be re-encoded to include it in the BER encoded stream prior to transmission.
        /// </summary>
        /// <param name="authKey">Authentication key (not password)</param>
        /// <param name="wholePacket">SNMP version 3 BER encoded packet.</param>
        public void Authenticate(byte[] authKey, ref MutableByte wholePacket)
        {
            IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(_authentication);

            byte[] authParam = authProto.authenticate(authKey, wholePacket);
            _authenticationParameters = new OctetString(authParam);
        }
        /// <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);
                        }
                    }
                }
            }
        }
Exemple #6
0
        /// <summary>
        ///     Some protocols support a method to extend the encryption or decryption key when supplied key
        ///     is too short.
        /// </summary>
        /// <param name="shortKey">Key that needs to be extended</param>
        /// <param name="password">Privacy password as configured on the SNMP agent.</param>
        /// <param name="engineID">Authoritative engine id. Value is retrieved as part of SNMP v3 discovery procedure</param>
        /// <param name="authProtocol">Authentication protocol class instance cast as <see cref="IAuthenticationDigest" /></param>
        /// <returns>Extended key value</returns>
        public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID,
                                     IAuthenticationDigest authProtocol)
        {
            var extKey     = new byte[MinimumKeyLength];
            var lastKeyBuf = new byte[shortKey.Length];

            Array.Copy(shortKey, lastKeyBuf, shortKey.Length);
            var keyLen = shortKey.Length > MinimumKeyLength ? MinimumKeyLength : shortKey.Length;

            Array.Copy(shortKey, extKey, keyLen);
            while (keyLen < MinimumKeyLength)
            {
                var tmpBuf = authProtocol.PasswordToKey(lastKeyBuf, engineID);
                if (tmpBuf == null)
                {
                    return(null);
                }
                if (tmpBuf.Length <= MinimumKeyLength - keyLen)
                {
                    Array.Copy(tmpBuf, 0, extKey, keyLen, tmpBuf.Length);
                    keyLen += tmpBuf.Length;
                }
                else
                {
                    Array.Copy(tmpBuf, 0, extKey, keyLen, MinimumKeyLength - keyLen);
                    keyLen += MinimumKeyLength - keyLen;
                }
                lastKeyBuf = new byte[tmpBuf.Length];
                Array.Copy(tmpBuf, lastKeyBuf, tmpBuf.Length);
            }
            return(extKey);
        }
Exemple #7
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);
                        }
                    }
                }
            }
        }
Exemple #8
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));
        }
 /// <summary>
 /// Authenticate SNMP version 3 message.
 ///
 /// Before calling this member, entire SNMP version 3 packet needs to be encoded. After authentication
 /// process is completed, authenticationParameters value in the USM header is updated and SNMPv3 packet
 /// needs to be re-encoded to include it in the BER encoded stream prior to transmission.
 /// </summary>
 /// <param name="wholePacket">SNMP version 3 BER encoded packet.</param>
 public void Authenticate(ref MutableByte wholePacket)
 {
     if (_authentication != AuthenticationDigests.None)
     {
         IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(_authentication);
         byte[] authParam = authProto.authenticate(AuthenticationSecret, EngineId.ToArray(), wholePacket);
         _authenticationParameters = new OctetString(authParam);
     }
 }
        /// <summary>
        ///     Encrypt ScopedPdu using DES encryption protocol
        /// </summary>
        /// <param name="unencryptedData">Unencrypted ScopedPdu byte array</param>
        /// <param name="offset">Offset to start encryption</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key. Key has to be at least 32 bytes is length</param>
        /// <param name="engineBoots">Authoritative engine boots value</param>
        /// <param name="engineTime">Authoritative engine time value. Not used for DES</param>
        /// <param name="privacyParameters">
        ///     Privacy parameters out buffer. This field will be filled in with information
        ///     required to decrypt the information. Output length of this field is 8 bytes and space has to be reserved
        ///     in the USM header to store this information
        /// </param>
        /// <param name="authDigest">Authentication digest class reference. Not used by DES and can be null.</param>
        /// <returns>Encrypted byte array</returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     Thrown when encryption key is null or length of the encryption key is too
        ///     short.
        /// </exception>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots,
                              int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            if (key == null || key.Length < MinimumKeyLength)
            {
                throw new ArgumentOutOfRangeException("encryptionKey",
                                                      "Encryption key length has to 32 bytes or more.");
            }

            privacyParameters = GetSalt(engineBoots);
            var iv = GetIV(key, privacyParameters);

            // DES uses 8 byte keys but we need 16 to encrypt ScopedPdu. Get first 8 bytes and use them as encryption key
            var outKey = GetKey(key);


            var div = (int)Math.Floor(length / 8.0);

            if (length % 8 != 0)
            {
                div += 1;
            }
            var newLength = div * 8;
            var result    = new byte[newLength];
            var buffer    = new byte[newLength];

            var inbuffer   = new byte[8];
            var cipherText = iv;
            var posIn      = 0;
            var posResult  = 0;

            Buffer.BlockCopy(unencryptedData, offset, buffer, 0, length);

            DES des = new DESCryptoServiceProvider();

            des.Mode    = CipherMode.ECB;
            des.Padding = PaddingMode.None;

            var transform = des.CreateEncryptor(outKey, null);

            for (var b = 0; b < div; b++)
            {
                for (var i = 0; i < 8; i++)
                {
                    inbuffer[i] = (byte)(buffer[posIn] ^ cipherText[i]);
                    posIn++;
                }
                transform.TransformBlock(inbuffer, 0, inbuffer.Length, cipherText, 0);
                Buffer.BlockCopy(cipherText, 0, result, posResult, cipherText.Length);
                posResult += cipherText.Length;
            }

            des.Clear();

            return(result);
        }
 /// <summary>
 /// Convert privacy password into encryption key using packet authentication hash.
 /// </summary>
 /// <param name="secret">Privacy user secret</param>
 /// <param name="engineId">Authoritative engine id of the snmp agent</param>
 /// <param name="authProtocol">Authentication protocol</param>
 /// <returns>Encryption key</returns>
 /// <exception cref="SnmpPrivacyException">Thrown when key size is shorter then MinimumKeyLength</exception>
 public byte[] PasswordToKey(byte[] secret, byte[] engineId, IAuthenticationDigest authProtocol)
 {
     // RFC 3414 - password length is minimum of 8 bytes long
     if (secret == null || secret.Length < 8)
     {
         throw new SnmpPrivacyException("Invalid privacy secret length.");
     }
     byte[] encryptionKey = authProtocol.PasswordToKey(secret, engineId);
     return(encryptionKey);
 }
 /// <summary>
 /// Authenticate incoming packet
 /// </summary>
 /// <param name="authKey">Authentication key (not password)</param>
 /// <param name="wholePacket">Received BER encoded SNMP version 3 packet</param>
 /// <returns>True if packet is successfully authenticated, otherwise false.</returns>
 public bool IsAuthentic(byte[] authKey, MutableByte wholePacket)
 {
     if (_authentication != AuthenticationDigests.None)
     {
         IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(_authentication);
         if (authProto != null)
         {
             return(authProto.authenticateIncomingMsg(authKey, _authenticationParameters, wholePacket));
         }
     }
     return(false); // Nothing to authenticate
 }
 /// <summary>
 /// Convert privacy password into encryption key using packet authentication hash.
 /// </summary>
 /// <param name="secret">Privacy user secret</param>
 /// <param name="engineId">Authoritative engine id of the snmp agent</param>
 /// <param name="authProtocol">Authentication protocol</param>
 /// <returns>Encryption key</returns>
 /// <exception cref="SnmpPrivacyException">Thrown when key size is shorter then MinimumKeyLength</exception>
 public byte[] PasswordToKey(byte[] secret, byte[] engineId, IAuthenticationDigest authProtocol)
 {
     if (secret == null || secret.Length < 8)
     {
         throw new SnmpPrivacyException("Invalid privacy secret length.");
     }
     byte[] key = authProtocol.PasswordToKey(secret, engineId);
     if (key.Length < MinimumKeyLength)
     {
         key = ExtendShortKey(key, secret, engineId, authProtocol);
     }
     return(key);
 }
Exemple #14
0
        /// <summary>Authenticate incoming packet</summary>
        /// <param name="wholePacket">Received BER encoded SNMP version 3 packet</param>
        /// <returns>True if packet is successfully authenticated, otherwise false.</returns>
        public bool IsAuthentic(MutableByte wholePacket)
        {
            if (authentication != AuthenticationDigests.None)
            {
                IAuthenticationDigest authProto = Security.Authentication.GetInstance(authentication);
                if (authProto != null)
                {
                    return(authProto.AuthenticateIncomingMessage(AuthenticationSecret, engineId, authenticationParameters, wholePacket));
                }
            }

            return(false); // Nothing to authenticate
        }
 /// <summary>
 /// Generate authentication key from authentication password and engine id
 /// </summary>
 /// <returns>Authentication key on success or null on failure</returns>
 public byte[] GenerateAuthenticationKey()
 {
     if (_userSecurityModel.EngineId == null || _userSecurityModel.EngineId.Length <= 0)
         return null;
     if (_userSecurityModel.AuthenticationSecret == null || _userSecurityModel.AuthenticationSecret.Length <= 0)
         return null;
     if (_userSecurityModel.Authentication != AuthenticationDigests.None)
     {
         IAuthenticationDigest authProto = Authentication.GetInstance(_userSecurityModel.Authentication);
         if (authProto != null)
         {
             return authProto.PasswordToKey(_userSecurityModel.AuthenticationSecret, _userSecurityModel.EngineId);
         }
     }
     return null;
 }
Exemple #16
0
        /// <summary>
        ///     Extends the encryption key if key size returned by PasswordToKey is less then minimum
        ///     required by the encryption protocol.
        /// </summary>
        /// <remarks>
        ///     There is no need to call this method in a user application becuase PasswordToKey() method will
        ///     make the call if password it generates is too short.
        /// </remarks>
        /// <param name="shortKey">Encryption key</param>
        /// <param name="password">Privacy password</param>
        /// <param name="engineID">Authoritative engine id</param>
        /// <param name="authProtocol">Authentication protocol class instance</param>
        /// <returns>unaltered shortKey value</returns>
        public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID,
                                     IAuthenticationDigest authProtocol)
        {
            var length      = shortKey.Length;
            var extendedKey = new byte[MinimumKeyLength];

            Buffer.BlockCopy(shortKey, 0, extendedKey, 0, shortKey.Length);

            while (length < MinimumKeyLength)
            {
                var key =
                    authProtocol.PasswordToKey(shortKey,
                                               engineID);
                var copyBytes = Math.Min(MaximumKeyLength - length,
                                         authProtocol.DigestLength);
                Buffer.BlockCopy(key, 0, extendedKey, length, copyBytes);
                length += copyBytes;
            }
            return(extendedKey);
        }
        /// <summary>
        /// Generate authentication key from authentication password and engine id
        /// </summary>
        /// <returns>Authentication key on success or null on failure</returns>
        public byte[] GenerateAuthenticationKey()
        {
            if (USM.EngineId == null || USM.EngineId.Length <= 0)
            {
                return(null);
            }

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

            if (USM.Authentication != AuthenticationDigests.None)
            {
                IAuthenticationDigest authProto = SnmpSharpNet.Authentication.GetInstance(USM.Authentication);
                if (authProto != null)
                {
                    return(authProto.PasswordToKey(USM.AuthenticationSecret, USM.EngineId));
                }
            }
            return(null);
        }
Exemple #18
0
        /// <summary>
        ///     Encrypt ScopedPdu using TripleDES encryption protocol
        /// </summary>
        /// <param name="unencryptedData">Unencrypted ScopedPdu byte array</param>
        /// <param name="offset">Offset to start encryption</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key. Key has to be at least 32 bytes is length</param>
        /// <param name="engineBoots">Authoritative engine boots value</param>
        /// <param name="engineTime">Authoritative engine time value.</param>
        /// <param name="privacyParameters">
        ///     Privacy parameters out buffer. This field will be filled in with information
        ///     required to decrypt the information. Output length of this field is 8 bytes and space has to be reserved
        ///     in the USM header to store this information
        /// </param>
        /// <param name="authDigest">Authentication digest class reference. Used by TripleDES.</param>
        /// <returns>Encrypted byte array</returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     Thrown when encryption key is null or length of the encryption key is too
        ///     short.
        /// </exception>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots,
                              int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            privacyParameters = GetSalt(engineBoots);
            var privParamHash = authDigest.ComputeHash(privacyParameters, 0, privacyParameters.Length);

            privacyParameters = new byte[8];
            Buffer.BlockCopy(privParamHash, 0, privacyParameters, 0, 8);
            var iv = GetIV(key, privacyParameters);

            byte[] encryptedData = null;
            try
            {
                TripleDES tdes = new TripleDESCryptoServiceProvider();
                tdes.Mode    = CipherMode.CBC;
                tdes.Padding = PaddingMode.None;
                // normalize key - generated key is 32 bytes long, we need 24 bytes to encrypt
                var normKey = new byte[24];
                Buffer.BlockCopy(key, 0, normKey, 0, normKey.Length);
                var transform = tdes.CreateEncryptor(normKey, iv);
                if (length % 8 == 0)
                {
                    encryptedData = transform.TransformFinalBlock(unencryptedData, offset, length);
                }
                else
                {
                    var tmpbuffer = new byte[8 * (length / 8 + 1)];
                    Buffer.BlockCopy(unencryptedData, offset, tmpbuffer, 0, length);
                    encryptedData = transform.TransformFinalBlock(tmpbuffer, 0, tmpbuffer.Length);
                }
            }
            catch (Exception ex)
            {
                throw new SnmpPrivacyException(ex,
                                               "Exception was thrown while TripleDES privacy protocol was encrypting data\r\n" + ex);
            }
            return(encryptedData);
        }
Exemple #19
0
 /// <summary>
 /// Convert privacy password into encryption key using packet authentication hash.
 /// </summary>
 /// <param name="secret">Privacy user secret/password</param>
 /// <param name="engineId">Authoritative engine id of the SNMP agent</param>
 /// <param name="authProtocol">Authentication protocol</param>
 /// <returns>Encryption key</returns>
 /// <exception cref="SnmpPrivacyException">Thrown when user secret/password is shorter then MinimumKeyLength</exception>
 public byte[] PasswordToKey(byte[] secret, byte[] engineId, IAuthenticationDigest authProtocol)
 {
     // RFC 3414 - password length is minimum of 8 bytes long
     if (secret == null || secret.Length < 8)
         throw new SnmpPrivacyException("Invalid privacy secret length.");
     byte[] encryptionKey = authProtocol.PasswordToKey(secret, engineId);
     if( encryptionKey.Length < MinimumKeyLength )
         encryptionKey = ExtendShortKey(encryptionKey, secret, engineId, authProtocol);
     return encryptionKey;
 }
Exemple #20
0
        /// <summary>
        /// Extends the encryption key if key size returned by PasswordToKey is less then minimum
        /// required by the encryption protocol.
        /// </summary>
        /// <remarks>
        /// There is no need to call this method in a user application becuase PasswordToKey() method will
        /// make the call if password it generates is too short.
        /// </remarks>
        /// <param name="shortKey">Encryption key</param>
        /// <param name="password">Privacy password</param>
        /// <param name="engineID">Authoritative engine id</param>
        /// <param name="authProtocol">Authentication protocol class instance</param>
        /// <returns>unaltered shortKey value</returns>
        public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID, IAuthenticationDigest authProtocol)
        {
            int length = shortKey.Length;
            byte[] extendedKey = new byte[MinimumKeyLength];
            Buffer.BlockCopy(shortKey, 0, extendedKey, 0, shortKey.Length);

            while (length < MinimumKeyLength)
            {
                byte[] key =
                    authProtocol.PasswordToKey(shortKey,
                                               engineID);
                int copyBytes = Math.Min(MaximumKeyLength - length,
                                         authProtocol.DigestLength);
                Buffer.BlockCopy(key, 0, extendedKey, length, copyBytes);
                length += copyBytes;
            }
            return extendedKey;
        }
Exemple #21
0
        /// <summary>
        /// Encrypt ScopedPdu using TripleDES encryption protocol
        /// </summary>
        /// <param name="unencryptedData">Unencrypted ScopedPdu byte array</param>
        /// <param name="offset">Offset to start encryption</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key. Key has to be at least 32 bytes is length</param>
        /// <param name="engineBoots">Authoritative engine boots value</param>
        /// <param name="engineTime">Authoritative engine time value.</param>
        /// <param name="privacyParameters">Privacy parameters out buffer. This field will be filled in with information
        /// required to decrypt the information. Output length of this field is 8 bytes and space has to be reserved
        /// in the USM header to store this information</param>
        /// <param name="authDigest">Authentication digest class reference. Used by TripleDES.</param>
        /// <returns>Encrypted byte array</returns>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when encryption key is null or length of the encryption key is too short.</exception>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots, int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            privacyParameters = GetSalt(engineBoots);
            byte[] privParamHash = authDigest.ComputeHash(privacyParameters, 0, privacyParameters.Length);
            privacyParameters = new byte[8];
            Buffer.BlockCopy(privParamHash, 0, privacyParameters, 0, 8);
            byte[] iv = GetIV(key, privacyParameters);

            byte[] encryptedData = null;
            try
            {
                TripleDES tdes = new TripleDESCryptoServiceProvider();
                tdes.Mode = CipherMode.CBC;
                tdes.Padding = PaddingMode.None;
                // normalize key - generated key is 32 bytes long, we need 24 bytes to encrypt
                byte[] normKey = new byte[24];
                Buffer.BlockCopy(key, 0, normKey, 0, normKey.Length);
                ICryptoTransform transform = tdes.CreateEncryptor(normKey, iv);
                if ((length % 8) == 0)
                {
                    encryptedData = transform.TransformFinalBlock(unencryptedData, offset, length);
                }
                else
                {
                    byte[] tmpbuffer = new byte[8 * ((length / 8) + 1)];
                    Buffer.BlockCopy(unencryptedData, offset, tmpbuffer, 0, length);
                    encryptedData = transform.TransformFinalBlock(tmpbuffer, 0, tmpbuffer.Length);
                }
            }
            catch (Exception ex)
            {
                throw new SnmpPrivacyException(ex, "Exception was thrown while TripleDES privacy protocol was encrypting data\r\n" + ex.ToString());
            }
            return encryptedData;
        }
Exemple #22
0
 /// <summary>
 /// Convert privacy password into encryption key using packet authentication hash.
 /// </summary>
 /// <param name="secret">Privacy user secret</param>
 /// <param name="engineId">Authoritative engine id of the snmp agent</param>
 /// <param name="authProtocol">Authentication protocol</param>
 /// <returns>Encryption key</returns>
 /// <exception cref="SnmpPrivacyException">Thrown when key size is shorter then MinimumKeyLength</exception>
 public byte[] PasswordToKey(byte[] secret, byte[] engineId, IAuthenticationDigest authProtocol)
 {
     if (secret == null || secret.Length < 8)
         throw new SnmpPrivacyException("Invalid privacy secret length.");
     byte[] key = authProtocol.PasswordToKey(secret, engineId);
     if (key.Length < MinimumKeyLength)
     {
         key = ExtendShortKey(key, secret, engineId, authProtocol);
     }
     return key;
 }
        /// <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);
        }
        /// <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>
        /// Some protocols support a method to extend the encryption or decryption key when supplied key
        /// is too short.
        /// </summary>
        /// <param name="shortKey">Key that needs to be extended</param>
        /// <param name="password">Privacy password as configured on the SNMP agent.</param>
        /// <param name="engineID">Authoritative engine id. Value is retrieved as part of SNMP v3 discovery procedure</param>
        /// <param name="authProtocol">Authentication protocol class instance cast as <see cref="IAuthenticationDigest"/></param>
        /// <returns>Extended key value</returns>
        public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID, IAuthenticationDigest authProtocol)
        {
            byte[] extKey = new byte[MinimumKeyLength];
            int    length = shortKey.Length;

            for (int i = 0; i < length; i++)
            {
                extKey[i] = shortKey[i];
            }

            while (length < extKey.Length)
            {
                // fix the key hashing. Only hash upto the length of the *shortKey*
                byte[] hash = authProtocol.ComputeHash(extKey, 0, length);

                if (hash == null)
                {
                    return(null);
                }
                int bytesToCopy = extKey.Length - length;
                if (bytesToCopy > authProtocol.DigestLength)
                {
                    bytesToCopy = authProtocol.DigestLength;
                }
                Buffer.BlockCopy(hash, 0, extKey, length, bytesToCopy);

                length += bytesToCopy;
            }
            return(extKey);
        }
Exemple #26
0
        /// <summary>
        /// Encrypt <see cref="ScopedPdu"/> data BER encoded in a byte array.
        /// </summary>
        /// <param name="unencryptedData">BER encoded <see cref="ScopedPdu"/> byte array that needs to be encrypted</param>
        /// <param name="offset">Offset within the BER encoded byte array to start encryption operation from.</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key</param>
        /// <param name="engineBoots">Authoritative engine boots value. Retrieved as part of SNMP v3 discovery process.</param>
        /// <param name="engineTime">Authoritative engine time value. Retrieved as part of SNMP v3 discovery process.</param>
        /// <param name="privacyParameters">Byte array that will receive privacy parameters information that is the result of the
        /// encryption procedure.</param>
        /// <param name="authDigest">Authentication digest reference. Not used by AES protocol and can be null</param>
        /// <returns>Byte array containing encrypted <see cref="ScopedPdu"/> BER encoded data</returns>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots, int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            // check the key before doing anything else
            if (key == null || key.Length < _keyBytes)
                throw new ArgumentOutOfRangeException("encryptionKey", "Invalid key length");

            byte[] iv = new byte[16];
            Int64 salt = NextSalt();
            privacyParameters = new byte[PrivacyParametersLength];
            byte[] bootsBytes = BitConverter.GetBytes(engineBoots);
            iv[0] = bootsBytes[3];
            iv[1] = bootsBytes[2];
            iv[2] = bootsBytes[1];
            iv[3] = bootsBytes[0];
            byte[] timeBytes = BitConverter.GetBytes(engineTime);
            iv[4] = timeBytes[3];
            iv[5] = timeBytes[2];
            iv[6] = timeBytes[1];
            iv[7] = timeBytes[0];

            // Set privacy parameters to the local 64 bit salt value
            byte[] saltBytes = BitConverter.GetBytes(salt);
            privacyParameters[0] = saltBytes[7];
            privacyParameters[1] = saltBytes[6];
            privacyParameters[2] = saltBytes[5];
            privacyParameters[3] = saltBytes[4];
            privacyParameters[4] = saltBytes[3];
            privacyParameters[5] = saltBytes[2];
            privacyParameters[6] = saltBytes[1];
            privacyParameters[7] = saltBytes[0];

            // Copy salt value to the iv array
            Buffer.BlockCopy(privacyParameters, 0, iv, 8, 8);

            Rijndael rm = new RijndaelManaged();
            rm.KeySize = _keyBytes * 8;
            rm.FeedbackSize = 128;
            rm.BlockSize = 128;
            // we have to use Zeros padding otherwise we get encrypt buffer size exception
            rm.Padding = PaddingMode.Zeros;
            rm.Mode = CipherMode.CFB;
            // make sure we have the right key length
            byte[] pkey = new byte[MinimumKeyLength];
            Buffer.BlockCopy(key, 0, pkey, 0, MinimumKeyLength);
            rm.Key = pkey;
            rm.IV = iv;
            ICryptoTransform cryptor = rm.CreateEncryptor();
            byte[] encryptedData = cryptor.TransformFinalBlock(unencryptedData, offset, length);
            // check if encrypted data is the same length as source data
            if (encryptedData.Length != unencryptedData.Length)
            {
                // cut out the padding
                byte[] tmp = new byte[unencryptedData.Length];
                Buffer.BlockCopy(encryptedData, 0, tmp, 0, unencryptedData.Length);
                return tmp;
            }
            return encryptedData;
        }
 /// <summary>
 /// Operation not used by DES. Key length has to be 16 bytes of encryption/decryption operation will fail.
 ///
 /// When called, shortKey is returned.
 /// </summary>
 /// <param name="shortKey">Encryption key</param>
 /// <param name="password">Privacy password</param>
 /// <param name="engineID">Authoritative engine id</param>
 /// <param name="authProtocol">Authentication protocol class instance</param>
 /// <returns>unaltered shortKey value</returns>
 public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID, IAuthenticationDigest authProtocol)
 {
     return(shortKey);
 }
Exemple #28
0
 /// <summary>
 /// Operation not used by DES. Key length has to be 16 bytes of encryption/decryption operation will fail.
 /// 
 /// When called, shortKey is returned.
 /// </summary>
 /// <param name="shortKey">Encryption key</param>
 /// <param name="password">Privacy password</param>
 /// <param name="engineID">Authoritative engine id</param>
 /// <param name="authProtocol">Authentication protocol class instance</param>
 /// <returns>unaltered shortKey value</returns>
 public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID, IAuthenticationDigest authProtocol)
 {
     return shortKey;
 }
Exemple #29
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);
        }
Exemple #30
0
        /// <summary>Encrypt <see cref="ScopedPdu"/> data BER encoded in a byte array.</summary>
        /// <param name="unencryptedData">BER encoded <see cref="ScopedPdu"/> byte array that needs to be encrypted</param>
        /// <param name="offset">Offset within the BER encoded byte array to start encryption operation from.</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key</param>
        /// <param name="engineBoots">Authoritative engine boots value. Retrieved as part of SNMP v3 discovery process.</param>
        /// <param name="engineTime">Authoritative engine time value. Retrieved as part of SNMP v3 discovery process.</param>
        /// <param name="privacyParameters">Byte array that will receive privacy parameters information that is the result of the
        /// encryption procedure.</param>
        /// <param name="authDigest">Authentication digest reference. Not used by AES protocol and can be null</param>
        /// <returns>Byte array containing encrypted <see cref="ScopedPdu"/> BER encoded data</returns>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots, int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            // check the key before doing anything else
            if (key == null || key.Length < keyBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(key), "Invalid key length");
            }

            byte[] iv   = new byte[16];
            var    salt = NextSalt();

            privacyParameters = new byte[PrivacyParametersLength];

            byte[] bootsBytes = BitConverter.GetBytes(engineBoots);
            iv[0] = bootsBytes[3];
            iv[1] = bootsBytes[2];
            iv[2] = bootsBytes[1];
            iv[3] = bootsBytes[0];

            byte[] timeBytes = BitConverter.GetBytes(engineTime);
            iv[4] = timeBytes[3];
            iv[5] = timeBytes[2];
            iv[6] = timeBytes[1];
            iv[7] = timeBytes[0];

            // Set privacy parameters to the local 64 bit salt value
            byte[] saltBytes = BitConverter.GetBytes(salt);
            privacyParameters[0] = saltBytes[7];
            privacyParameters[1] = saltBytes[6];
            privacyParameters[2] = saltBytes[5];
            privacyParameters[3] = saltBytes[4];
            privacyParameters[4] = saltBytes[3];
            privacyParameters[5] = saltBytes[2];
            privacyParameters[6] = saltBytes[1];
            privacyParameters[7] = saltBytes[0];

            // Copy salt value to the iv array
            Buffer.BlockCopy(privacyParameters, 0, iv, 8, 8);

            Rijndael rm = new RijndaelManaged
            {
                KeySize      = keyBytes * 8,
                FeedbackSize = 128,
                BlockSize    = 128,

                // we have to use Zeros padding otherwise we get encrypt buffer size exception
                Padding = PaddingMode.Zeros,
                Mode    = CipherMode.CFB,
            };

            // make sure we have the right key length
            byte[] pkey = new byte[MinimumKeyLength];
            Buffer.BlockCopy(key, 0, pkey, 0, MinimumKeyLength);
            rm.Key = pkey;
            rm.IV  = iv;

            ICryptoTransform cryptor = rm.CreateEncryptor();

            byte[] encryptedData = cryptor.TransformFinalBlock(unencryptedData, offset, length);

            // check if encrypted data is the same length as source data
            if (encryptedData.Length != unencryptedData.Length)
            {
                // cut out the padding
                byte[] tmp = new byte[unencryptedData.Length];
                Buffer.BlockCopy(encryptedData, 0, tmp, 0, unencryptedData.Length);

                return(tmp);
            }

            return(encryptedData);
        }
Exemple #31
0
        /// <summary>
        /// Encrypt ScopedPdu using DES encryption protocol
        /// </summary>
        /// <param name="unencryptedData">Unencrypted ScopedPdu byte array</param>
        /// <param name="offset">Offset to start encryption</param>
        /// <param name="length">Length of data to encrypt</param>
        /// <param name="key">Encryption key. Key has to be at least 32 bytes is length</param>
        /// <param name="engineBoots">Authoritative engine boots value</param>
        /// <param name="engineTime">Authoritative engine time value. Not used for DES</param>
        /// <param name="privacyParameters">Privacy parameters out buffer. This field will be filled in with information
        /// required to decrypt the information. Output length of this field is 8 bytes and space has to be reserved
        /// in the USM header to store this information</param>
        /// <param name="authDigest">Authentication digest class reference. Not used by DES and can be null.</param>
        /// <returns>Encrypted byte array</returns>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when encryption key is null or length of the encryption key is too short.</exception>
        public byte[] Encrypt(byte[] unencryptedData, int offset, int length, byte[] key, int engineBoots, int engineTime, out byte[] privacyParameters, IAuthenticationDigest authDigest)
        {
            if (key == null || key.Length < MinimumKeyLength)
                throw new ArgumentOutOfRangeException("encryptionKey", "Encryption key length has to 32 bytes or more.");

            privacyParameters = GetSalt(engineBoots);
            byte[] iv = GetIV(key, privacyParameters);

            // DES uses 8 byte keys but we need 16 to encrypt ScopedPdu. Get first 8 bytes and use them as encryption key
            byte[] outKey = GetKey(key);

            int div = (int)Math.Floor(length / 8.0);
            if ((length % 8) != 0)
                div += 1;
            int newLength = div * 8;
            byte[] result = new byte[newLength];
            byte[] buffer = new byte[newLength];

            byte[] inbuffer = new byte[8];
            byte[] cipherText = iv;
            int posIn = 0;
            int posResult = 0;
            Buffer.BlockCopy(unencryptedData, offset, buffer, 0, length);

            DES des = new DESCryptoServiceProvider();
            des.Mode = CipherMode.ECB;
            des.Padding = PaddingMode.None;

            ICryptoTransform transform = des.CreateEncryptor(outKey, null);
            for (int b = 0; b < div; b++)
            {
                for (int i = 0; i < 8; i++)
                {
                    inbuffer[i] = (byte)(buffer[posIn] ^ cipherText[i]);
                    posIn++;
                }
                transform.TransformBlock(inbuffer, 0, inbuffer.Length, cipherText, 0);
                Buffer.BlockCopy(cipherText, 0, result, posResult, cipherText.Length);
                posResult += cipherText.Length;
            }

            des.Clear();

            return result;
        }
Exemple #32
0
 /// <summary>
 /// Some protocols support a method to extend the encryption or decryption key when supplied key
 /// is too short.
 /// </summary>
 /// <param name="shortKey">Key that needs to be extended</param>
 /// <param name="password">Privacy password as configured on the SNMP agent.</param>
 /// <param name="engineID">Authoritative engine id. Value is retrieved as part of SNMP v3 discovery procedure</param>
 /// <param name="authProtocol">Authentication protocol class instance cast as <see cref="IAuthenticationDigest"/></param>
 /// <returns>Extended key value</returns>
 public byte[] ExtendShortKey(byte[] shortKey, byte[] password, byte[] engineID, IAuthenticationDigest authProtocol)
 {
     byte[] extKey = new byte[MinimumKeyLength];
     byte[] lastKeyBuf = new byte[shortKey.Length];
     Array.Copy(shortKey, lastKeyBuf, shortKey.Length);
     int keyLen = shortKey.Length > MinimumKeyLength ? MinimumKeyLength : shortKey.Length;
     Array.Copy(shortKey, extKey, keyLen);
     while (keyLen < MinimumKeyLength)
     {
         byte[] tmpBuf = authProtocol.PasswordToKey(lastKeyBuf, engineID);
         if (tmpBuf == null)
         {
             return null;
         }
         if (tmpBuf.Length <= (MinimumKeyLength - keyLen))
         {
             Array.Copy(tmpBuf, 0, extKey, keyLen, tmpBuf.Length);
             keyLen += tmpBuf.Length;
         }
         else
         {
             Array.Copy(tmpBuf, 0, extKey, keyLen, MinimumKeyLength - keyLen);
             keyLen += (MinimumKeyLength - keyLen);
         }
         lastKeyBuf = new byte[tmpBuf.Length];
         Array.Copy(tmpBuf, lastKeyBuf, tmpBuf.Length);
     }
     return extKey;
 }