Webserver+3d print

Dependents:   Nucleo

cyclone_crypto/rsa.c

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

File content as of revision 0:8918a71cdbe9:

/**
 * @file rsa.c
 * @brief RSA public-key cryptography standard
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneCrypto 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
 *
 * RSA is an algorithm for public-key cryptography which is suitable for signing
 * as well as encryption. Refer to PKCS #1 (RSA Cryptography Standard)
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

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

//Dependencies
#include <stdlib.h>
#include <string.h>
#include "crypto.h"
#include "rsa.h"
#include "mpi.h"
#include "asn1.h"
#include "oid.h"
#include "debug.h"

//Check crypto library configuration
#if (RSA_SUPPORT == ENABLED)

//PKCS #1 OID (1.2.840.113549.1.1)
const uint8_t PKCS1_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01};
//RSA encryption OID (1.2.840.113549.1.1.1)
const uint8_t RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01};
//MD5 with RSA encryption OID (1.2.840.113549.1.1.4)
const uint8_t MD5_WITH_RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04};
//SHA-1 with RSA encryption OID (1.2.840.113549.1.1.5)
const uint8_t SHA1_WITH_RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05};
//SHA-256 with RSA encryption OID (1.2.840.113549.1.1.11)
const uint8_t SHA256_WITH_RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B};
//SHA-384 with RSA encryption OID (1.2.840.113549.1.1.12)
const uint8_t SHA384_WITH_RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C};
//SHA-512 with RSA encryption OID (1.2.840.113549.1.1.13)
const uint8_t SHA512_WITH_RSA_ENCRYPTION_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D};
//RSA PKCS #1 v1.5 signature with SHA-3-224 OID (2.16.840.1.101.3.4.3.13)
const uint8_t RSASSA_PKCS1_v1_5_WITH_SHA3_224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0D};
//RSA PKCS #1 v1.5 signature with SHA-3-256 OID (2.16.840.1.101.3.4.3.14)
const uint8_t RSASSA_PKCS1_v1_5_WITH_SHA3_256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0E};
//RSA PKCS #1 v1.5 signature with SHA-3-384 OID (2.16.840.1.101.3.4.3.15)
const uint8_t RSASSA_PKCS1_v1_5_WITH_SHA3_384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0F};
//RSA PKCS #1 v1.5 signature with SHA-3-512 OID (2.16.840.1.101.3.4.3.16)
const uint8_t RSASSA_PKCS1_v1_5_WITH_SHA3_512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x10};


/**
 * @brief Initialize a RSA public key
 * @param[in] key Pointer to the RSA public key to initialize
 **/

void rsaInitPublicKey(RsaPublicKey *key)
{
   //Initialize multiple precision integers
   mpiInit(&key->n);
   mpiInit(&key->e);
}


/**
 * @brief Release a RSA public key
 * @param[in] key Pointer to the RSA public key to free
 **/

void rsaFreePublicKey(RsaPublicKey *key)
{
   //Free multiple precision integers
   mpiFree(&key->n);
   mpiFree(&key->e);
}


/**
 * @brief Initialize a RSA private key
 * @param[in] key Pointer to the RSA private key to initialize
 **/

void rsaInitPrivateKey(RsaPrivateKey *key)
{
   //Initialize multiple precision integers
   mpiInit(&key->n);
   mpiInit(&key->e);
   mpiInit(&key->d);
   mpiInit(&key->p);
   mpiInit(&key->q);
   mpiInit(&key->dp);
   mpiInit(&key->dq);
   mpiInit(&key->qinv);
}


/**
 * @brief Release a RSA private key
 * @param[in] key Pointer to the RSA private key to free
 **/

void rsaFreePrivateKey(RsaPrivateKey *key)
{
   //Free multiple precision integers
   mpiFree(&key->n);
   mpiFree(&key->e);
   mpiFree(&key->d);
   mpiFree(&key->p);
   mpiFree(&key->q);
   mpiFree(&key->dp);
   mpiFree(&key->dq);
   mpiFree(&key->qinv);
}


/**
 * @brief RSA encryption primitive
 *
 * The RSA encryption primitive produces a ciphertext representative from
 * a message representative under the control of a public key
 *
 * @param[in] key RSA public key
 * @param[in] m Message representative
 * @param[out] c Ciphertext representative
 * @return Error code
 **/

error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
{
   //Ensure the RSA public key is valid
   if(!key->n.size || !key->e.size)
      return ERROR_INVALID_PARAMETER;

   //The message representative m shall be between 0 and n - 1
   if(mpiCompInt(m, 0) < 0 || mpiComp(m, &key->n) >= 0)
      return ERROR_OUT_OF_RANGE;

   //Perform modular exponentiation (c = m ^ e mod n)
   return mpiExpMod(c, m, &key->e, &key->n);
}


/**
 * @brief RSA decryption primitive
 *
 * The RSA decryption primitive recovers the message representative from
 * the ciphertext representative under the control of a private key
 *
 * @param[in] key RSA private key
 * @param[in] c Ciphertext representative
 * @param[out] m Message representative
 * @return Error code
 **/

error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
{
   error_t error;
   Mpi m1;
   Mpi m2;
   Mpi h;

   //The ciphertext representative c shall be between 0 and n - 1
   if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
      return ERROR_OUT_OF_RANGE;

   //Initialize multiple-precision integers
   mpiInit(&m1);
   mpiInit(&m2);
   mpiInit(&h);

   //Use the Chinese remainder algorithm?
   if(key->n.size && key->p.size && key->q.size &&
      key->dp.size && key->dq.size && key->qinv.size)
   {
      //Compute m1 = c ^ dP mod p
      MPI_CHECK(mpiExpMod(&m1, c, &key->dp, &key->p));
      //Compute m2 = c ^ dQ mod q
      MPI_CHECK(mpiExpMod(&m2, c, &key->dq, &key->q));
      //Let h = (m1 - m2) * qInv mod p
      MPI_CHECK(mpiSub(&h, &m1, &m2));
      MPI_CHECK(mpiMulMod(&h, &h, &key->qinv, &key->p));
      //Let m = m2 + q * h
      MPI_CHECK(mpiMul(m, &key->q, &h));
      MPI_CHECK(mpiAdd(m, m, &m2));
   }
   //Use modular exponentiation?
   else if(key->n.size && key->d.size)
   {
      //Let m = c ^ d mod n
      error = mpiExpMod(m, c, &key->d, &key->n);
   }
   //Invalid parameters?
   else
   {
      //Report an error
      error = ERROR_INVALID_PARAMETER;
   }

end:
   //Free previously allocated memory
   mpiFree(&m1);
   mpiFree(&m2);
   mpiFree(&h);

   //Return status code
   return error;
}


/**
 * @brief RSA signature primitive
 *
 * The RSA signature primitive produces a signature representative from
 * a message representative under the control of a private key
 *
 * @param[in] key RSA private key
 * @param[in] m Message representative
 * @param[out] s Signature representative
 * @return Error code
 **/

error_t rsasp1(const RsaPrivateKey *key, const Mpi *m, Mpi *s)
{
   //RSASP1 primitive is the same as RSADP except for the names of its
   //input and output arguments. They are distinguished as they are
   //intended for different purposes
   return rsadp(key, m, s);
}


/**
 * @brief RSA verification primitive
 *
 * The RSA verification primitive recovers the message representative from
 * the signature representative under the control of a public key
 *
 * @param[in] key RSA public key
 * @param[in] s Signature representative
 * @param[out] m Message representative
 * @return Error code
 **/

error_t rsavp1(const RsaPublicKey *key, const Mpi *s, Mpi *m)
{
   //RSAVP1 primitive is the same as RSAEP except for the names of its
   //input and output arguments. They are distinguished as they are
   //intended for different purposes
   return rsaep(key, s, m);
}


/**
 * @brief PKCS #1 v1.5 encryption operation
 * @param[in] prngAlgo PRNG algorithm
 * @param[in] prngContext Pointer to the PRNG context
 * @param[in] key Recipient's RSA public key
 * @param[in] message Message to be encrypted
 * @param[in] messageLength Length of the message to be encrypted
 * @param[out] ciphertext Ciphertext resulting from the encryption operation
 * @param[out] ciphertextLength Length of the resulting ciphertext
 * @return Error code
 **/

error_t rsaesPkcs1v15Encrypt(const PrngAlgo *prngAlgo, void *prngContext, const RsaPublicKey *key,
   const uint8_t *message, size_t messageLength, uint8_t *ciphertext, size_t *ciphertextLength)
{
   error_t error;
   uint_t i;
   uint_t j;
   uint_t k;
   uint_t n;
   uint8_t *p;
   Mpi m;
   Mpi c;

   //Check parameters
   if(key == NULL || message == NULL)
      return ERROR_INVALID_PARAMETER;
   if(ciphertext == NULL || ciphertextLength == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 encryption...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Message:\r\n");
   TRACE_DEBUG_ARRAY("    ", message, messageLength);

   //Initialize multiple-precision integers
   mpiInit(&m);
   mpiInit(&c);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);

   //Check the length of the message
   if((messageLength + 11) > k)
      return ERROR_INVALID_LENGTH;

   //Point to the buffer where the encoded message EM will be formatted
   p = ciphertext;

   //The leading 0x00 octet ensures that the encoded message,
   //converted to an integer, is less than the modulus
   *(p++) = 0x00;
   //For a public-key operation, the block type BT shall be 0x02
   *(p++) = 0x02;

   //Length of the padding string PS
   n = k - messageLength - 3;

   //Generate the padding string (pseudo-randomly generated non-zero octets)
   while(n > 0)
   {
      //Generate random data
      error = prngAlgo->read(prngContext, p, n);
      //Any error to report?
      if(error)
         return error;

      //Parse the resulting octet string
      for(i = 0, j = 0; j < n; j++)
      {
         //Strip any byte with a value of zero
         if(p[j] != 0)
            p[i++] = p[j];
      }

      //Advance data pointer
      p += i;
      n -= i;
   }

   //Append a 0x00 octet to the padding string
   *(p++) = 0x00;
   //Copy the message to be encrypted
   memcpy(p, message, messageLength);

   //Rewind to the beginning of the encoded message
   p = ciphertext;

   //Debug message
   TRACE_DEBUG("  Encoded message\r\n");
   TRACE_DEBUG_ARRAY("    ", p, k);

   //Start of exception handling block
   do
   {
      //Convert the encoded message EM to an integer message representative m
      error = mpiReadRaw(&m, p, k);
      //Conversion failed?
      if(error)
         break;

      //Apply the RSAEP encryption primitive
      error = rsaep(key, &m, &c);
      //Any error to report?
      if(error)
         break;

      //Convert the ciphertext representative c to a ciphertext of length k octets
      error = mpiWriteRaw(&c, ciphertext, k);
      //Conversion failed?
      if(error)
         break;

      //Length of the resulting ciphertext
      *ciphertextLength = k;

      //Debug message
      TRACE_DEBUG("  Ciphertext:\r\n");
      TRACE_DEBUG_ARRAY("    ", ciphertext, *ciphertextLength);

      //End of exception handling block
   } while(0);

   //Free previously allocated memory
   mpiFree(&m);
   mpiFree(&c);

   //Return status code
   return error;
}


/**
 * @brief PKCS #1 v1.5 decryption operation
 * @param[in] key Recipient's RSA private key
 * @param[in] ciphertext Ciphertext to be decrypted
 * @param[in] ciphertextLength Length of the ciphertext to be decrypted
 * @param[out] message Output buffer where to store the decrypted message
 * @param[in] messageSize Size of the output buffer
 * @param[out] messageLength Length of the decrypted message
 * @return Error code
 **/

error_t rsaesPkcs1v15Decrypt(const RsaPrivateKey *key, const uint8_t *ciphertext,
   size_t ciphertextLength, uint8_t *message, size_t messageSize, size_t *messageLength)
{
   error_t error;
   uint_t i;
   uint_t k;
   uint8_t *em;
   Mpi c;
   Mpi m;

   //Check parameters
   if(key == NULL || ciphertext == NULL)
      return ERROR_INVALID_PARAMETER;
   if(message == NULL || messageLength == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 decryption...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Private exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->d);
   TRACE_DEBUG("  Prime 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->p);
   TRACE_DEBUG("  Prime 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->q);
   TRACE_DEBUG("  Prime exponent 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dp);
   TRACE_DEBUG("  Prime exponent 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dq);
   TRACE_DEBUG("  Coefficient:\r\n");
   TRACE_DEBUG_MPI("    ", &key->qinv);
   TRACE_DEBUG("  Ciphertext:\r\n");
   TRACE_DEBUG_ARRAY("    ", ciphertext, ciphertextLength);

   //Initialize multiple-precision integers
   mpiInit(&c);
   mpiInit(&m);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);

   //Check the length of the ciphertext
   if(ciphertextLength != k || ciphertextLength < 11)
      return ERROR_INVALID_LENGTH;

   //Allocate a buffer to store the encoded message EM
   em = cryptoAllocMem(k);
   //Failed to allocate memory?
   if(em == NULL)
      return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Convert the ciphertext to an integer ciphertext representative c
      error = mpiReadRaw(&c, ciphertext, ciphertextLength);
      //Conversion failed?
      if(error)
         break;

      //Apply the RSADP decryption primitive
      error = rsadp(key, &c, &m);
      //Any error to report?
      if(error)
         break;

      //Convert the message representative m to an encoded message EM of length k octets
      error = mpiWriteRaw(&m, em, k);
      //Conversion failed?
      if(error)
         break;

      //Debug message
      TRACE_DEBUG("  Encoded message\r\n");
      TRACE_DEBUG_ARRAY("    ", em, k);

      //The first octet of EM must have a value of 0x00
      //and the block type BT shall be 0x02
      if(em[0] != 0x00 || em[1] != 0x02)
      {
         //Report an error
         error = ERROR_UNEXPECTED_VALUE;
         break;
      }

      //An octet with hexadecimal value 0x00 is used to separate PS from M
      for(i = 2; i < k && em[i] != 0x00; i++);

      //Check whether the padding string is valid
      if(i < 10 || i >= k)
      {
         //Report an error
         error = ERROR_INVALID_PADDING;
         break;
      }

      //Ensure that the output buffer is large enough
      if(messageSize < (k - i - 1))
      {
         //Report an error
         error = ERROR_INVALID_LENGTH;
         break;
      }

      //Recover the length of the message
      *messageLength = k - i - 1;
      //Copy the message contents
      memcpy(message, em + i + 1, *messageLength);

      //Debug message
      TRACE_DEBUG("  Message:\r\n");
      TRACE_DEBUG_ARRAY("    ", message, *messageLength);

      //End of exception handling block
   } while(0);

   //Release multiple precision integers
   mpiFree(&c);
   mpiFree(&m);
   //Free previously allocated memory
   cryptoFreeMem(em);

   //Return status code
   return error;
}


/**
 * @brief PKCS #1 v1.5 signature generation operation
 * @param[in] key Signer's RSA private key
 * @param[in] hash Hash function used to digest the message
 * @param[in] digest Digest of the message to be signed
 * @param[out] signature Resulting signature
 * @param[out] signatureLength Length of the resulting signature
 * @return Error code
 **/

error_t rsassaPkcs1v15Sign(const RsaPrivateKey *key, const HashAlgo *hash,
   const uint8_t *digest, uint8_t *signature, size_t *signatureLength)
{
   error_t error;
   uint_t k;
   uint8_t *em;
   Mpi m;
   Mpi s;

   //Check parameters
   if(key == NULL || hash == NULL || digest == NULL)
      return ERROR_INVALID_PARAMETER;
   if(signature == NULL || signatureLength == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 signature generation...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Private exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->d);
   TRACE_DEBUG("  Prime 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->p);
   TRACE_DEBUG("  Prime 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->q);
   TRACE_DEBUG("  Prime exponent 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dp);
   TRACE_DEBUG("  Prime exponent 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dq);
   TRACE_DEBUG("  Coefficient:\r\n");
   TRACE_DEBUG_MPI("    ", &key->qinv);
   TRACE_DEBUG("  Message digest:\r\n");
   TRACE_DEBUG_ARRAY("    ", digest, hash->digestSize);

   //Initialize multiple-precision integers
   mpiInit(&m);
   mpiInit(&s);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);
   //Point to the buffer where the encoded message EM will be generated
   em = signature;

   //Apply the EMSA-PKCS1-v1.5 encoding operation
   error = emsaPkcs1v15Encode(hash, digest, em, k);
   //Any error to report?
   if(error)
      return error;

   //Debug message
   TRACE_DEBUG("  Encoded message\r\n");
   TRACE_DEBUG_ARRAY("    ", em, k);

   //Start of exception handling block
   do
   {
      //Convert the encoded message EM to an integer message representative m
      error = mpiReadRaw(&m, em, k);
      //Conversion failed?
      if(error)
         break;

      //Apply the RSASP1 signature primitive
      error = rsasp1(key, &m, &s);
      //Any error to report?
      if(error)
         break;

      //Convert the signature representative s to a signature of length k octets
      error = mpiWriteRaw(&s, signature, k);
      //Conversion failed?
      if(error)
         break;

      //Length of the resulting signature
      *signatureLength = k;

      //Debug message
      TRACE_DEBUG("  Signature:\r\n");
      TRACE_DEBUG_ARRAY("    ", signature, *signatureLength);

      //End of exception handling block
   } while(0);

   //Free previously allocated memory
   mpiFree(&m);
   mpiFree(&s);

   //Return status code
   return error;
}


/**
 * @brief PKCS #1 v1.5 signature verification operation
 * @param[in] key Signer's RSA public key
 * @param[in] hash Hash function used to digest the message
 * @param[in] digest Digest of the message whose signature is to be verified
 * @param[in] signature Signature to be verified
 * @param[in] signatureLength Length of the signature to be verified
 * @return Error code
 **/

error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash,
   const uint8_t *digest, const uint8_t *signature, size_t signatureLength)
{
   error_t error;
   uint_t k;
   uint8_t *em;
   const uint8_t *oid;
   size_t oidLength;
   const uint8_t *d;
   size_t dLength;
   Mpi s;
   Mpi m;

   //Check parameters
   if(key == NULL || hash == NULL || digest == NULL || signature == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 signature verification...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Message digest:\r\n");
   TRACE_DEBUG_ARRAY("    ", digest, hash->digestSize);
   TRACE_DEBUG("  Signature:\r\n");
   TRACE_DEBUG_ARRAY("    ", signature, signatureLength);

   //Initialize multiple-precision integers
   mpiInit(&s);
   mpiInit(&m);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);

   //Check the length of the signature
   if(signatureLength != k)
      return ERROR_INVALID_LENGTH;

   //Allocate a memory buffer to hold the encoded message
   em = cryptoAllocMem(k);
   //Failed to allocate memory?
   if(em == NULL)
      return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Convert the signature to an integer signature representative s
      error = mpiReadRaw(&s, signature, signatureLength);
      //Conversion failed?
      if(error)
         break;

      //Apply the RSAVP1 verification primitive
      error = rsavp1(key, &s, &m);
      //Any error to report?
      if(error)
         break;

      //Convert the message representative m to an encoded message EM of length k octets
      error = mpiWriteRaw(&m, em, k);
      //Conversion failed?
      if(error)
         break;

      //Debug message
      TRACE_DEBUG("  Encoded message\r\n");
      TRACE_DEBUG_ARRAY("    ", em, k);

      //Parse the encoded message EM
      error = emsaPkcs1v15Decode(em, k, &oid, &oidLength, &d, &dLength);
      //Any error to report?
      if(error)
         break;

      //Assume an error...
      error = ERROR_INVALID_SIGNATURE_ALGO;
      //Ensure the hash algorithm identifier matches the OID
      if(oidComp(oid, oidLength, hash->oid, hash->oidSize))
         break;
      //Check the length of the digest
      if(dLength != hash->digestSize)
         break;

      //Compare the message digest
      error = memcmp(digest, d, dLength) ? ERROR_INVALID_SIGNATURE : NO_ERROR;

      //End of exception handling block
   } while(0);

   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&m);
   //Free previously allocated memory
   cryptoFreeMem(em);

   //Return status code
   return error;
}


/**
 * @brief PKCS #1 v1.5 encoding method
 * @param[in] hash Hash function used to digest the message
 * @param[in] digest Digest of the message to be signed
 * @param[out] em Encoded message
 * @param[in] emLength Intended length of the encoded message
 * @return Error code
 **/

error_t emsaPkcs1v15Encode(const HashAlgo *hash,
   const uint8_t *digest, uint8_t *em, size_t emLength)
{
   uint_t i;
   size_t paddingLength;

   //Ensure the length of the digest is valid
   if((hash->oidSize + hash->digestSize + 21) > emLength)
      return ERROR_INVALID_LENGTH;

   //The leading 0x00 octet ensures that the encoded message,
   //converted to an integer, is less than the modulus
   em[0] = 0x00;
   //Block type 0x01 is used for private-key operations
   em[1] = 0x01;

   //Compute the length of the padding string PS
   paddingLength = emLength - hash->oidSize - hash->digestSize - 13;
   //Fill the padding string with 0xFF
   memset(em + 2, 0xFF, paddingLength);

   //Point to the byte that follows PS
   i = paddingLength + 2;
   //Append a 0x00 octet to PS
   em[i++] = 0x00;

   //Encode the DigestInfo using ASN.1
   em[i++] = ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE;
   em[i++] = (uint8_t) (hash->oidSize + hash->digestSize + 8);
   em[i++] = ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE;
   em[i++] = (uint8_t) (hash->oidSize + 4);
   em[i++] = ASN1_TYPE_OBJECT_IDENTIFIER;
   em[i++] = (uint8_t) hash->oidSize;

   //Copy the hash algorithm OID
   memcpy(em + i, hash->oid, hash->oidSize);
   i += hash->oidSize;

   //Encode the rest of the ASN.1 structure
   em[i++] = ASN1_TYPE_NULL;
   em[i++] = 0;
   em[i++] = ASN1_TYPE_OCTET_STRING;
   em[i++] = (uint8_t) hash->digestSize;

   //Append the hash value
   memcpy(em + i, digest, hash->digestSize);

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief PKCS #1 v1.5 decoding method
 * @param[in] em Encoded message
 * @param[in] emLength Length of the encoded message
 * @param[out] oid Hash algorithm OID
 * @param[out] oidLength Length of the hash algorithm OID
 * @param[out] digest Digest value
 * @param[out] digestLength Length of the digest value

 * @return Error code
 **/

error_t emsaPkcs1v15Decode(const uint8_t *em, size_t emLength, const uint8_t **oid,
   size_t *oidLength, const uint8_t **digest, size_t *digestLength)
{
   error_t error;
   uint_t i;
   size_t length;
   const uint8_t *data;
   Asn1Tag tag;

   //Check the length of the encoded message EM
   if(emLength < 11)
      return ERROR_INVALID_LENGTH;

   //The first octet of EM must have a value of 0x00
   if(em[0] != 0x00)
      return ERROR_UNEXPECTED_VALUE;
   //The block type BT shall be 0x01
   if(em[1] != 0x01)
      return ERROR_UNEXPECTED_VALUE;

   //Check the padding string PS
   for(i = 2; i < emLength; i++)
   {
      //A 0x00 octet indicates the end of the padding string
      if(em[i] == 0x00)
         break;
      //Each byte of PS must be set to 0xFF when the block type is 0x01
      if(em[i] != 0xFF)
         return ERROR_INVALID_PADDING;
   }

   //Check whether the padding string is properly terminated
   if(i >= emLength)
      return ERROR_INVALID_PADDING;
   //The length of PS cannot be less than 8 octets
   if(i < 10)
      return ERROR_INVALID_PADDING;

   //Point to the DigestInfo structure
   data = em + i + 1;
   length = emLength - i - 1;

   //Read the contents of the DigestInfo structure
   error = asn1ReadTag(data, length, &tag);
   //Failed to decode the ASN.1 tag?
   if(error)
      return ERROR_INVALID_TAG;

   //Enforce encoding, class and type
   if(!tag.constructed || tag.objType != ASN1_TYPE_SEQUENCE)
      return ERROR_INVALID_TAG;

   //Point to the DigestAlgorithm structure
   data = tag.value;
   length = tag.length;

   //Decode the DigestAlgorithm tag
   error = asn1ReadTag(data, length, &tag);
   //Failed to decode the ASN.1 tag?
   if(error)
      return ERROR_INVALID_TAG;

   //Enforce encoding, class and type
   if(!tag.constructed || tag.objType != ASN1_TYPE_SEQUENCE)
      return ERROR_INVALID_TAG;

   //Save the location of the next tag
   data += tag.totalLength;
   length -= tag.totalLength;

   //Decode the AlgorithmIdentifier tag
   error = asn1ReadTag(tag.value, tag.length, &tag);
   //Failed to decode the ASN.1 tag?
   if(error)
      return ERROR_INVALID_TAG;

   //Enforce encoding, class and type
   if(tag.constructed || tag.objType != ASN1_TYPE_OBJECT_IDENTIFIER)
      return ERROR_INVALID_TAG;

   //Save the hash algorithm OID
   *oid = tag.value;
   *oidLength = tag.length;

   //Decode the DigestValue tag
   error = asn1ReadTag(data, length, &tag);
   //Failed to decode the ASN.1 tag?
   if(error)
      return ERROR_INVALID_TAG;

   //Enforce encoding, class and type
   if(tag.constructed || tag.objType != ASN1_TYPE_OCTET_STRING)
      return ERROR_INVALID_TAG;

   //Save the hash value
   *digest = tag.value;
   *digestLength = tag.length;

   //EM successfully decoded
   return NO_ERROR;
}

#endif