Skip to content
LibItsSecurity_externals.cc 85.4 KiB
Newer Older
/*!
 * \file      LibItsSecurity_Functions.cc
 * \brief     Source file for Security externl functions.
 * \author    ETSI STF525
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#include <memory>

#include "LibItsSecurity_Functions.hh"

#include "sha256.hh"
#include "sha384.hh"
#include "hmac.hh"

#include "security_ecc.hh"

#include "security_services.hh"

#include <openssl/ec.h>
#include <openssl/ecdsa.h>

#include "loggers.hh"

namespace LibItsSecurity__Functions 
{

  // FIXME Unify code with security_services
  
  /**
   * \fn OCTETSTRING fx_hashWithSha256(const OCTETSTRING& p__toBeHashedData);
   * \brief Produces a 256-bit (32-bytes) hash value
   * \param[in] p__toBeHashedData The data to be used to calculate the hash value
   * \return  The hash value
   */
  OCTETSTRING fx__hashWithSha256(
                                 const OCTETSTRING& p__toBeHashedData
                                 ) {
    loggers::get_instance().log_msg(">>> fx__hashWithSha256: p__toBeHashedData= ", p__toBeHashedData); 
    sha256 hash;
    OCTETSTRING hashData;
    hash.generate(p__toBeHashedData, hashData);
    loggers::get_instance().log_msg("fx__hashWithSha256: hashData= ", hashData);
    return hashData;
  } // End of function fx__hashWithSha256

  /**
   * \fn OCTETSTRING fx_hashWithSha384(const OCTETSTRING& p__toBeHashedData);
   * \brief Produces a 384-bit (48-bytes) hash value
   * \param[in] p__toBeHashedData Data to be used to calculate the hash value
   * \return The hash value
   */
  OCTETSTRING fx__hashWithSha384(
                                 const OCTETSTRING& p__toBeHashedData
                                 ) {
    sha384 hash;
    OCTETSTRING hashData;
    hash.generate(p__toBeHashedData, hashData);
    loggers::get_instance().log_msg("fx__hashWithSha384: hashData= ", hashData);
    return hashData;
  } // End of function fx__hashWithSha384

  /**
   * \fn OCTETSTRING fx__signWithEcdsaNistp256WithSha256(const OCTETSTRING& p__toBeSignedSecuredMessage, const OCTETSTRING& p__privateKey);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signature based on standard IEEE 1609.2
   * \param[in] p__toBeSignedSecuredMessage The data to be signed
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__privateKey The private key
   * \return The signature value
   */
  OCTETSTRING fx__signWithEcdsaNistp256WithSha256(
                                                  const OCTETSTRING& p__toBeSignedSecuredMessage,
                                                  const OCTETSTRING& p__certificateIssuer,
                                                  const OCTETSTRING& p__privateKey
                                                  ) {
garciay's avatar
garciay committed
    loggers::get_instance().log_msg(">>> fx__signWithEcdsaNistp256WithSha256: data=", p__toBeSignedSecuredMessage); 
    loggers::get_instance().log_msg(">>> fx__signWithEcdsaNistp256WithSha256: issuer=", p__certificateIssuer); 
    loggers::get_instance().log_msg(">>> fx__signWithEcdsaNistp256WithSha256: private key=", p__privateKey); 
    
    // Sanity checks
    if ((p__certificateIssuer.lengthof() != 32) || (p__privateKey.lengthof() != 32)) {
      loggers::get_instance().log("fx__signWithEcdsaNistp256WithSha256: Wrong parameters");
      return OCTETSTRING(0, nullptr);
    }
    
    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeSignedSecuredMessage, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__signWithEcdsaNistp256WithSha256: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__signWithEcdsaNistp256WithSha256: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    loggers::get_instance().log_msg("fx__signWithEcdsaNistp256WithSha256: Hash (Data input) || Hash (Signer identifier input)=", hashData1);
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__signWithEcdsaNistp256WithSha256: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Calculate the signature
    security_ecc k(ec_elliptic_curves::nist_p_256, p__privateKey);
    OCTETSTRING r_sig;
    OCTETSTRING s_sig;
    if (k.sign(hashData, r_sig, s_sig) == 0) {
      OCTETSTRING os = r_sig + s_sig;
      loggers::get_instance().log_msg("r_sig= ", r_sig);
      loggers::get_instance().log_msg("s_sig= ", s_sig);
      loggers::get_instance().log_msg("sig= ", os);
    return OCTETSTRING(0, nullptr);
Yann Garcia's avatar
Yann Garcia committed
  /**
   * \fn OCTETSTRING fx__signWithEcdsaNistp256WithSha256(const OCTETSTRING& p__toBeSignedSecuredMessage, const OCTETSTRING& p__privateKey);
   * \brief Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signature based on raw data
   * \param[in] p__toBeSignedSecuredMessage The data to be signed
   * \param[in] p__privateKey The private key
   * \return The signature value
   */
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__test__signWithEcdsaNistp256WithSha256(
                                                        const OCTETSTRING& p__toBeSignedSecuredMessage,
                                                        const OCTETSTRING& p__privateKey
                                                        ) {
    loggers::get_instance().log_msg(">>> fx__test__signWithEcdsaNistp256WithSha256: data=", p__toBeSignedSecuredMessage); 
    loggers::get_instance().log_msg(">>> fx__test__signWithEcdsaNistp256WithSha256: private key=", p__privateKey); 
    
    // Sanity checks
    if (p__privateKey.lengthof() != 32) {
      loggers::get_instance().log("fx__test__signWithEcdsaNistp256WithSha256: Wrong parameters");
      return OCTETSTRING(0, nullptr);
    }
    
    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeSignedSecuredMessage, hashData1);
    loggers::get_instance().log_msg("fx__test__signWithEcdsaNistp256WithSha256: Hash (Data input)=", hashData1);
    // Calculate the signature
    security_ecc k(ec_elliptic_curves::nist_p_256, p__privateKey);
    OCTETSTRING r_sig;
    OCTETSTRING s_sig;
    if (k.sign(hashData1, r_sig, s_sig) == 0) {
      OCTETSTRING os = r_sig + s_sig;
      loggers::get_instance().log_msg("r_sig= ", r_sig);
      loggers::get_instance().log_msg("s_sig= ", s_sig);
      loggers::get_instance().log_msg("sig= ", os);
      return os;
    }

    return OCTETSTRING(0, nullptr);
  }

  /**
   * \fn OCTETSTRING fx__signWithEcdsaBrainpoolp256WithSha256(const OCTETSTRING& p__toBeSignedSecuredMessage, const OCTETSTRING& p__privateKey);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signature based on standard IEEE 1609.2
   * \param[in] p__toBeSignedSecuredMessage The data to be signed
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__privateKey The private key
   * \return The signature value
   */
  OCTETSTRING fx__signWithEcdsaBrainpoolp256WithSha256(
                                                       const OCTETSTRING& p__toBeSignedSecuredMessage,
                                                       const OCTETSTRING& p__certificateIssuer,
                                                       const OCTETSTRING& p__privateKey
                                                       ) {
    // Sanity checks
    if ((p__certificateIssuer.lengthof() != 32) || (p__privateKey.lengthof() != 32)) {
      loggers::get_instance().log("fx__signWithEcdsaBrainpoolp256WithSha256: Wrong parameters");
      return OCTETSTRING(0, nullptr);
    }
    
    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeSignedSecuredMessage, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp256WithSha256: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp256WithSha256: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp256WithSha256: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Calculate the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_256_r1, p__privateKey);
    OCTETSTRING r_sig;
    OCTETSTRING s_sig;
    if (k.sign(hashData, r_sig, s_sig) == 0) {
      OCTETSTRING os = r_sig + s_sig;
      loggers::get_instance().log_msg("r_sig= ", r_sig);
      loggers::get_instance().log_msg("s_sig= ", s_sig);
      loggers::get_instance().log_msg("sig= ", os);
    return OCTETSTRING(0, nullptr);
  }

  /**
   * \fn OCTETSTRING fx__signWithEcdsaBrainpoolp384WithSha384(const OCTETSTRING& p__toBeSignedSecuredMessage, const OCTETSTRING& p__privateKey);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signature based on standard IEEE 1609.2
   * \param[in] p__toBeSignedSecuredMessage The data to be signed
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__privateKey The private key
   * \return The signature value
   */
  OCTETSTRING fx__signWithEcdsaBrainpoolp384WithSha384(
                                                       const OCTETSTRING& p__toBeSignedSecuredMessage,
                                                       const OCTETSTRING& p__certificateIssuer,
                                                       const OCTETSTRING& p__privateKey
                                                       ) {
    // Sanity checks
	    if ((p__certificateIssuer.lengthof() != 48) || (p__privateKey.lengthof() != 48)) {
      loggers::get_instance().log("fx__signWithEcdsaBrainpoolp384WithSha384: Wrong parameters");
      return OCTETSTRING(0, nullptr);
    }
    
    // Calculate the SHA384 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha384 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeSignedSecuredMessage, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 48)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha384_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Calculate the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_384_r1, p__privateKey);
    OCTETSTRING r_sig;
    OCTETSTRING s_sig;
    if (k.sign(hashData, r_sig, s_sig) == 0) {
      OCTETSTRING os = r_sig + s_sig;
      loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: r_sig= ", r_sig);
      loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: s_sig= ", s_sig);
      loggers::get_instance().log_msg("fx__signWithEcdsaBrainpoolp384WithSha384: sig= ", os);
    return OCTETSTRING(0, nullptr);
  }

  /**
   * \fn BOOLEAN fx__verifyWithEcdsaNistp256WithSha256(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaNistp256PublicKeyCompressed);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaNistp256PublicKeyCompressed The compressed public key (x coordinate only)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaNistp256WithSha256(
                                                const OCTETSTRING& p__toBeVerifiedData,
                                                const OCTETSTRING& p__certificateIssuer,
                                                const OCTETSTRING& p__signature,
                                                const OCTETSTRING& p__ecdsaNistp256PublicKeyCompressed,
                                                const INTEGER& p__compressedMode
    // Sanity checks
    if ((p__certificateIssuer.lengthof() != 32) || (p__signature.lengthof() != 64) || (p__ecdsaNistp256PublicKeyCompressed.lengthof() != 32)) {
      loggers::get_instance().log("fx__verifyWithEcdsaNistp256WithSha256: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::nist_p_256, p__ecdsaNistp256PublicKeyCompressed, (p__compressedMode == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (k.sign_verif(hashData, p__signature) == 0) {
Yann Garcia's avatar
Yann Garcia committed
  /**
   * \fn BOOLEAN fx__verifyWithEcdsaNistp256WithSha256(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__ecdsaNistp256PublicKeyCompressed);
   * \brief Verify the signature of the specified data based on raw data
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaNistp256PublicKeyCompressed The compressed public key (x coordinate only)
   * \return true on success, false otherwise
   */
Yann Garcia's avatar
Yann Garcia committed
  BOOLEAN fx__test__verifyWithEcdsaNistp256WithSha256(
                                                      const OCTETSTRING& p__toBeVerifiedData,
                                                      const OCTETSTRING& p__signature,
                                                      const OCTETSTRING& p__ecdsaNistp256PublicKeyCompressed,
                                                      const INTEGER& p__compressedMode
                                                      ) {
    // Sanity checks
    if ((p__signature.lengthof() != 64) || (p__ecdsaNistp256PublicKeyCompressed.lengthof() != 32)) {
      loggers::get_instance().log("fx__test__verifyWithEcdsaNistp256WithSha256: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    loggers::get_instance().log_msg("fx__test__verifyWithEcdsaNistp256WithSha256: Hash (Data input)=", hashData1);
    // Check the signature
    security_ecc k(ec_elliptic_curves::nist_p_256, p__ecdsaNistp256PublicKeyCompressed, (p__compressedMode == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (k.sign_verif(hashData1, p__signature) == 0) {
      return TRUE;
    }

    return FALSE;
  }
  
  /**
   * \fn BOOLEAN fx__verifyWithEcdsaNistp256WithSha256_1(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaNistp256PublicKeyX, const OCTETSTRING& p__ecdsaNistp256PublicKeyY);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaNistp256PublicKeyX The public key (x coordinate)
   * \param[in] p__ecdsaNistp256PublicKeyY The public key (y coordinate)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaNistp256WithSha256__1(
                                                   const OCTETSTRING& p__toBeVerifiedData,
                                                   const OCTETSTRING& p__certificateIssuer,
                                                   const OCTETSTRING& p__signature,
                                                   const OCTETSTRING& p__ecdsaNistp256PublicKeyX,
                                                   const OCTETSTRING& p__ecdsaNistp256PublicKeyY
                                                   ) {
    // Sanity checks
Yann Garcia's avatar
Yann Garcia committed
    if ((p__certificateIssuer.lengthof() != 32) || (p__signature.lengthof() != 64) || (p__ecdsaNistp256PublicKeyX.lengthof() != 32) || (p__ecdsaNistp256PublicKeyY.lengthof() != 32)) {
      loggers::get_instance().log("fx__verifyWithEcdsaNistp256WithSha256__1: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256__1: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256__1: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaNistp256WithSha256__1: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::nist_p_256, p__ecdsaNistp256PublicKeyX, p__ecdsaNistp256PublicKeyY);
    //security_ecc k(ec_elliptic_curves::nist_p_256);
    if (k.sign_verif(hashData, p__signature) == 0) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * \fn BOOLEAN fx__verifyWithEcdsaBrainpoolp256WithSha256(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyCompressed);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaBrainpoolp256PublicKeyCompressed The compressed public key (x coordinate only)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaBrainpoolp256WithSha256(
                                                     const OCTETSTRING& p__toBeVerifiedData,
                                                     const OCTETSTRING& p__certificateIssuer,
                                                     const OCTETSTRING& p__signature,
                                                     const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyCompressed,
                                                     const INTEGER& p__compressedMode
                                                     ) {
    // Sanity checks
    if ((p__certificateIssuer.lengthof() != 32) || (p__signature.lengthof() != 64) || (p__ecdsaBrainpoolp256PublicKeyCompressed.lengthof() != 32)) {
      loggers::get_instance().log("fx__verifyWithEcdsaBrainpoolp256WithSha256: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_256_r1, p__ecdsaBrainpoolp256PublicKeyCompressed, (p__compressedMode == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (k.sign_verif(hashData, p__signature) == 0) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * \fn BOOLEAN fx__verifyWithEcdsaBrainpoolp256WithSha256_1(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyX, const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyY);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaBrainpoolp256PublicKeyX The public key (x coordinate)
   * \param[in] p__ecdsaBrainpoolp256PublicKeyY The public key (y coordinate)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaBrainpoolp256WithSha256__1(
                                                        const OCTETSTRING& p__toBeVerifiedData,
                                                        const OCTETSTRING& p__certificateIssuer,
                                                        const OCTETSTRING& p__signature,
                                                        const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyX,
                                                        const OCTETSTRING& p__ecdsaBrainpoolp256PublicKeyY
                                                        ) {
    // Sanity checks
Yann Garcia's avatar
Yann Garcia committed
    if ((p__certificateIssuer.lengthof() != 32) || (p__signature.lengthof() != 64) || (p__ecdsaBrainpoolp256PublicKeyX.lengthof() != 32) || (p__ecdsaBrainpoolp256PublicKeyY.lengthof() != 32)) {
      loggers::get_instance().log("fx__verifyWithEcdsaBrainpoolp256WithSha256__1: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA256 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha256 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha256_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256__1: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256__1: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp256WithSha256__1: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_256_r1, p__ecdsaBrainpoolp256PublicKeyX, p__ecdsaBrainpoolp256PublicKeyY);
    if (k.sign_verif(hashData, p__signature) == 0) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * \fn BOOLEAN fx__verifyWithEcdsaBrainpoolp384WithSha384(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyCompressed);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaBrainpoolp384PublicKeyCompressed The compressed public key (x coordinate only)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaBrainpoolp384WithSha384(
                                                     const OCTETSTRING& p__toBeVerifiedData,
                                                     const OCTETSTRING& p__certificateIssuer,
                                                     const OCTETSTRING& p__signature,
                                                     const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyCompressed,
                                                     const INTEGER& p__compressedMode
                                                     ) {
    // Sanity checks
    if ((p__certificateIssuer.lengthof() != 48) || (p__signature.lengthof() != 96) || (p__ecdsaBrainpoolp384PublicKeyCompressed.lengthof() != 48)) {
      loggers::get_instance().log("fx__verifyWithEcdsaBrainpoolp384WithSha384: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA384 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha384 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 48)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha384_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_384_r1, p__ecdsaBrainpoolp384PublicKeyCompressed, (p__compressedMode == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (k.sign_verif(hashData, p__signature) == 0) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * \fn BOOLEAN fx__verifyWithEcdsaBrainpoolp384WithSha384_1(const OCTETSTRING& p__toBeVerifiedData, const OCTETSTRING& p__signature, const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyX, const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyY);
Yann Garcia's avatar
Yann Garcia committed
   * \brief Verify the signature of the specified data based on standard IEEE 1609.2
   * \param[in] p__toBeVerifiedData The data to be verified
   * \param[in] p__certificateIssuer The whole-hash issuer certificate or int2oct(0, 32) in case of self signed certificate
   * \param[in] p__signature The signature
   * \param[in] p__ecdsaBrainpoolp384PublicKeyX The public key (x coordinate)
   * \param[in] p__ecdsaBrainpoolp384PublicKeyY The public key (y coordinate)
   * \return true on success, false otherwise
   */
  BOOLEAN fx__verifyWithEcdsaBrainpoolp384WithSha384__1(
                                                        const OCTETSTRING& p__toBeVerifiedData,
                                                        const OCTETSTRING& p__certificateIssuer,
                                                        const OCTETSTRING& p__signature,
                                                        const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyX,
                                                        const OCTETSTRING& p__ecdsaBrainpoolp384PublicKeyY
                                                        ) {
    // Sanity checks
Yann Garcia's avatar
Yann Garcia committed
    if ((p__certificateIssuer.lengthof() != 48) || (p__signature.lengthof() != 96) || (p__ecdsaBrainpoolp384PublicKeyX.lengthof() != 48) || (p__ecdsaBrainpoolp384PublicKeyY.lengthof() != 48)) {
      loggers::get_instance().log("fx__verifyWithEcdsaBrainpoolp384WithSha384__1: Wrong parameters");
      return FALSE;
    }

    // Calculate the SHA384 of the hashed data for signing: Hash ( Hash (Data input) || Hash (Signer identifier input) )
    sha384 hash;
    OCTETSTRING hashData1; // Hash (Data input)
    hash.generate(p__toBeVerifiedData, hashData1);
    OCTETSTRING hashData2; // Hash (Signer identifier input)
    if (p__certificateIssuer != int2oct(0, 32)) { // || Hash (Signer identifier input)
      hashData2 = p__certificateIssuer;
    } else {
      hashData2 = hash.get_sha384_empty_string(); // Hash of empty string
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash (Data input)=", hashData1);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash (Signer identifier input)=", hashData2);
    hashData1 += hashData2; // Hash (Data input) || Hash (Signer identifier input)
    OCTETSTRING hashData; // Hash ( Hash (Data input) || Hash (Signer identifier input) )
    hash.generate(hashData1, hashData);
    loggers::get_instance().log_msg("fx__verifyWithEcdsaBrainpoolp384WithSha384: Hash ( Hash (Data input) || Hash (Signer identifier input) )=", hashData);
    // Check the signature
    security_ecc k(ec_elliptic_curves::brainpool_p_384_r1, p__ecdsaBrainpoolp384PublicKeyX, p__ecdsaBrainpoolp384PublicKeyY);
    if (k.sign_verif(hashData, p__signature) == 0) {
Yann Garcia's avatar
Yann Garcia committed
   * \fn OCTETSTRING fx__hmac__sha256(const OCTETSTRING& p__k, const OCTETSTRING& p__m);
   * \brief Generate a HMAC-SHA256 value based on the provided secret key
   * \param[in] p__k The secret key used for the HMAC calculation
   * \param[in] p__m The message
   * \return The HMAC value resized to 16-byte
   */
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__hmac__sha256(const OCTETSTRING& p__k, const OCTETSTRING& p__m) {
    loggers::get_instance().log(">>> fx__hmac__sha256");

    hmac h(hash_algorithms::sha_256); // TODO Use ec_encryption_algorithm
    OCTETSTRING t;
    if (h.generate(p__m, p__k, t) == -1) {
Yann Garcia's avatar
Yann Garcia committed
      loggers::get_instance().warning("fx__hmac__sha256: Failed to generate HMAC");
      return OCTETSTRING(0, nullptr);
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg("fx__hmac__sha256: HMAC: ", t);
Yann Garcia's avatar
Yann Garcia committed
   * \fn OCTETSTRING fx__encrypt__aes__128__ccm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__pt);
   * \brief Encrypt the message using AES 128 CCM algorithm
   * \param[in] p__k The symmetric encryption key
   * \param[in] p__n The initial vector, nonce vector
   * \param[in] p__pt The message to encrypt
   * \return The encrypted message concatenated to the AES 128 CCM tag
   */
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__encrypt__aes__128__ccm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__pt) {
    loggers::get_instance().log(">>> fx__encrypt__aes__128__ccm__test");
    
    security_ecc ec(ec_elliptic_curves::nist_p_256);
    OCTETSTRING enc_message;
    if (ec.encrypt(encryption_algotithm::aes_128_ccm, p__k, p__n, p__pt, enc_message) == -1) {
Yann Garcia's avatar
Yann Garcia committed
      loggers::get_instance().warning("fx__encrypt__aes__128__ccm__test: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    OCTETSTRING os(enc_message + ec.tag());
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg("fx__encrypt__aes__128__ccm__test: encrypted message: ", os);
Yann Garcia's avatar
Yann Garcia committed
  /**
   * \fn OCTETSTRING fx__encrypt__aes__128__gcm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__pt);
   * \brief Encrypt the message using AES 128 GCM algorithm
   * \param[in] p__k The symmetric encryption key
   * \param[in] p__n The initial vector, nonce vector
   * \param[in] p__pt The message to encrypt
   * \return The encrypted message concatenated to the AES 128 CCM tag
   */
  OCTETSTRING fx__encrypt__aes__128__gcm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__pt) {
    loggers::get_instance().log(">>> fx__encrypt__aes__128__gcm__test");
    
    security_ecc ec(ec_elliptic_curves::nist_p_256);
    OCTETSTRING enc_message;
    if (ec.encrypt(encryption_algotithm::aes_128_gcm, p__k, p__n, p__pt, enc_message) == -1) {
Yann Garcia's avatar
Yann Garcia committed
      loggers::get_instance().warning("fx__encrypt__aes__128__gcm__test: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    }
    OCTETSTRING os(enc_message + ec.tag());
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg("fx__encrypt__aes__128__gcm__test: encrypted message: ", os);
Yann Garcia's avatar
Yann Garcia committed
   * \fn OCTETSTRING fx__decrypt__aes__128__ccm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__ct);
   * \brief Encrypt the message using AES 128 CCM algorithm
   * \param[in] p__k The symmetric encryption key
   * \param[in] p__n The initial vector, nonce vector
   * \param[in] p__ct The encrypted message concatenated to the AES 128 CCM tag
   * \return The original message
   */
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__decrypt__aes__128__ccm__test(const OCTETSTRING& p__k, const OCTETSTRING& p__n, const OCTETSTRING& p__ct) {
    loggers::get_instance().log_msg(">>> fx__decrypt__aes__128__ccm__test: p__k: ", p__k);
    loggers::get_instance().log_msg(">>> fx__decrypt__aes__128__ccm__test: p__n: ", p__n);
    loggers::get_instance().log_msg(">>> fx__decrypt__aes__128__ccm__test: p__ct: ", p__ct);
    
    security_ecc ec(ec_elliptic_curves::nist_p_256);
    // Extract the tag
    OCTETSTRING tag(16, p__ct.lengthof() - 16 + static_cast<const unsigned char*>(p__ct));
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg("fx__decrypt__aes__128__ccm__test: tag: ", tag);
    // Remove the tag from the end of the encrypted message
    OCTETSTRING ct(p__ct.lengthof() - 16, static_cast<const unsigned char*>(p__ct));
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg("fx__decrypt__aes__128__ccm__test: ct: ", ct);
    if (ec.decrypt(encryption_algotithm::aes_128_ccm, p__k, p__n, tag, ct, message) == -1) {
Yann Garcia's avatar
Yann Garcia committed
      loggers::get_instance().warning("fx__decrypt__aes__128__ccm__test: Failed to decrypt message");
      return OCTETSTRING(0, nullptr);
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_to_hexa("fx__decrypt__aes__128__ccm__test: decrypted message: ", message);
  }
  
  /**
   * \fn OCTETSTRING fx__encryptWithEciesNistp256WithSha256(const OCTETSTRING& p__toBeEncryptedSecuredMessage, const OCTETSTRING& p__recipientsPublicKeyX, const OCTETSTRING& p__recipientsPublicKeyY, OCTETSTRING& p__publicEphemeralKeyX, OCTETSTRING& p__publicEphemeralKeyY, OCTETSTRING& p__encrypted__sym__key, OCTETSTRING& p__authentication__vector, OCTETSTRING& p__nonce);
   * \brief Encrypt the message using ECIES algorithm to encrypt AES 128 CCM symmetric key, as defined in IEEE Std 1609.2-2017
   * \param[in] p__toBeEncryptedSecuredMessage The message to be encrypted
   * \param[in] p__recipientsPublicKeyCompressed The Recipient's compressed public key
   * \param[in] p__compressedMode The compressed mode, 0 if the latest bit of Y-coordinate is 0, 1 otherwise
   * \param[out] p__publicEphemeralKeyCompressed The public ephemeral compressed key
   * \param[out] p__ephemeralCompressedMode The compressed mode, 0 if the latest bit of Y-coordinate is 0, 1 otherwise
   * \param[out] p__encrypted__sym__key The encrypted AES 128 symmetric key
   * \param[out] p__authentication__vector The tag of the encrypted AES 128 symmetric key
   * \param[out] p__nonce The nonce vector
   * \param[in] p__use__hardcoded__values In debug mode, set to true to use hardcoded values
   * \return The original message
   * \see IEEE Std 1609.2-2017 Clause 5.3.5 Public key encryption algorithms: ECIES
   * \see https://www.nominet.uk/researchblog/how-elliptic-curve-cryptography-encryption-works/
   * \see http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf
   */
  // TODO Use common function for both fx__encryptWithEciesxxx and fx__decryptWithEciesxxx function
  OCTETSTRING fx__encryptWithEciesNistp256WithSha256(const OCTETSTRING& p__toBeEncryptedSecuredMessage, const OCTETSTRING& p__recipientsPublicKeyCompressed, const INTEGER& p__compressedMode, const OCTETSTRING& p__salt, OCTETSTRING& p__publicEphemeralKeyCompressed, INTEGER& p__ephemeralCompressedMode,OCTETSTRING& p__aes__sym__key, OCTETSTRING& p__encrypted__sym__key, OCTETSTRING& p__authentication__vector, OCTETSTRING& p__nonce, const BOOLEAN& p__use__hardcoded__values) {
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesNistp256WithSha256: p__toBeEncryptedSecuredMessage: ", p__toBeEncryptedSecuredMessage);
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesNistp256WithSha256: p__recipientsPublicKeyCompressed: ", p__recipientsPublicKeyCompressed);
    loggers::get_instance().log(">>> fx__encryptWithEciesNistp256WithSha256: p__compressedMode: %d", static_cast<int>(p__compressedMode));
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesNistp256WithSha256: p__salt: ", p__salt);
    loggers::get_instance().log(">>> fx__encryptWithEciesNistp256WithSha256: p__use__hardcoded__values: %x", static_cast<const boolean>(p__use__hardcoded__values));
    // 1. Generate new Private/Public Ephemeral key
    std::unique_ptr<security_ecc> ec;
    if (!static_cast<const boolean>(p__use__hardcoded__values)) {
      ec.reset(new security_ecc(ec_elliptic_curves::nist_p_256));
      if (ec->generate() == -1) {
        loggers::get_instance().warning("fx__encryptWithEciesNistp256WithSha256: Failed to generate ephemeral keys");
        return OCTETSTRING(0, nullptr);
      }
    } else {
      ec.reset(new security_ecc(ec_elliptic_curves::nist_p_256, str2oct("0722B39ABC7B6C5301CA0408F454F81553D7FE59F492DBF385B6B6D1F81E0F68"))); // Hardcoded private key
    // 2. Generate and derive shared secret based on recipient's private keys
    security_ecc ec_comp(ec_elliptic_curves::nist_p_256, p__recipientsPublicKeyCompressed, (static_cast<int>(p__compressedMode) == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (static_cast<const boolean>(p__use__hardcoded__values)) { // Set AES encryption key to an harcoded value
      ec->symmetric_encryption_key(str2oct("5A4E63B247C714644E85CAC49BD26C81"));
    }
    if (ec->generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__salt) == -1) {
      loggers::get_instance().warning("fx__encryptWithEciesNistp256WithSha256: Failed to generate and derive secret key");
      return OCTETSTRING(0, nullptr);
    
    // Set the AES symmetric key
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: AES symmetric key: ", ec->symmetric_encryption_key());
    p__aes__sym__key = ec->symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: p__aes__sym__key: ", p__aes__sym__key);
    // Set the encrypted symmetric key
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: Encrypted symmetric key: ", ec->encrypted_symmetric_key());
    p__encrypted__sym__key = ec->encrypted_symmetric_key();
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
    // Set the tag of the symmetric key encryption
    p__authentication__vector = ec->tag();
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    // Set ephemeral public keys
    p__publicEphemeralKeyCompressed = ec->public_key_compressed();
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: Ephemeral public compressed key: ", p__publicEphemeralKeyCompressed);
    p__ephemeralCompressedMode = (ec->public_key_compressed_mode() == ecc_compressed_mode::compressed_y_0) ? 0 : 1;
    loggers::get_instance().log("fx__encryptWithEciesNistp256WithSha256: Ephemeral public compressed mode: %d: ", p__ephemeralCompressedMode);
    // 3. Retrieve AES 128 parameters
    p__nonce = ec->nonce();
    loggers::get_instance().log_msg("fx__encryptWithEciesNistp256WithSha256: p__nonce: ", p__nonce);
    // 4. Encrypt the data using AES-128 CCM
    OCTETSTRING enc_message;
    if (ec->encrypt(encryption_algotithm::aes_128_ccm, ec->symmetric_encryption_key(), ec->nonce(), p__toBeEncryptedSecuredMessage, enc_message) == -1) {
      loggers::get_instance().warning("fx__encryptWithEciesNistp256WithSha256: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    enc_message += ec->tag();
    loggers::get_instance().log_to_hexa("fx__encryptWithEciesNistp256WithSha256: enc message||Tag: ", enc_message);
  /**
   * @desc Test function for ECIES NIST P-256 Encryption with SHA-256
   * @remark For the purpose of testing, the content of p__toBeEncryptedSecuredMessage is the AES 128 symmetric key to be encrypted
   */
  OCTETSTRING fx__test__encryptWithEciesNistp256WithSha256(const OCTETSTRING& p__toBeEncryptedSecuredMessage, const OCTETSTRING& p__privateEphemeralKey, const OCTETSTRING& p__recipientPublicKeyX, const OCTETSTRING& p__recipientPublicKeyY, const OCTETSTRING& p__salt, OCTETSTRING& p__publicEphemeralKeyX, OCTETSTRING& p__publicEphemeralKeyY, OCTETSTRING& p__aes__sym__key, OCTETSTRING& p__encrypted__sym__key, OCTETSTRING& p__authentication__vector, OCTETSTRING& p__nonce) {
    
    // 1. Generate new ephemeral Private/Public keys
    security_ecc ec(ec_elliptic_curves::nist_p_256, p__privateEphemeralKey);
    p__publicEphemeralKeyX = ec.public_key_x();
    p__publicEphemeralKeyY = ec.public_key_y();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: Vx=", p__publicEphemeralKeyX);
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: Vy=", p__publicEphemeralKeyY);
    
    // 2. Generate and derive shared secret
    security_ecc ec_comp(ec_elliptic_curves::nist_p_256, p__recipientPublicKeyX, p__recipientPublicKeyY);
    ec.symmetric_encryption_key(p__toBeEncryptedSecuredMessage);
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: ", ec.encrypted_symmetric_key());
    if (ec.generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__salt) == -1) {
      loggers::get_instance().warning("fx__test__encryptWithEciesNistp256WithSha256: Failed to generate and derive secret key");
      return OCTETSTRING(0, nullptr);
    }
    
    // Set the AES symmetric key
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: AES symmetric key: ", ec.symmetric_encryption_key());
    p__aes__sym__key = ec.symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: p__aes__sym__key: ", p__aes__sym__key);
    // Set the encrypted symmetric key
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: Encrypted symmetric key: ", ec.encrypted_symmetric_key());
    p__encrypted__sym__key = ec.encrypted_symmetric_key();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
    // Set the tag of the symmetric key encryption
    p__authentication__vector = ec.tag();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    // 3. Retrieve AES 128 parameters
    p__nonce = ec.nonce();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesNistp256WithSha256: p__nonce: ", p__nonce);
    // 4. Encrypt the data using AES-128 CCM
    OCTETSTRING enc_message;
    if (ec.encrypt(encryption_algotithm::aes_128_ccm, ec.symmetric_encryption_key(), ec.nonce(), p__toBeEncryptedSecuredMessage, enc_message) == -1) {
      loggers::get_instance().warning("fx__test__encryptWithEciesNistp256WithSha256: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    }
    enc_message += ec.tag();
    loggers::get_instance().log_to_hexa("fx__test__encryptWithEciesNistp256WithSha256: enc message||Tag: ", enc_message);
    
    return enc_message;
  }
  
  /**
   * \fn OCTETSTRING fx__decryptWithEciesNistp256WithSha256(const OCTETSTRING& p__encryptedSecuredMessage, const OCTETSTRING& p__privateEncKey, const OCTETSTRING& p__publicEphemeralKeyX, const OCTETSTRING& p__publicEphemeralKeyY, const OCTETSTRING& p__encrypted__sym__key, const OCTETSTRING& p__authentication__vector, const OCTETSTRING& p__nonce);
   * \brief Decrypt the message using ECIES algorithm to decrypt AES 128 CCM symmetric key, as defined in IEEE Std 1609.2-2017
   * \param[in] p__encryptedSecuredMessage The encrypted message
   * \param[in] p__privateEncKey The private encryption key
   * \param[in] p__publicEphemeralKeyCompressed The public ephemeral compressed key
   * \param[in] p__ephemeralCompressedMode The compressed mode, 0 if the latest bit of Y-coordinate is 0, 1 otherwise
   * \param[in] p__encrypted__sym__key The encrypted AES 128 symmetric key
   * \param[in] p__authentication__vector The tag of the encrypted AES 128 symmetric key
   * \param[in] p__nonce The nonce vector
   * \return The original message
   * \see IEEE Std 1609.2-2017 Clause 5.3.5 Public key encryption algorithms: ECIES
   * \see https://www.nominet.uk/researchblog/how-elliptic-curve-cryptography-encryption-works/
   * \see http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf
   */
  // TODO Use common function for both fx__encryptWithEciesxxx and fx__decryptWithEciesxxx function
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__decryptWithEciesNistp256WithSha256(const OCTETSTRING& p__encryptedSecuredMessage, const OCTETSTRING& p__privateEncKey, const OCTETSTRING& p__publicEphemeralKeyCompressed, const INTEGER& p__ephemeralCompressedMode, const OCTETSTRING& p__encrypted__sym__key, const OCTETSTRING& p__authentication__vector, const OCTETSTRING& p__nonce, const OCTETSTRING& p__salt, OCTETSTRING& p__aes__sym__enc__key) {
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__toBeEncryptedSecuredMessage: ", p__encryptedSecuredMessage);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__privateEncKey: ", p__privateEncKey);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__publicEphemeralKeyCompressed: ", p__publicEphemeralKeyCompressed);
    loggers::get_instance().log(">>> fx__decryptWithEciesNistp256WithSha256: p__ephemeralCompressedMode: %d", static_cast<int>(p__ephemeralCompressedMode));
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__nonce: ", p__nonce);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesNistp256WithSha256: p__salt", p__salt);
    // 1. Create security_ecc instance based on recipient's private key
    security_ecc ec(ec_elliptic_curves::nist_p_256, p__privateEncKey);
    security_ecc ec_comp(ec_elliptic_curves::nist_p_256, p__publicEphemeralKeyCompressed, (static_cast<int>(p__ephemeralCompressedMode) == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    // 2. Generate the shared secret value based on public ephemeral keys will be required
    if (ec.generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__encrypted__sym__key, p__nonce, p__authentication__vector, p__salt) == -1) {
      loggers::get_instance().warning("fx__decryptWithEciesNistp256WithSha256: Failed to generate shared secret");
      return OCTETSTRING(0, nullptr);
    }
    
    // Decrypt the message
    OCTETSTRING enc_message(p__encryptedSecuredMessage.lengthof() - ec.tag().lengthof(), static_cast<const unsigned char*>(p__encryptedSecuredMessage)); // Extract the encrypted message
    loggers::get_instance().log_msg("fx__decryptWithEciesNistp256WithSha256: enc_message: ", enc_message); // Extract the ctag value
    OCTETSTRING tag(ec.tag().lengthof(), static_cast<const unsigned char*>(p__encryptedSecuredMessage) + p__encryptedSecuredMessage.lengthof() - ec.tag().lengthof());
    loggers::get_instance().log_msg("fx__decryptWithEciesNistp256WithSha256: tag: ", tag);
    OCTETSTRING message;
    if (ec.decrypt(tag, enc_message, message) == -1) {
      loggers::get_instance().warning("fx__decryptWithEciesNistp256WithSha256: Failed to generate shared secret");
      return OCTETSTRING(0, nullptr);
    loggers::get_instance().log_msg("fx__decryptWithEciesNistp256WithSha256: dec message: ", message);
Yann Garcia's avatar
Yann Garcia committed
    p__aes__sym__enc__key = ec.symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__decryptWithEciesNistp256WithSha256: AES 128 encryption key: ", p__aes__sym__enc__key);
  OCTETSTRING fx__encryptWithEciesBrainpoolp256WithSha256(const OCTETSTRING& p__toBeEncryptedSecuredMessage, const OCTETSTRING& p__recipientsPublicKeyCompressed, const INTEGER& p__compressedMode, const OCTETSTRING& p__salt, OCTETSTRING& p__publicEphemeralKeyCompressed, INTEGER& p__ephemeralCompressedMode,OCTETSTRING& p__aes__sym__key, OCTETSTRING& p__encrypted__sym__key, OCTETSTRING& p__authentication__vector, OCTETSTRING& p__nonce, const BOOLEAN& p__use__hardcoded__values) {
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesBrainpoolp256WithSha256: p__toBeEncryptedSecuredMessage: ", p__toBeEncryptedSecuredMessage);
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesBrainpoolp256WithSha256: p__recipientsPublicKeyCompressed: ", p__recipientsPublicKeyCompressed);
    loggers::get_instance().log(">>> fx__encryptWithEciesBrainpoolp256WithSha256: p__compressedMode: %d", static_cast<int>(p__compressedMode));
    loggers::get_instance().log_msg(">>> fx__encryptWithEciesBrainpoolp256WithSha256: p__salt: ", p__salt);
    loggers::get_instance().log(">>> fx__encryptWithEciesBrainpoolp256WithSha256: p__use__hardcoded__values: %x", static_cast<const boolean>(p__use__hardcoded__values));
    
    // 1. Generate new Private/Public Ephemeral key
    std::unique_ptr<security_ecc> ec;
    if (!static_cast<const boolean>(p__use__hardcoded__values)) {
      ec.reset(new security_ecc(ec_elliptic_curves::brainpool_p_256_r1));
      if (ec->generate() == -1) {
        loggers::get_instance().warning("fx__encryptWithEciesBrainpoolp256WithSha256: Failed to generate ephemeral keys");
        return OCTETSTRING(0, nullptr);
      }
    } else {
      ec.reset(new security_ecc(ec_elliptic_curves::brainpool_p_256_r1, str2oct("0722B39ABC7B6C5301CA0408F454F81553D7FE59F492DBF385B6B6D1F81E0F68"))); // Hardcoded private key
    // 2. Generate and derive shared secret based on recipient's private keys
    security_ecc ec_comp(ec_elliptic_curves::brainpool_p_256_r1, p__recipientsPublicKeyCompressed, (static_cast<int>(p__compressedMode) == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    if (static_cast<const boolean>(p__use__hardcoded__values)) { // Set AES encryption key to an harcoded value
      ec->symmetric_encryption_key(str2oct("5A4E63B247C714644E85CAC49BD26C81"));
    }
    if (ec->generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__salt) == -1) {
      loggers::get_instance().warning("fx__encryptWithEciesBrainpoolp256WithSha256: Failed to generate and derive secret key");
      return OCTETSTRING(0, nullptr);
    // Set the AES symmetric key
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: AES symmetric key: ", ec->symmetric_encryption_key());
    p__aes__sym__key = ec->symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: p__aes__sym__key: ", p__aes__sym__key);
    // Set the encrypted symmetric key
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: Encrypted symmetric key: ", ec->encrypted_symmetric_key());
    p__encrypted__sym__key = ec->encrypted_symmetric_key();
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
    // Set the tag of the symmetric key encryption
    p__authentication__vector = ec->tag();
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    // Set ephemeral public keys
    p__publicEphemeralKeyCompressed = ec->public_key_compressed();
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: Ephemeral public compressed key: ", p__publicEphemeralKeyCompressed);
    p__ephemeralCompressedMode = (ec->public_key_compressed_mode() == ecc_compressed_mode::compressed_y_0) ? 0 : 1;
    loggers::get_instance().log("fx__encryptWithEciesBrainpoolp256WithSha256: Ephemeral public compressed mode: %d: ", p__ephemeralCompressedMode);
    // 3. Retrieve AES 128 parameters
    p__nonce = ec->nonce();
    loggers::get_instance().log_msg("fx__encryptWithEciesBrainpoolp256WithSha256: p__nonce: ", p__nonce);
    // 4. Encrypt the data using AES-128 CCM
    OCTETSTRING enc_message;
    if (ec->encrypt(encryption_algotithm::aes_128_ccm, ec->symmetric_encryption_key(), ec->nonce(), p__toBeEncryptedSecuredMessage, enc_message) == -1) {
      loggers::get_instance().warning("fx__encryptWithEciesBrainpoolp256WithSha256: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    enc_message += ec->tag();
    loggers::get_instance().log_to_hexa("fx__encryptWithEciesBrainpoolp256WithSha256: enc message||Tag: ", enc_message);
  /**
   * @desc Test function for ECIES BRAINPOOL P-256r1 Encryption with SHA-256
   * @remark For the purpose of testing, the content of p__toBeEncryptedSecuredMessage is the AES 128 symmetric key to be encrypted
   */
  OCTETSTRING fx__test__encryptWithEciesBrainpoolp256WithSha256(const OCTETSTRING& p__toBeEncryptedSecuredMessage, const OCTETSTRING& p__privateEphemeralKey, const OCTETSTRING& p__recipientPublicKeyX, const OCTETSTRING& p__recipientPublicKeyY, const OCTETSTRING& p__salt, OCTETSTRING& p__publicEphemeralKeyX, OCTETSTRING& p__publicEphemeralKeyY, OCTETSTRING& p__aes__sym__key, OCTETSTRING& p__encrypted__sym__key, OCTETSTRING& p__authentication__vector, OCTETSTRING& p__nonce) {
    
    // 1. Generate new ephemeral Private/Public keys
    security_ecc ec(ec_elliptic_curves::brainpool_p_256_r1, p__privateEphemeralKey);
    p__publicEphemeralKeyX = ec.public_key_x();
    p__publicEphemeralKeyY = ec.public_key_y();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: Vx=", p__publicEphemeralKeyX);
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: Vy=", p__publicEphemeralKeyY);
    
    // 2. Generate and derive shared secret
    security_ecc ec_comp(ec_elliptic_curves::brainpool_p_256_r1, p__recipientPublicKeyX, p__recipientPublicKeyY);
    ec.symmetric_encryption_key(p__toBeEncryptedSecuredMessage);
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: ", ec.encrypted_symmetric_key());
    if (ec.generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__salt) == -1) {
      loggers::get_instance().warning("fx__test__encryptWithEciesBrainpoolp256WithSha256: Failed to generate and derive secret key");
      return OCTETSTRING(0, nullptr);
    }
    
    // Set the AES symmetric key
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: AES symmetric key: ", ec.symmetric_encryption_key());
    p__aes__sym__key = ec.symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: p__aes__sym__key: ", p__aes__sym__key);
    // Set the encrypted symmetric key
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: Encrypted symmetric key: ", ec.encrypted_symmetric_key());
    p__encrypted__sym__key = ec.encrypted_symmetric_key();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
    // Set the tag of the symmetric key encryption
    p__authentication__vector = ec.tag();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    // 3. Retrieve AES 128 parameters
    p__nonce = ec.nonce();
    loggers::get_instance().log_msg("fx__test__encryptWithEciesBrainpoolp256WithSha256: p__nonce: ", p__nonce);
    // 4. Encrypt the data using AES-128 CCM
    OCTETSTRING enc_message;
    if (ec.encrypt(encryption_algotithm::aes_128_ccm, ec.symmetric_encryption_key(), ec.nonce(), p__toBeEncryptedSecuredMessage, enc_message) == -1) {
      loggers::get_instance().warning("fx__test__encryptWithEciesBrainpoolp256WithSha256: Failed to encrypt message");
      return OCTETSTRING(0, nullptr);
    }
    enc_message += ec.tag();
    loggers::get_instance().log_to_hexa("fx__test__encryptWithEciesBrainpoolp256WithSha256: enc message||Tag: ", enc_message);
    
    return enc_message;
  }
  
Yann Garcia's avatar
Yann Garcia committed
  OCTETSTRING fx__decryptWithEciesBrainpoolp256WithSha256(const OCTETSTRING& p__encryptedSecuredMessage, const OCTETSTRING& p__privateEncKey, const OCTETSTRING& p__publicEphemeralKeyCompressed, const INTEGER& p__ephemeralCompressedMode, const OCTETSTRING& p__encrypted__sym__key, const OCTETSTRING& p__authentication__vector, const OCTETSTRING& p__nonce, const OCTETSTRING& p__salt, OCTETSTRING& p__aes__sym__enc__key) {
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__toBeEncryptedSecuredMessage: ", p__encryptedSecuredMessage);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__privateEncKey: ", p__privateEncKey);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__publicEphemeralKeyCompressed: ", p__publicEphemeralKeyCompressed);
    loggers::get_instance().log(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__ephemeralCompressedMode: %d", static_cast<int>(p__ephemeralCompressedMode));
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__nonce: ", p__nonce);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__authentication__vector: ", p__authentication__vector);
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__encrypted__sym__key: ", p__encrypted__sym__key);
Yann Garcia's avatar
Yann Garcia committed
    loggers::get_instance().log_msg(">>> fx__decryptWithEciesBrainpoolp256WithSha256: p__salt", p__salt);
    // 1. Create security_ecc instance based on public ephemeral keys
    security_ecc ec(ec_elliptic_curves::brainpool_p_256_r1, p__privateEncKey);
    security_ecc ec_comp(ec_elliptic_curves::brainpool_p_256_r1, p__publicEphemeralKeyCompressed, (static_cast<int>(p__ephemeralCompressedMode) == 0) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1);
    // 2. Generate the shared secret value based on public ephemeral keys will be required
    if (ec.generate_and_derive_ephemeral_key(encryption_algotithm::aes_128_ccm, ec_comp.public_key_x(), ec_comp.public_key_y(), p__encrypted__sym__key, p__nonce, p__authentication__vector, OCTETSTRING(0, nullptr)) == -1) {
      loggers::get_instance().warning("fx__decryptWithEciesBrainpoolp256WithSha256: Failed to generate shared secret");
      return OCTETSTRING(0, nullptr);
    // Decrypt the message
    OCTETSTRING enc_message(p__encryptedSecuredMessage.lengthof() - ec.tag().lengthof(), static_cast<const unsigned char*>(p__encryptedSecuredMessage)); // Extract the encrypted message
    loggers::get_instance().log_msg("fx__decryptWithEciesBrainpoolp256WithSha256: enc_message: ", enc_message); // Extract the ctag value
    OCTETSTRING tag(ec.tag().lengthof(), static_cast<const unsigned char*>(p__encryptedSecuredMessage) + p__encryptedSecuredMessage.lengthof() - ec.tag().lengthof());
    loggers::get_instance().log_msg("fx__decryptWithEciesBrainpoolp256WithSha256: tag: ", tag);
    OCTETSTRING message;
    if (ec.decrypt(tag, enc_message, message) == -1) {
      loggers::get_instance().warning("fx__decryptWithEciesBrainpoolp256WithSha256: Failed to generate shared secret");
      return OCTETSTRING(0, nullptr);
    loggers::get_instance().log_msg("fx__decryptWithEciesBrainpoolp256WithSha256: dec message: ", message);
Yann Garcia's avatar
Yann Garcia committed
    p__aes__sym__enc__key = ec.symmetric_encryption_key();
    loggers::get_instance().log_msg("fx__decryptWithEciesBrainpoolp256WithSha256: AES 128 encryption key: ", p__aes__sym__enc__key);