Webserver+3d print

Dependents:   Nucleo

cyclone_tcp/snmp/snmp_usm.c

Committer:
Sergunb
Date:
2017-02-04
Revision:
0:8918a71cdbe9

File content as of revision 0:8918a71cdbe9:

/**
 * @file snmp_usm.c
 * @brief User-based Security Model (USM) for SNMPv3
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneTCP Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @section Description
 *
 * This module implements the User-based Security Model (USM) for Simple
 * Network Management Protocol (SNMP) version 3. Refer to the following
 * RFCs for complete details:
 * - RFC 3414: User-based Security Model (USM) for SNMPv3
 * - RFC 3826: AES Cipher Algorithm in the SNMP User-based Security Model
 * - RFC 7860: HMAC-SHA-2 Authentication Protocols in the User-based Security Model
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL SNMP_TRACE_LEVEL

//Dependencies
#include "core/net.h"
#include "snmp/snmp_common.h"
#include "snmp/snmp_usm.h"
#include "crypto.h"
#include "asn1.h"
#include "hmac.h"
#include "debug.h"

//Check TCP/IP stack configuration
#if (SNMP_V3_SUPPORT == ENABLED)

//usmStatsUnsupportedSecLevels.0 object (1.3.6.1.6.3.15.1.1.1.0)
const uint8_t usmStatsUnsupportedSecLevelsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 1, 0};
//usmStatsNotInTimeWindows.0 object (1.3.6.1.6.3.15.1.1.2.0)
const uint8_t usmStatsNotInTimeWindowsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 2, 0};
//usmStatsUnknownUserNames.0 object (1.3.6.1.6.3.15.1.1.3.0)
const uint8_t usmStatsUnknownUserNamesObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 3, 0};
//usmStatsUnknownEngineIDs.0 object (1.3.6.1.6.3.15.1.1.4.0)
const uint8_t usmStatsUnknownEngineIdsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 4, 0};
//usmStatsWrongDigests.0 object (1.3.6.1.6.3.15.1.1.5.0)
const uint8_t usmStatsWrongDigestsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 5, 0};
//usmStatsDecryptionErrors.0 object (1.3.6.1.6.3.15.1.1.6.0)
const uint8_t usmStatsDecryptionErrorsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 6, 0};


/**
 * @brief Password to key algorithm
 * @param[in] authProtocol Authentication protocol (MD5 or SHA-1)
 * @param[in] password NULL-terminated string that contains the password
 * @param[in] engineId Pointer to the engine ID
 * @param[in] engineIdLen Length of the engine ID
 * @param[out] key Pointer to the resulting key
 * @return Error code
 **/

error_t snmpGenerateKey(SnmpAuthProtocol authProtocol, const char_t *password,
   const uint8_t *engineId, size_t engineIdLen, SnmpKey *key)
{
   size_t i;
   size_t n;
   size_t passwordLen;
   const HashAlgo *hash;
   uint8_t context[MAX_HASH_CONTEXT_SIZE];

   //Clear SNMP key
   memset(key, 0, sizeof(SnmpKey));

#if (SNMP_MD5_SUPPORT == ENABLED)
   //HMAC-MD5-96 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_MD5)
   {
      //Use MD5 to generate the key
      hash = MD5_HASH_ALGO;
   }
   else
#endif
#if (SNMP_SHA1_SUPPORT == ENABLED)
   //HMAC-SHA-1-96 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_SHA1)
   {
      //Use SHA-1 to generate the key
      hash = SHA1_HASH_ALGO;
   }
   else
#endif
#if (SNMP_SHA224_SUPPORT == ENABLED)
   //HMAC-SHA-224-128 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_SHA224)
   {
      //Use SHA-224 to generate the key
      hash = SHA224_HASH_ALGO;
   }
   else
#endif
#if (SNMP_SHA256_SUPPORT == ENABLED)
   //HMAC-SHA-256-192 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_SHA256)
   {
      //Use SHA-256 to generate the key
      hash = SHA256_HASH_ALGO;
   }
   else
#endif
#if (SNMP_SHA384_SUPPORT == ENABLED)
   //HMAC-SHA-384-256 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_SHA384)
   {
      //Use SHA-384 to generate the key
      hash = SHA384_HASH_ALGO;
   }
   else
#endif
#if (SNMP_SHA512_SUPPORT == ENABLED)
   //HMAC-SHA-512-384 authentication protocol?
   if(authProtocol == SNMP_AUTH_PROTOCOL_SHA512)
   {
      //Use SHA-512 to generate the key
      hash = SHA512_HASH_ALGO;
   }
   else
#endif
   {
      //Invalid authentication protocol
      return ERROR_INVALID_PARAMETER;
   }

   //Retrieve the length of the password
   passwordLen = strlen(password);

   //SNMP implementations must ensure that passwords are at
   //least 8 characters in length (see RFC 3414 11.2)
   if(passwordLen < 8)
      return ERROR_INVALID_LENGTH;

   //Initialize hash context
   hash->init(context);

   //Loop until we have done 1 megabyte
   for(i = 0; i < 1048576; i += n)
   {
      n = MIN(passwordLen, 1048576 - i);
      hash->update(context, password, n);
   }

   //Finalize hash computation
   hash->final(context, key->b);

   //Key localization
   hash->init(context);
   hash->update(context, key, hash->digestSize);
   hash->update(context, engineId, engineIdLen);
   hash->update(context, key, hash->digestSize);
   hash->final(context, key->b);

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Check security parameters
 * @param[in] user Security profile of the user
 * @param[in,out] message Pointer to the incoming SNMP message
 * @param[in] engineId Pointer to the authoritative engine ID
 * @param[in] engineIdLen Length of the authoritative engine ID
 * @return Error code
 **/

error_t snmpCheckSecurityParameters(const SnmpUserInfo *user,
   SnmpMessage *message, const uint8_t *engineId, size_t engineIdLen)
{
   //Check the length of the authoritative engine ID
   if(message->msgAuthEngineIdLen != engineIdLen)
      return ERROR_UNKNOWN_ENGINE_ID;

   //If the value of the msgAuthoritativeEngineID field is unknown, then an
   //error indication (unknownEngineID) is returned to the calling module
   if(memcmp(message->msgAuthEngineId, engineId, engineIdLen))
      return ERROR_UNKNOWN_ENGINE_ID;

   //If no information is available for the user, then an error indication
   //(unknownSecurityName) is returned to the calling module
   if(user == NULL)
      return ERROR_UNKNOWN_USER_NAME;

   //Check whether the securityLevel specifies that the message should
   //be authenticated
   if(user->authProtocol != SNMP_AUTH_PROTOCOL_NONE)
   {
      //Make sure the authFlag is set
      if(!(message->msgFlags & SNMP_MSG_FLAG_AUTH))
         return ERROR_UNSUPPORTED_SECURITY_LEVEL;
   }

   //Check whether the securityLevel specifies that the message should
   //be encrypted
   if(user->privProtocol != SNMP_PRIV_PROTOCOL_NONE)
   {
      //Make sure the privFlag is set
      if(!(message->msgFlags & SNMP_MSG_FLAG_PRIV))
         return ERROR_UNSUPPORTED_SECURITY_LEVEL;
   }

   //Security parameters are valid
   return NO_ERROR;
}


/**
 * @brief Authenticate outgoing SNMP message
 * @param[in] user Security profile of the user
 * @param[in,out] message Pointer to the outgoing SNMP message
 * @return Error code
 **/

error_t snmpAuthOutgoingMessage(const SnmpUserInfo *user, SnmpMessage *message)
{
   const HashAlgo *hash;
   size_t hmacDigestSize;
   HmacContext hmacContext;

#if (SNMP_MD5_SUPPORT == ENABLED)
   //HMAC-MD5-96 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_MD5)
   {
      //Use MD5 hash algorithm
      hash = MD5_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 12;
   }
   else
#endif
#if (SNMP_SHA1_SUPPORT == ENABLED)
   //HMAC-SHA-1-96 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA1)
   {
      //Use SHA-1 hash algorithm
      hash = SHA1_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 12;
   }
   else
#endif
#if (SNMP_SHA224_SUPPORT == ENABLED)
   //HMAC-SHA-224-128 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA224)
   {
      //Use SHA-224 hash algorithm
      hash = SHA224_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 16;
   }
   else
#endif
#if (SNMP_SHA256_SUPPORT == ENABLED)
   //HMAC-SHA-256-192 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA256)
   {
      //Use SHA-256 hash algorithm
      hash = SHA256_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 24;
   }
   else
#endif
#if (SNMP_SHA384_SUPPORT == ENABLED)
   //HMAC-SHA-384-256 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA384)
   {
      //Use SHA-384 hash algorithm
      hash = SHA384_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 32;
   }
   else
#endif
#if (SNMP_SHA512_SUPPORT == ENABLED)
   //HMAC-SHA-512-384 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA512)
   {
      //Use SHA-512 hash algorithm
      hash = SHA512_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 48;
   }
   else
#endif
   //Invalid authentication protocol?
   {
      //Report en error
      return ERROR_FAILURE;
   }

   //Check the length of the msgAuthenticationParameters field
   if(message->msgAuthParametersLen != hmacDigestSize)
      return ERROR_FAILURE;

   //The MAC is calculated over the whole message
   hmacInit(&hmacContext, hash, user->authKey.b, hash->digestSize);
   hmacUpdate(&hmacContext, message->pos, message->length);
   hmacFinal(&hmacContext, NULL);

   //Replace the msgAuthenticationParameters field with the calculated MAC
   memcpy(message->msgAuthParameters, hmacContext.digest, hmacDigestSize);

   //Successful message authentication
   return NO_ERROR;
}


/**
 * @brief Authenticate incoming SNMP message
 * @param[in] user Security profile of the user
 * @param[in] message Pointer to the incoming SNMP message
 * @return Error code
 **/

error_t snmpAuthIncomingMessage(const SnmpUserInfo *user, SnmpMessage *message)
{
   const HashAlgo *hash;
   size_t hmacDigestSize;
   uint8_t hmacDigest[SNMP_MAX_HMAC_DIGEST_SIZE];
   HmacContext hmacContext;

#if (SNMP_MD5_SUPPORT == ENABLED)
   //HMAC-MD5-96 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_MD5)
   {
      //Use MD5 hash algorithm
      hash = MD5_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 12;
   }
   else
#endif
#if (SNMP_SHA1_SUPPORT == ENABLED)
   //HMAC-SHA-1-96 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA1)
   {
      //Use SHA-1 hash algorithm
      hash = SHA1_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 12;
   }
   else
#endif
#if (SNMP_SHA224_SUPPORT == ENABLED)
   //HMAC-SHA-224-128 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA224)
   {
      //Use SHA-224 hash algorithm
      hash = SHA224_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 16;
   }
   else
#endif
#if (SNMP_SHA256_SUPPORT == ENABLED)
   //HMAC-SHA-256-192 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA256)
   {
      //Use SHA-256 hash algorithm
      hash = SHA256_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 24;
   }
   else
#endif
#if (SNMP_SHA384_SUPPORT == ENABLED)
   //HMAC-SHA-384-256 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA384)
   {
      //Use SHA-384 hash algorithm
      hash = SHA384_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 32;
   }
   else
#endif
#if (SNMP_SHA512_SUPPORT == ENABLED)
   //HMAC-SHA-512-384 authentication protocol?
   if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA512)
   {
      //Use SHA-512 hash algorithm
      hash = SHA512_HASH_ALGO;
      //Length of the message digest
      hmacDigestSize = 48;
   }
   else
#endif
   //Invalid authentication protocol?
   {
      //Report an error
      return ERROR_AUTHENTICATION_FAILED;
   }

   //Check the length of the msgAuthenticationParameters field
   if(message->msgAuthParametersLen != hmacDigestSize)
      return ERROR_AUTHENTICATION_FAILED;

   //The MAC received in the msgAuthenticationParameters field is saved
   memcpy(hmacDigest, message->msgAuthParameters, hmacDigestSize);

   //The digest in the msgAuthenticationParameters field is replaced by
   //a null octet string
   memset(message->msgAuthParameters, 0, hmacDigestSize);

   //The MAC is calculated over the whole message
   hmacInit(&hmacContext, hash, user->authKey.b, hash->digestSize);
   hmacUpdate(&hmacContext, message->buffer, message->bufferLen);
   hmacFinal(&hmacContext, NULL);

   //Restore the value of the msgAuthenticationParameters field
   memcpy(message->msgAuthParameters, hmacDigest, hmacDigestSize);

   //The newly calculated MAC is compared with the MAC value that was
   //saved in the first step
   if(memcmp(hmacContext.digest, hmacDigest, hmacDigestSize))
      return ERROR_AUTHENTICATION_FAILED;

   //Successful message authentication
   return NO_ERROR;
}


/**
 * @brief Data encryption
 * @param[in] user Security profile of the user
 * @param[in,out] message Pointer to the outgoing SNMP message
 * @param[in,out] salt Pointer to the salt integer
 * @return Error code
 **/

error_t snmpEncryptData(const SnmpUserInfo *user, SnmpMessage *message, uint64_t *salt)
{
   error_t error;
   uint_t i;
   size_t n;
   Asn1Tag tag;

   //Debug message
   TRACE_DEBUG("Scoped PDU (%" PRIuSIZE " bytes):\r\n", message->length);
   //Display the contents of the scopedPDU
   TRACE_DEBUG_ARRAY("  ", message->pos, message->length);
   //Display ASN.1 structure
   asn1DumpObject(message->pos, message->length, 0);

#if (SNMP_DES_SUPPORT == ENABLED)
   //DES-CBC privacy protocol?
   if(user->privProtocol == SNMP_PRIV_PROTOCOL_DES)
   {
      DesContext desContext;
      uint8_t iv[DES_BLOCK_SIZE];

      //The data to be encrypted is treated as sequence of octets. Its length
      //should be an integral multiple of 8
      if(message->length % 8)
      {
         //If it is not, the data is padded at the end as necessary
         n = 8 - (message->length % 8);
         //The actual pad value is irrelevant
         memset(message->pos + message->length, n, n);
         //Update the length of the data
         message->length += n;
      }

      //The 32-bit snmpEngineBoots is converted to the first 4 octets of our salt
      STORE32BE(message->msgAuthEngineBoots, message->msgPrivParameters);
      //The 32-bit integer is then converted to the last 4 octet of our salt
      STORE32BE(*salt, message->msgPrivParameters + 4);

      //The resulting salt is then put into the msgPrivacyParameters field
      message->msgPrivParametersLen = 8;

      //Initialize DES context
      error = desInit(&desContext, user->privKey.b, 8);
      //Initialization failed?
      if(error)
         return error;

      //The last 8 octets of the 16-octet secret (private privacy key) are
      //used as pre-IV
      memcpy(iv, user->privKey.b + DES_BLOCK_SIZE, DES_BLOCK_SIZE);

      //The msgPrivacyParameters field is XOR-ed with the pre-IV to obtain the IV
      for(i = 0; i < DES_BLOCK_SIZE; i++)
         iv[i] ^= message->msgPrivParameters[i];

      //Perform CBC encryption
      error = cbcEncrypt(DES_CIPHER_ALGO, &desContext, iv,
         message->pos, message->pos, message->length);
      //Any error to report?
      if(error)
         return error;
   }
   else
#endif
#if (SNMP_AES_SUPPORT == ENABLED)
   //AES-128-CFB privacy protocol?
   if(user->privProtocol == SNMP_PRIV_PROTOCOL_AES)
   {
      AesContext aesContext;
      uint8_t iv[AES_BLOCK_SIZE];

      //The 32-bit snmpEngineBoots is converted to the first 4 octets of the IV
      STORE32BE(message->msgAuthEngineBoots, iv);
      //The 32-bit snmpEngineTime is converted to the subsequent 4 octets
      STORE32BE(message->msgAuthEngineTime, iv + 4);
      //The 64-bit integer is then converted to the last 8 octets
      STORE64BE(*salt, iv + 8);

      //The 64-bit integer must be placed in the msgPrivacyParameters field to
      //enable the receiving entity to compute the correct IV and to decrypt
      //the message
      STORE64BE(*salt, message->msgPrivParameters);
      message->msgPrivParametersLen = 8;

      //Initialize AES context
      error = aesInit(&aesContext, user->privKey.b, 16);
      //Initialization failed?
      if(error)
         return error;

      //Perform CFB-128 encryption
      error = cfbEncrypt(AES_CIPHER_ALGO, &aesContext, 128, iv,
         message->pos, message->pos, message->length);
      //Any error to report?
      if(error)
         return error;
   }
   else
#endif
   //Invalid privacy protocol?
   {
      //Report an error
      return ERROR_FAILURE;
   }

   //The encryptedPDU is encapsulated within an octet string
   tag.constructed = FALSE;
   tag.objClass = ASN1_CLASS_UNIVERSAL;
   tag.objType = ASN1_TYPE_OCTET_STRING;
   tag.length = message->length;
   tag.value = NULL;

   //Write the corresponding ASN.1 tag
   error = asn1WriteTag(&tag, TRUE, message->pos, &n);
   //Any error to report?
   if(error)
      return error;

   //Move backward
   message->pos -= n;
   //Total length of the encryptedPDU
   message->length += n;

   //The salt integer is then modified. It is incremented by one and wrap
   //when it reaches its maximum value
   *salt += 1;

   //Successful encryption
   return NO_ERROR;
}


/**
 * @brief Data decryption
 * @param[in] user Security profile of the user
 * @param[in,out] message Pointer to the incoming SNMP message
 * @return Error code
 **/

error_t snmpDecryptData(const SnmpUserInfo *user, SnmpMessage *message)
{
   error_t error;
   uint_t i;
   Asn1Tag tag;

   //The encryptedPDU is encapsulated within an octet string
   error = asn1ReadTag(message->pos, message->length, &tag);
   //Failed to decode ASN.1 tag?
   if(error)
      return error;

   //Enforce encoding, class and type
   error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
   //The tag does not match the criteria?
   if(error)
      return error;

   //Point to the encryptedPDU
   message->pos = (uint8_t *) tag.value;
   //Length of the encryptedPDU
   message->length = tag.length;

#if (SNMP_DES_SUPPORT == ENABLED)
   //DES-CBC privacy protocol?
   if(user->privProtocol == SNMP_PRIV_PROTOCOL_DES)
   {
      DesContext desContext;
      uint8_t iv[DES_BLOCK_SIZE];

      //Before decryption, the encrypted data length is verified. The length
      //of the encrypted data must be a multiple of 8 octets
      if(message->length % 8)
         return ERROR_DECRYPTION_FAILED;

      //Check the length of the msgPrivacyParameters field
      if(message->msgPrivParametersLen != 8)
         return ERROR_DECRYPTION_FAILED;

      //Initialize DES context
      error = desInit(&desContext, user->privKey.b, 8);
      //Initialization failed?
      if(error)
         return error;

      //The last 8 octets of the 16-octet secret (private privacy key) are
      //used as pre-IV
      memcpy(iv, user->privKey.b + DES_BLOCK_SIZE, DES_BLOCK_SIZE);

      //The msgPrivacyParameters field is XOR-ed with the pre-IV to obtain the IV
      for(i = 0; i < DES_BLOCK_SIZE; i++)
         iv[i] ^= message->msgPrivParameters[i];

      //Perform CBC decryption
      error = cbcDecrypt(DES_CIPHER_ALGO, &desContext, iv,
         message->pos, message->pos, message->length);
      //Any error to report?
      if(error)
         return error;
   }
   else
#endif
#if (SNMP_AES_SUPPORT == ENABLED)
   //AES-128-CFB privacy protocol?
   if(user->privProtocol == SNMP_PRIV_PROTOCOL_AES)
   {
      AesContext aesContext;
      uint8_t iv[AES_BLOCK_SIZE];

      //Check the length of the msgPrivacyParameters field
      if(message->msgPrivParametersLen != 8)
         return ERROR_DECRYPTION_FAILED;

      //The 32-bit snmpEngineBoots is converted to the first 4 octets of the IV
      STORE32BE(message->msgAuthEngineBoots, iv);
      //The 32-bit snmpEngineTime is converted to the subsequent 4 octets
      STORE32BE(message->msgAuthEngineTime, iv + 4);
      //The 64-bit integer is then converted to the last 8 octets
      memcpy(iv + 8, message->msgPrivParameters, 8);

      //Initialize AES context
      error = aesInit(&aesContext, user->privKey.b, 16);
      //Initialization failed?
      if(error)
         return error;

      //Perform CFB-128 encryption
      error = cfbDecrypt(AES_CIPHER_ALGO, &aesContext, 128, iv,
         message->pos, message->pos, message->length);
      //Any error to report?
      if(error)
         return error;
   }
   else
#endif
   //Invalid privacy protocol?
   {
      //Report an error
      return ERROR_DECRYPTION_FAILED;
   }

   //Debug message
   TRACE_DEBUG("Scoped PDU (%" PRIuSIZE " bytes):\r\n", message->length);
   //Display the contents of the scopedPDU
   TRACE_DEBUG_ARRAY("  ", message->pos, message->length);
   //Display ASN.1 structure
   asn1DumpObject(message->pos, message->length, 0);

   //Successful decryption
   return NO_ERROR;
}

#endif