Add algorithm param validation
[platform/core/security/key-manager.git] / src / manager / crypto / sw-backend / internals.cpp
index d121118..8612631 100644 (file)
  */
 #include <exception>
 #include <fstream>
+#include <utility>
+#include <algorithm>
 
-#include <openssl/x509_vfy.h>
 #include <openssl/evp.h>
 #include <openssl/obj_mac.h>
 #include <openssl/ec.h>
 #include <openssl/dsa.h>
-#include <openssl/dh.h>
 #include <openssl/rsa.h>
 #include <openssl/bio.h>
 #include <openssl/rand.h>
 #include <openssl/obj_mac.h>
 
 #include <ckm/ckm-error.h>
-#include <ckm/ckm-type.h>
-#include <key-impl.h>
 #include <assert.h>
 #include <dpl/log/log.h>
 
 #include <generic-backend/exception.h>
+#include <generic-backend/algo-validation.h>
 #include <sw-backend/internals.h>
+#include <sw-backend/crypto.h>
 
 #define OPENSSL_SUCCESS 1       // DO NOTCHANGE THIS VALUE
 #define OPENSSL_FAIL    0       // DO NOTCHANGE THIS VALUE
 #define DEV_HW_RANDOM_FILE    "/dev/hwrng"
 #define DEV_URANDOM_FILE    "/dev/urandom"
 
-namespace {
-typedef std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> EvpMdCtxUPtr;
-typedef std::unique_ptr<EVP_PKEY_CTX, std::function<void(EVP_PKEY_CTX*)>> EvpPkeyCtxUPtr;
-} // anonymous namespace
-
 namespace CKM {
 namespace Crypto {
 namespace SW {
 namespace Internals {
 
+namespace {
+typedef std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> EvpMdCtxUPtr;
+typedef std::unique_ptr<EVP_PKEY_CTX, std::function<void(EVP_PKEY_CTX*)>> EvpPkeyCtxUPtr;
+typedef std::unique_ptr<EVP_PKEY, std::function<void(EVP_PKEY*)>> EvpPkeyUPtr;
+
+typedef std::unique_ptr<BIO, std::function<void(BIO*)>> BioUniquePtr;
+typedef int(*I2D_CONV)(BIO*, EVP_PKEY*);
+
+const size_t DEFAULT_AES_GCM_TAG_LEN = 128; // tag length in bits according to W3C Crypto API
+const size_t DEFAULT_AES_IV_LEN = 16; // default iv size in bytes for AES
+
+RawBuffer i2d(I2D_CONV fun, EVP_PKEY* pkey) {
+    BioUniquePtr bio(BIO_new(BIO_s_mem()), BIO_free_all);
+
+    if (NULL == pkey) {
+        ThrowErr(Exc::Crypto::InternalError, "attempt to parse an empty key!");
+    }
+
+    if (NULL == bio.get()) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in memory allocation! Function: BIO_new.");
+    }
+
+    if (1 != fun(bio.get(), pkey)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in conversion EVP_PKEY to DER");
+    }
+
+    RawBuffer output(8196);
+
+    int size = BIO_read(bio.get(), output.data(), output.size());
+
+    if (size <= 0) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in BIO_read: ", size);
+    }
+
+    output.resize(size);
+    return output;
+}
+
+// encryption / decryption
+typedef ParamCheck<ParamName::ALGO_TYPE,
+                   AlgoType,
+                   true,
+                   Type<AlgoType>::Equals<AlgoType::AES_CTR,
+                                          AlgoType::AES_CBC,
+                                          AlgoType::AES_GCM,
+                                          AlgoType::AES_CFB,
+                                          AlgoType::RSA_OAEP>> IsEncryption;
+
+typedef ParamCheck<ParamName::ED_IV,
+                   RawBuffer,
+                   true,
+                   Type<size_t>::Equals<DEFAULT_AES_IV_LEN>,
+                   BufferSizeGetter> IvSizeCheck;
+
+typedef ParamCheck<ParamName::ED_CTR_LEN,
+                   int,
+                   false,
+                   Type<int>::Equals<128>> CtrLenCheck;
+
+typedef ParamCheck<ParamName::ED_IV,
+                   RawBuffer,
+                   true,
+                   DefaultValidator<size_t>,
+                   BufferSizeGetter> GcmIvCheck;
+
+typedef ParamCheck<ParamName::ED_TAG_LEN,
+                   int,
+                   false,
+                   Type<int>::Equals<32, 64, 96, 104, 112, 120, 128>> GcmTagCheck;
+
+// sign / verify
+typedef ParamCheck<ParamName::ALGO_TYPE,
+                   AlgoType,
+                   false,
+                   Type<AlgoType>::Equals<AlgoType::RSA_SV,
+                                          AlgoType::DSA_SV,
+                                          AlgoType::ECDSA_SV>> IsSignVerify;
+
+typedef ParamCheck<ParamName::SV_HASH_ALGO,
+                   HashAlgorithm,
+                   false,
+                   Type<HashAlgorithm>::Equals<HashAlgorithm::NONE,
+                                               HashAlgorithm::SHA1,
+                                               HashAlgorithm::SHA256,
+                                               HashAlgorithm::SHA384,
+                                               HashAlgorithm::SHA512>> HashAlgoCheck;
+
+typedef ParamCheck<ParamName::SV_RSA_PADDING,
+                   RSAPaddingAlgorithm,
+                   false,
+                   Type<RSAPaddingAlgorithm>::Equals<RSAPaddingAlgorithm::NONE,
+                                                     RSAPaddingAlgorithm::PKCS1,
+                                                     RSAPaddingAlgorithm::X931>> RsaPaddingCheck;
+
+// key generation
+typedef ParamCheck<ParamName::ALGO_TYPE,
+                   AlgoType,
+                   true,
+                   Type<AlgoType>::Equals<AlgoType::RSA_GEN,
+                                          AlgoType::DSA_GEN,
+                                          AlgoType::ECDSA_GEN>> IsAsymGeneration;
+
+typedef ParamCheck<ParamName::ALGO_TYPE,
+                   AlgoType,
+                   true,
+                   Type<AlgoType>::Equals<AlgoType::AES_GEN>> IsSymGeneration;
+
+typedef ParamCheck<ParamName::GEN_KEY_LEN,
+                   int,
+                   true,
+                   Type<int>::Equals<1024, 2048, 4096>> RsaKeyLenCheck;
+
+typedef ParamCheck<ParamName::GEN_KEY_LEN,
+                   int,
+                   true,
+                   Type<int>::Equals<1024, 2048, 3072, 4096>> DsaKeyLenCheck;
+
+typedef ParamCheck<ParamName::GEN_KEY_LEN,
+                   int,
+                   true,
+                   Type<int>::Equals<128, 192, 256>> AesKeyLenCheck;
+
+typedef ParamCheck<ParamName::GEN_EC,
+                   ElipticCurve,
+                   true,
+                   Type<ElipticCurve>::Equals<ElipticCurve::prime192v1,
+                                              ElipticCurve::prime256v1,
+                                              ElipticCurve::secp384r1>> EcdsaEcCheck;
+
+typedef std::map<AlgoType, ValidatorVector> ValidatorMap;
+ValidatorMap initValidators() {
+    ValidatorMap validators;
+    validators.emplace(AlgoType::RSA_SV, VBuilder<HashAlgoCheck, RsaPaddingCheck>::Build());
+    validators.emplace(AlgoType::RSA_SV, VBuilder<HashAlgoCheck, RsaPaddingCheck>::Build());
+    validators.emplace(AlgoType::DSA_SV, VBuilder<HashAlgoCheck>::Build());
+    validators.emplace(AlgoType::ECDSA_SV, VBuilder<HashAlgoCheck>::Build());
+    validators.emplace(AlgoType::RSA_GEN, VBuilder<RsaKeyLenCheck>::Build());
+    validators.emplace(AlgoType::DSA_GEN, VBuilder<DsaKeyLenCheck>::Build());
+    validators.emplace(AlgoType::ECDSA_GEN, VBuilder<EcdsaEcCheck>::Build());
+    validators.emplace(AlgoType::AES_GEN, VBuilder<AesKeyLenCheck>::Build());
+    validators.emplace(AlgoType::AES_CTR, VBuilder<IvSizeCheck, CtrLenCheck>::Build());
+    validators.emplace(AlgoType::AES_CBC, VBuilder<IvSizeCheck>::Build());
+    validators.emplace(AlgoType::AES_CFB, VBuilder<IvSizeCheck>::Build());
+    validators.emplace(AlgoType::AES_GCM, VBuilder<GcmIvCheck, GcmTagCheck>::Build());
+    return validators;
+};
+ValidatorMap g_validators = initValidators();
+
+template <typename TypeCheck>
+void validateParams(const CryptoAlgorithm& ca)
+{
+    // check algorithm type (Encryption/Decryption, Sign/Verify, Key generation)
+    TypeCheck tc;
+    tc.Check(ca);
+
+    AlgoType at = unpack<AlgoType>(ca, ParamName::ALGO_TYPE);
+    for(const auto& validator : g_validators.at(at)) {
+        validator->Check(ca);
+    }
+}
+
+} // anonymous namespace
+
 int initialize() {
     int hw_rand_ret = 0;
     int u_rand_ret = 0;
@@ -77,8 +235,7 @@ int initialize() {
         hw_rand_ret = RAND_load_file(DEV_URANDOM_FILE, 32);
 
         if(hw_rand_ret != 32) {
-            LogError("Error in U_RAND_file_load");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in U_RAND_file_load");
+            ThrowErr(Exc::Crypto::InternalError, "Error in U_RAND_file_load");
         }
     }
 
@@ -104,8 +261,7 @@ const EVP_MD *getMdAlgo(const HashAlgorithm hashAlgo) {
          md_algo = EVP_sha512();
          break;
     default:
-        LogError("Error in hashAlgorithm value");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in hashAlgorithm value");
+        ThrowErr(Exc::Crypto::InternalError, "Error in hashAlgorithm value");
     }
     return md_algo;
 }
@@ -123,204 +279,101 @@ int getRsaPadding(const RSAPaddingAlgorithm padAlgo) {
         rsa_padding = RSA_X931_PADDING;
         break;
     default:
-        LogError("Error in RSAPaddingAlgorithm value");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in RSAPaddingAlgorithm value");
+        ThrowErr(Exc::Crypto::InternalError, "Error in RSAPaddingAlgorithm value");
     }
     return rsa_padding;
 }
 
-void createKeyPairRSA(const int size, // size in bits [1024, 2048, 4096]
-        KeyImpl &createdPrivateKey,  // returned value
-        KeyImpl &createdPublicKey)  // returned value
+TokenPair createKeyPairRSA(CryptoBackend backendId, const int size)
 {
-    EVP_PKEY_CTX *ctx = NULL;
-    EVP_PKEY *pkey = NULL;
-    EVP_PKEY *pparam = NULL;
+    EvpPkeyUPtr pkey;
 
     // check the parameters of functions
-    if(size != 1024 && size !=2048 && size != 4096) {
-        LogError("Error in RSA input size");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in RSA input size");
+    if(size!=1024 && size!=2048 && size!=4096) {
+        ThrowErr(Exc::Crypto::InputParam, "Error in RSA input size");
     }
 
-    // check the parameters of functions
-    if(&createdPrivateKey == NULL) {
-        LogError("Error in createdPrivateKey value");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in createdPrivateKey value");
+    EvpPkeyCtxUPtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL), EVP_PKEY_CTX_free);
+    if(!ctx) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new_id function !!");
     }
 
-    // check the parameters of functions
-    if(&createdPublicKey == NULL) {
-        LogError("Error in createdPrivateKey value");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in createdPublicKey value");
+    if(EVP_PKEY_keygen_init(ctx.get()) <= 0) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen_init function !!");
     }
 
-    Try {
-        if(!(ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL))) {
-            LogError("Error in EVP_PKEY_CTX_new_id function !!");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new_id function !!");
-        }
+    if(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), size) <= 0) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_rsa_keygen_bits function !!");
+    }
 
-        if(EVP_PKEY_keygen_init(ctx) <= 0) {
-            LogError("Error in EVP_PKEY_keygen_init function !!");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen_init function !!");
-        }
+    EVP_PKEY *pkeyTmp = NULL;
+    if(!EVP_PKEY_keygen(ctx.get(), &pkeyTmp)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen function !!");
+    }
+    pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
 
-        if(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx,size) <= 0) {
-            LogError("Error in EVP_PKEY_CTX_set_rsa_keygen_bits function !!");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_rsa_keygen_bits function !!");
-        }
+    return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_RSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
+                                        Token(backendId, DataType(KeyType::KEY_RSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
+}
 
-        if(!EVP_PKEY_keygen(ctx, &pkey)) {
-            LogError("Error in EVP_PKEY_keygen function !!");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen function !!");
-        }
-    } Catch(Crypto::Exception::InternalError) {
-        if(pkey) {
-            EVP_PKEY_free(pkey);
-        }
 
-        if(pparam) {
-            EVP_PKEY_free(pparam);
-        }
+TokenPair createKeyPairDSA(CryptoBackend backendId, const int size)
+{
+    EvpPkeyUPtr pkey;
+    EvpPkeyUPtr pparam;
 
-        if(ctx) {
-            EVP_PKEY_CTX_free(ctx);
-        }
+    // check the parameters of functions
+    if(size!=1024 && size!=2048 && size!=3072 && size!=4096) {
+        ThrowErr(Exc::Crypto::InputParam, "Error in DSA input size");
+    }
 
-        ReThrowMsg(Crypto::Exception::InternalError,"Error in opensslError function !!");
+    /* Create the context for generating the parameters */
+    EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL), EVP_PKEY_CTX_free);
+    if(!pctx) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new_id function");
     }
 
-    KeyImpl::EvpShPtr ptr(pkey, EVP_PKEY_free); // shared ptr will free pkey
+    if(EVP_SUCCESS != EVP_PKEY_paramgen_init(pctx.get())) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_paramgen_init function");
+    }
 
-    createdPrivateKey = KeyImpl(ptr, KeyType::KEY_RSA_PRIVATE);
-    createdPublicKey = KeyImpl(ptr, KeyType::KEY_RSA_PUBLIC);
+    if(EVP_SUCCESS != EVP_PKEY_CTX_set_dsa_paramgen_bits(pctx.get(), size)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_dsa_paramgen_bits(", size, ") function");
+    }
 
-    if(pparam) {
-        EVP_PKEY_free(pparam);
+    /* Generate parameters */
+    EVP_PKEY *pparamTmp = NULL;
+    if(EVP_SUCCESS != EVP_PKEY_paramgen(pctx.get(), &pparamTmp)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_paramgen function");
     }
+    pparam = EvpPkeyUPtr(pparamTmp, EVP_PKEY_free);
 
-    if(ctx) {
-        EVP_PKEY_CTX_free(ctx);
+    // Start to generate key
+    EvpPkeyCtxUPtr kctx(EVP_PKEY_CTX_new(pparam.get(), NULL), EVP_PKEY_CTX_free);
+    if(!kctx) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new function");
+    }
+
+    if(EVP_SUCCESS != EVP_PKEY_keygen_init(kctx.get())) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen_init function");
     }
-}
 
+    /* Generate the key */
+    EVP_PKEY *pkeyTmp = NULL;
+    if(!EVP_PKEY_keygen(kctx.get(), &pkeyTmp)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen function !!");
+    }
+    pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
 
-void createKeyPairDSA(const int size, // size in bits [1024, 2048, 3072, 4096]
-        KeyImpl &createdPrivateKey,  // returned value
-        KeyImpl &createdPublicKey)  // returned value
-{
-       EVP_PKEY_CTX *pctx = NULL;
-       EVP_PKEY_CTX *kctx = NULL;
-       EVP_PKEY *pkey = NULL;
-       EVP_PKEY *pparam = NULL;
-
-       // check the parameters of functions
-       if(size != 1024 && size !=2048 && size !=3072 && size != 4096) {
-               LogError("Error in DSA input size");
-               ThrowMsg(Exception::InternalError, "Error in DSA input size");
-       }
-
-       // check the parameters of functions
-       if(&createdPrivateKey == NULL) {
-               LogError("Error in createdPrivateKey value");
-               ThrowMsg(Exception::InternalError, "Error in createdPrivateKey value");
-       }
-
-       // check the parameters of functions
-       if(&createdPublicKey == NULL) {
-               LogError("Error in createdPrivateKey value");
-               ThrowMsg(Exception::InternalError, "Error in createdPublicKey value");
-       }
-
-       Try {
-               /* Create the context for generating the parameters */
-               if(!(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL))) {
-                       LogError("Error in EVP_PKEY_CTX_new_id function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new_id function");
-               }
-
-               if(EVP_SUCCESS != EVP_PKEY_paramgen_init(pctx)) {
-                       LogError("Error in EVP_PKEY_paramgen_init function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_paramgen_init function");
-               }
-
-               if(EVP_SUCCESS != EVP_PKEY_CTX_set_dsa_paramgen_bits(pctx, size)) {
-                       LogError("Error in EVP_PKEY_CTX_set_dsa_paramgen_bits(" << size << ") function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_dsa_paramgen_bits(" << size << ") function");
-               }
-
-               /* Generate parameters */
-               if(EVP_SUCCESS != EVP_PKEY_paramgen(pctx, &pparam)) {
-                       LogError("Error in EVP_PKEY_paramgen function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_paramgen function");
-               }
-
-               // Start to generate key
-               if(!(kctx = EVP_PKEY_CTX_new(pparam, NULL))) {
-                       LogError("Error in EVP_PKEY_CTX_new function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new function");
-               }
-
-               if(EVP_SUCCESS != EVP_PKEY_keygen_init(kctx)) {
-                       LogError("Error in EVP_PKEY_keygen_init function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen_init function");
-               }
-
-               /* Generate the key */
-               if(EVP_SUCCESS != EVP_PKEY_keygen(kctx, &pkey)) {
-                       LogError("Error in EVP_PKEY_keygen function");
-                       ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen function");
-               }
-       }
-       Catch(Crypto::Exception::InternalError)
-       {
-               if(pkey) {
-                       EVP_PKEY_free(pkey);
-               }
-
-               if(pparam) {
-                       EVP_PKEY_free(pparam);
-               }
-
-               if(pctx) {
-                       EVP_PKEY_CTX_free(pctx);
-               }
-
-               if(kctx) {
-                       EVP_PKEY_CTX_free(kctx);
-               }
-
-               ReThrowMsg(Crypto::Exception::InternalError,"Error in openssl function !!");
-       }
-
-       KeyImpl::EvpShPtr ptr(pkey, EVP_PKEY_free); // shared ptr will free pkey
-
-       createdPrivateKey = KeyImpl(ptr, KeyType::KEY_DSA_PRIVATE);
-       createdPublicKey = KeyImpl(ptr, KeyType::KEY_DSA_PUBLIC);
-
-       if(pparam) {
-               EVP_PKEY_free(pparam);
-       }
-
-       if(pctx) {
-               EVP_PKEY_CTX_free(pctx);
-       }
-
-       if(kctx) {
-               EVP_PKEY_CTX_free(kctx);
-       }
+    return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_DSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
+                                        Token(backendId, DataType(KeyType::KEY_DSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
 }
 
-void createKeyPairECDSA(ElipticCurve type,
-        KeyImpl &createdPrivateKey,  // returned value
-        KeyImpl &createdPublicKey)  // returned value
+TokenPair createKeyPairECDSA(CryptoBackend backendId, ElipticCurve type)
 {
     int ecCurve = NOT_DEFINED;
-    EVP_PKEY_CTX *pctx = NULL;
-    EVP_PKEY_CTX *kctx = NULL;
-    EVP_PKEY *pkey = NULL;
-    EVP_PKEY *pparam = NULL;
+    EvpPkeyUPtr pkey;
+    EvpPkeyUPtr pparam;
 
     switch(type) {
     case ElipticCurve::prime192v1:
@@ -333,103 +386,243 @@ void createKeyPairECDSA(ElipticCurve type,
         ecCurve = NID_secp384r1;
         break;
     default:
-        LogError("Error in EC type");
-        ThrowMsg(Exception::InternalError, "Error in EC type");
+        ThrowErr(Exc::Crypto::InputParam, "Error in EC type");
     }
 
-    // check the parameters of functions
-    if(&createdPrivateKey == NULL) {
-        LogError("Error in createdPrivateKey value");
-        ThrowMsg(Exception::InternalError, "Error in createdPrivateKey value");
+    /* Create the context for generating the parameters */
+    EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free);
+    if(!pctx) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new_id function");
     }
 
-    // check the parameters of functions
-    if(&createdPublicKey == NULL) {
-        LogError("Error in createdPrivateKey value");
-        ThrowMsg(Exception::InternalError, "Error in createdPublicKey value");
+    if(EVP_SUCCESS != EVP_PKEY_paramgen_init(pctx.get())) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_paramgen_init function");
     }
 
-    Try {
-        /* Create the context for generating the parameters */
-        if(!(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) {
-            LogError("Error in EVP_PKEY_CTX_new_id function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new_id function");
-        }
+    if(EVP_SUCCESS != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx.get(), ecCurve)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_ec_paramgen_curve_nid function");
+    }
 
-        if(EVP_SUCCESS != EVP_PKEY_paramgen_init(pctx)) {
-            LogError("Error in EVP_PKEY_paramgen_init function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_paramgen_init function");
-        }
+    /* Generate parameters */
+    EVP_PKEY *pparamTmp = NULL;
+    if(EVP_SUCCESS != EVP_PKEY_paramgen(pctx.get(), &pparamTmp)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_paramgen function");
+    }
+    pparam = EvpPkeyUPtr(pparamTmp, EVP_PKEY_free);
 
-        if(EVP_SUCCESS != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecCurve)) {
-            LogError("Error in EVP_PKEY_CTX_set_ec_paramgen_curve_nid function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_ec_paramgen_curve_nid function");
-        }
+    // Start to generate key
+    EvpPkeyCtxUPtr kctx(EVP_PKEY_CTX_new(pparam.get(), NULL), EVP_PKEY_CTX_free);
+    if(!kctx) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new function");
+    }
 
-        /* Generate parameters */
-        if(EVP_SUCCESS != EVP_PKEY_paramgen(pctx, &pparam)) {
-            LogError("Error in EVP_PKEY_paramgen function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_paramgen function");
-        }
+    if(EVP_SUCCESS != EVP_PKEY_keygen_init(kctx.get())) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen_init function");
+    }
 
-        // Start to generate key
-        if(!(kctx = EVP_PKEY_CTX_new(pparam, NULL))) {
-            LogError("Error in EVP_PKEY_CTX_new function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new function");
-        }
+    /* Generate the key */
+    EVP_PKEY *pkeyTmp = NULL;
+    if(!EVP_PKEY_keygen(kctx.get(), &pkeyTmp)) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen function !!");
+    }
+    pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
 
-        if(EVP_SUCCESS != EVP_PKEY_keygen_init(kctx)) {
-            LogError("Error in EVP_PKEY_keygen_init function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen_init function");
-        }
+    return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_ECDSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
+                                        Token(backendId, DataType(KeyType::KEY_ECDSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
+}
 
-        /* Generate the key */
-        if(EVP_SUCCESS != EVP_PKEY_keygen(kctx, &pkey)) {
-            LogError("Error in EVP_PKEY_keygen function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen function");
-        }
-    } Catch(Crypto::Exception::InternalError) {
-        if(pkey) {
-            EVP_PKEY_free(pkey);
-        }
+Token createKeyAES(CryptoBackend backendId, const int sizeBits)
+{
+    // check the parameters of functions
+    if(sizeBits!=128 && sizeBits!=192 && sizeBits!=256) {
+        LogError("Error in AES input size");
+        ThrowMsg(Exc::Crypto::InputParam, "Error in AES input size");
+    }
 
-        if(pparam) {
-            EVP_PKEY_free(pparam);
-        }
+    uint8_t key[32];
+    int sizeBytes = sizeBits/8;
+    if (!RAND_bytes(key, sizeBytes)) {
+        LogError("Error in AES key generation");
+        ThrowMsg(Exc::Crypto::InternalError, "Error in AES key generation");
+    }
 
-        if(pctx) {
-            EVP_PKEY_CTX_free(pctx);
-        }
+    return Token(backendId, DataType(KeyType::KEY_AES), CKM::RawBuffer(key, key+sizeBytes));
+}
 
-        if(kctx) {
-            EVP_PKEY_CTX_free(kctx);
-        }
+TokenPair generateAKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm)
+{
+    validateParams<IsAsymGeneration>(algorithm);
 
-        ReThrowMsg(Crypto::Exception::InternalError,"Error in openssl function !!");
+    AlgoType keyType = unpack<AlgoType>(algorithm, ParamName::ALGO_TYPE);
+    if(keyType == AlgoType::RSA_GEN || keyType == AlgoType::DSA_GEN)
+    {
+        int keyLength = unpack<int>(algorithm, ParamName::GEN_KEY_LEN);
+        if(keyType == AlgoType::RSA_GEN)
+            return createKeyPairRSA(backendId, keyLength);
+        else
+            return createKeyPairDSA(backendId, keyLength);
+    }
+    else // AlgoType::ECDSA_GEN
+    {
+        ElipticCurve ecType = unpack<ElipticCurve>(algorithm, ParamName::GEN_EC);
+        return createKeyPairECDSA(backendId, ecType);
     }
+}
 
-    KeyImpl::EvpShPtr ptr(pkey, EVP_PKEY_free); // shared ptr will free pkey
+Token generateSKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm)
+{
+    validateParams<IsSymGeneration>(algorithm);
 
-    createdPrivateKey = KeyImpl(ptr, KeyType::KEY_ECDSA_PRIVATE);
-    createdPublicKey = KeyImpl(ptr, KeyType::KEY_ECDSA_PUBLIC);
+    int keySizeBits = unpack<int>(algorithm, ParamName::GEN_KEY_LEN);
+    return createKeyAES(backendId, keySizeBits);
+}
 
-    if(pparam) {
-        EVP_PKEY_free(pparam);
-    }
+RawBuffer encryptDataAesCbc(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv)
+{
+    Crypto::SW::Cipher::AesCbcEncryption enc(key, iv);
+    RawBuffer result = enc.Append(data);
+    RawBuffer tmp = enc.Finalize();
+    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
+    return result;
+}
+
+std::pair<RawBuffer, RawBuffer> encryptDataAesGcm(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv,
+    int tagSize)
+{
+    RawBuffer tag(tagSize);
+    Crypto::SW::Cipher::AesGcmEncryption enc(key, iv);
+    RawBuffer result = enc.Append(data);
+    RawBuffer tmp = enc.Finalize();
+    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
+    if (0 == enc.Control(EVP_CTRL_GCM_GET_TAG, tagSize, tag.data())) {
+        ThrowErr(Exc::Crypto::InternalError, "Error in AES control function. Get tag failed.");
+    }
+    return std::make_pair(result, tag);
+}
+
+RawBuffer encryptDataAesGcmPacked(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv,
+    int tagSize)
+{
+    auto pair = encryptDataAesGcm(key, data, iv, tagSize);
+    std::copy(pair.second.begin(), pair.second.end(), std::back_inserter(pair.first));
+    return pair.first;
+}
+
+RawBuffer decryptDataAesCbc(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv)
+{
+    Crypto::SW::Cipher::AesCbcDecryption dec(key, iv);
+    RawBuffer result = dec.Append(data);
+    RawBuffer tmp = dec.Finalize();
+    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
+    return result;
+}
+
+RawBuffer decryptDataAesGcm(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv,
+    const RawBuffer &tag)
+{
+    Crypto::SW::Cipher::AesGcmDecryption dec(key, iv);
+    void *ptr = (void*)tag.data();
+    if (0 == dec.Control(EVP_CTRL_GCM_SET_TAG, tag.size(), ptr)) {
+        ThrowErr(Exc::Crypto::InternalError,
+            "Error in AES control function. Set tag failed.");
+    }
+    RawBuffer result = dec.Append(data);
+    RawBuffer tmp = dec.Finalize();
+    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
+    return result;
+}
 
-    if(pctx) {
-        EVP_PKEY_CTX_free(pctx);
+RawBuffer decryptDataAesGcmPacked(
+    const RawBuffer &key,
+    const RawBuffer &data,
+    const RawBuffer &iv,
+    int tagSize)
+{
+    if (tagSize > static_cast<int>(data.size()))
+        ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
+
+    auto tagPos = data.data() + data.size() - tagSize;
+    return decryptDataAesGcm(
+        key,
+        RawBuffer(data.data(), tagPos),
+        iv,
+        RawBuffer(tagPos, data.data() + data.size()));
+}
+
+RawBuffer symmetricEncrypt(const RawBuffer &key,
+                           const CryptoAlgorithm &alg,
+                           const RawBuffer &data)
+{
+    validateParams<IsEncryption>(alg);
+    AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+
+    switch(keyType)
+    {
+        case AlgoType::AES_CBC:
+            return encryptDataAesCbc(key, data, unpack<RawBuffer>(alg, ParamName::ED_IV));
+        case AlgoType::AES_GCM:
+        {
+            int tagLenBits = DEFAULT_AES_GCM_TAG_LEN;
+            alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
+            return encryptDataAesGcmPacked(key,
+                                           data,
+                                           unpack<RawBuffer>(alg, ParamName::ED_IV),
+                                           tagLenBits/8);
+        }
+        default:
+            break;
     }
+    ThrowErr(Exc::Crypto::OperationNotSupported,
+        "symmetric enc error: algorithm not recognized");
+}
+
+RawBuffer symmetricDecrypt(const RawBuffer &key,
+                           const CryptoAlgorithm &alg,
+                           const RawBuffer &data)
+{
+    validateParams<IsEncryption>(alg);
+    AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
 
-    if(kctx) {
-        EVP_PKEY_CTX_free(kctx);
+    switch(keyType)
+    {
+        case AlgoType::AES_CBC:
+            return decryptDataAesCbc(key, data, unpack<RawBuffer>(alg, ParamName::ED_IV));
+        case AlgoType::AES_GCM:
+        {
+            int tagLenBits = DEFAULT_AES_GCM_TAG_LEN;
+            alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
+            return decryptDataAesGcmPacked(key,
+                                           data,
+                                           unpack<RawBuffer>(alg, ParamName::ED_IV),
+                                           tagLenBits/8);
+        }
+        default:
+            break;
     }
+    ThrowErr(Exc::Crypto::InputParam, "symmetric dec error: algorithm not recognized");
 }
 
 RawBuffer sign(EVP_PKEY *pkey,
     const CryptoAlgorithm &alg,
     const RawBuffer &message)
 {
+    validateParams<IsSignVerify>(alg);
+
     int rsa_padding = NOT_DEFINED;
     const EVP_MD *md_algo = NULL;
 
@@ -447,7 +640,7 @@ RawBuffer sign(EVP_PKEY *pkey,
 //       (privateKey.getType() != KeyType::KEY_ECDSA_PRIVATE))
 //    {
 //        LogError("Error in private key type");
-//        ThrowMsg(CryptoService::Exception::Crypto_internal, "Error in private key type");
+//        ThrowErr(CryptoService::Exception::Crypto_internal, "Error in private key type");
 //    }
 //
 //    if(privateKey.getType()==KeyType::KEY_RSA_PRIVATE) {
@@ -455,8 +648,7 @@ RawBuffer sign(EVP_PKEY *pkey,
 //    }
 
     if (NULL == pkey) {
-        LogError("Error in EVP_PKEY_keygen function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_keygen function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_keygen function");
     }
 
     if(md_algo == NULL) {
@@ -473,20 +665,17 @@ RawBuffer signMessage(EVP_PKEY *privKey,
     EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(privKey, NULL), EVP_PKEY_CTX_free);
  
     if(!pctx.get()) {
-        LogError("Error in EVP_PKEY_CTX_new function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new function");
     }
 
     if(EVP_PKEY_sign_init(pctx.get()) != EVP_SUCCESS) {
-        LogError("Error in EVP_PKEY_sign_init function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_sign_init function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_sign_init function");
     }
 
     /* Set padding algorithm */
     if(EVP_PKEY_type(privKey->type) == EVP_PKEY_RSA) {
         if(EVP_SUCCESS != EVP_PKEY_CTX_set_rsa_padding(pctx.get(), rsa_padding)) {
-            LogError("Error in EVP_PKEY_CTX_set_rsa_padding function");
-            ThrowMsg(Crypto::Exception::InternalError,
+            ThrowErr(Exc::Crypto::InternalError,
                      "Error in EVP_PKEY_CTX_set_rsa_padding function");
         }
     }
@@ -496,8 +685,7 @@ RawBuffer signMessage(EVP_PKEY *privKey,
      * signature. Length is returned in slen */
     size_t slen;
     if(EVP_SUCCESS != EVP_PKEY_sign(pctx.get(), NULL, &slen, message.data(), message.size())) {
-        LogError("Error in EVP_PKEY_sign function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_sign function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_sign function");
     }
 
     /* Allocate memory for the signature based on size in slen */
@@ -514,8 +702,7 @@ RawBuffer signMessage(EVP_PKEY *privKey,
         return sig;
     }
 
-    LogError("Error in EVP_PKEY_sign function. Input param error.");
-    ThrowMsg(Crypto::Exception::InputParam, "Error in EVP_PKEY_sign function. Input param error.");
+    ThrowErr(Exc::Crypto::InputParam, "Error in EVP_PKEY_sign function. Input param error.");
 }
 
 RawBuffer digestSignMessage(EVP_PKEY *privKey,
@@ -529,27 +716,23 @@ RawBuffer digestSignMessage(EVP_PKEY *privKey,
 
     // Create the Message Digest Context
     if(!mdctx.get()) {
-        LogError("Error in EVP_MD_CTX_create function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_MD_CTX_create function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_create function");
     }
 
     if(EVP_SUCCESS != EVP_DigestSignInit(mdctx.get(), &pctx, md_algo, NULL, privKey)) {
-        LogError("Error in EVP_DigestSignInit function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestSignInit function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestSignInit function");
     }
 
     /* Set padding algorithm */
     if(EVP_PKEY_type(privKey->type) == EVP_PKEY_RSA) {
         if(EVP_SUCCESS != EVP_PKEY_CTX_set_rsa_padding(pctx, rsa_padding)) {
-            LogError("Error in EVP_PKEY_CTX_set_rsa_padding function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
+            ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
         }
     }
 
     /* Call update with the message */
     if(EVP_SUCCESS != EVP_DigestSignUpdate(mdctx.get(), message.data(), message.size())) {
-        LogError("Error in EVP_DigestSignUpdate function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestSignUpdate function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestSignUpdate function");
     }
 
     /* Finalize the DigestSign operation */
@@ -557,8 +740,7 @@ RawBuffer digestSignMessage(EVP_PKEY *privKey,
      * signature. Length is returned in slen */
     size_t slen;
     if(EVP_SUCCESS != EVP_DigestSignFinal(mdctx.get(), NULL, &slen)) {
-        LogError("Error in EVP_DigestSignFinal function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestSignFinal function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestSignFinal function");
     }
 
     /* Allocate memory for the signature based on size in slen */
@@ -566,8 +748,7 @@ RawBuffer digestSignMessage(EVP_PKEY *privKey,
 
     /* Obtain the signature */
     if(EVP_SUCCESS != EVP_DigestSignFinal(mdctx.get(), sig.data(), &slen)) {
-        LogError("Error in EVP_DigestSignFinal function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestSignFinal function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestSignFinal function");
     }
 
     // Set value to return RawData
@@ -580,6 +761,8 @@ int verify(EVP_PKEY *pkey,
     const RawBuffer &message,
     const RawBuffer &signature)
 {
+    validateParams<IsSignVerify>(alg);
+
     int rsa_padding = NOT_DEFINED;
     const EVP_MD *md_algo = NULL;
 
@@ -597,7 +780,7 @@ int verify(EVP_PKEY *pkey,
 //       (publicKey.getType() != KeyType::KEY_ECDSA_PUBLIC))
 //    {
 //        LogError("Error in private key type");
-//        ThrowMsg(CryptoService::Exception::Crypto_internal, "Error in private key type");
+//        ThrowErr(CryptoService::Exception::Crypto_internal, "Error in private key type");
 //    }
 //
 //    if(publicKey.getType()==KeyType::KEY_RSA_PUBLIC) {
@@ -606,8 +789,7 @@ int verify(EVP_PKEY *pkey,
 
 //    auto shrPKey = publicKey.getEvpShPtr();
     if (NULL == pkey) {
-        LogError("Error in getEvpShPtr function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in getEvpShPtr function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in getEvpShPtr function");
     }
 
     if (md_algo == NULL) {
@@ -625,20 +807,17 @@ int verifyMessage(EVP_PKEY *pubKey,
     EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(pubKey, NULL), EVP_PKEY_CTX_free);
 
     if(!pctx.get()) {
-        LogError("Error in EVP_PKEY_CTX_new function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_new function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new function");
     }
 
     if(EVP_PKEY_verify_init(pctx.get()) != EVP_SUCCESS) {
-        LogError("Error in EVP_PKEY_verify_init function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_verify_init function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_verify_init function");
     }
 
     /* Set padding algorithm  */
     if(EVP_PKEY_type(pubKey->type) == EVP_PKEY_RSA) {
         if(EVP_SUCCESS != EVP_PKEY_CTX_set_rsa_padding(pctx.get(), rsa_padding)) {
-            LogError("Error in EVP_PKEY_CTX_set_rsa_padding function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
+            ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
         }
     }
 
@@ -661,25 +840,21 @@ int digestVerifyMessage(EVP_PKEY *pubKey,
 
     /* Create the Message Digest Context */
     if(!mdctx.get()) {
-        LogError("Error in EVP_MD_CTX_create function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_MD_CTX_create function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_create function");
     }
 
     if(EVP_SUCCESS != EVP_DigestVerifyInit(mdctx.get(), &pctx, md_algo, NULL, pubKey)) {
-        LogError("Error in EVP_DigestVerifyInit function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestVerifyInit function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestVerifyInit function");
     }
 
     if(EVP_PKEY_type(pubKey->type) == EVP_PKEY_RSA) {
         if(EVP_SUCCESS != EVP_PKEY_CTX_set_rsa_padding(pctx, rsa_padding)) {
-            LogError("Error in EVP_PKEY_CTX_set_rsa_padding function");
-            ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
+            ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_set_rsa_padding function");
         }
     }
 
     if(EVP_SUCCESS != EVP_DigestVerifyUpdate(mdctx.get(), message.data(), message.size()) ) {
-        LogError("Error in EVP_DigestVerifyUpdate function");
-        ThrowMsg(Crypto::Exception::InternalError, "Error in EVP_DigestVerifyUpdate function");
+        ThrowErr(Exc::Crypto::InternalError, "Error in EVP_DigestVerifyUpdate function");
     }
 
     if(EVP_SUCCESS == EVP_DigestVerifyFinal(mdctx.get(), const_cast<unsigned char*>(signature.data()), signature.size()) ) {