/***************************************************************************
    begin       : Wed Mar 16 2005
    copyright   : (C) 2005 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *          Please see toplevel file COPYING for license details           *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#define DISABLE_DEBUGLOG


#include "cryptkeysym_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/cryptdefs.h>
#include <gwenhywfar/text.h>



GWEN_INHERIT(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM)






GWENHYWFAR_CB int GWEN_Crypt_KeySym_Encipher(GWEN_CRYPT_KEY *k,
                                             const uint8_t *pInData,
                                             uint32_t inLen,
                                             uint8_t *pOutData,
                                             uint32_t *pOutLen)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  err=gcry_cipher_encrypt(xk->algoHandle, pOutData, inLen, pInData, inLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_encrypt(): %s", gcry_strerror(err));
    return GWEN_ERROR_GENERIC;
  }
  *pOutLen=inLen;

  return 0;
}



GWENHYWFAR_CB int GWEN_Crypt_KeySym_Decipher(GWEN_CRYPT_KEY *k,
                                             const uint8_t *pInData,
                                             uint32_t inLen,
                                             uint8_t *pOutData,
                                             uint32_t *pOutLen)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  err=gcry_cipher_decrypt(xk->algoHandle, pOutData, inLen, pInData, inLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_decrypt(): %s", gcry_strerror(err));
    return GWEN_ERROR_GENERIC;
  }
  *pOutLen=inLen;

  return 0;
}



GWENHYWFAR_CB void GWEN_Crypt_KeySym_freeData(GWEN_UNUSED void *bp, void *p)
{
  GWEN_CRYPT_KEY_SYM *xk;

  xk=(GWEN_CRYPT_KEY_SYM *) p;
  if (xk->keyData && xk->keyLen) {
    memset(xk->keyData, 0, xk->keyLen);
    free(xk->keyData);
  }
  xk->keyData=NULL;
  xk->keyLen=0;
  if (xk->algoValid)
    gcry_cipher_close(xk->algoHandle);
  GWEN_FREE_OBJECT(xk);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeySym_dup(const GWEN_CRYPT_KEY *k)
{
  GWEN_CRYPT_KEY *nk;
  GWEN_CRYPT_KEY_SYM *xk;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  nk=GWEN_Crypt_KeySym_fromData(GWEN_Crypt_Key_GetCryptAlgoId(k),
                                GWEN_Crypt_Key_GetKeySize(k),
                                xk->mode,
                                xk->algo,
                                GCRY_CIPHER_SECURE,
                                xk->keyData,
                                xk->keyLen);
  return nk;
}



enum gcry_cipher_modes GWEN_Crypt_KeySym__MyMode2GMode(GWEN_CRYPT_CRYPTMODE mode)
{
  switch (mode) {
  case GWEN_Crypt_CryptMode_Unknown:
        return GCRY_CIPHER_MODE_NONE;
  case GWEN_Crypt_CryptMode_None:
    return GCRY_CIPHER_MODE_NONE;
  case GWEN_Crypt_CryptMode_Ecb:
    return GCRY_CIPHER_MODE_ECB;
  case GWEN_Crypt_CryptMode_Cfb:
    return GCRY_CIPHER_MODE_CFB;
  case GWEN_Crypt_CryptMode_Cbc:
    return GCRY_CIPHER_MODE_CBC;
  }

  return GCRY_CIPHER_MODE_NONE;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeySym_Generate(GWEN_CRYPT_CRYPTALGOID cryptAlgoId, int keySize,
                                           GWEN_CRYPT_CRYPTMODE mode,
                                           int algo,
                                           unsigned int flags,
                                           int quality)
{
  GWEN_CRYPT_KEY *k;
  GWEN_CRYPT_KEY_SYM *xk;
  int kbytes;
  uint8_t *keyData;
  gcry_error_t err;
  enum gcry_random_level q;

  k=GWEN_Crypt_Key_new(cryptAlgoId, keySize);
  assert(k);
  GWEN_NEW_OBJECT(GWEN_CRYPT_KEY_SYM, xk);
  GWEN_INHERIT_SETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k, xk, GWEN_Crypt_KeySym_freeData);
  GWEN_Crypt_Key_SetEncipherFn(k, GWEN_Crypt_KeySym_Encipher);
  GWEN_Crypt_Key_SetDecipherFn(k, GWEN_Crypt_KeySym_Decipher);

  switch (quality) {
  case 0:
    q=GCRY_WEAK_RANDOM;
    break;
  case 1:
    q=GCRY_STRONG_RANDOM;
    break;
  case 2:
  default:
    q=GCRY_VERY_STRONG_RANDOM;
    break;
  }

  /* open algo */
  err=gcry_cipher_open(&xk->algoHandle, algo, GWEN_Crypt_KeySym__MyMode2GMode(mode), flags);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_open(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }
  xk->algoValid=1;
  xk->mode=mode;

  while (1) {
    kbytes=keySize;
    keyData=gcry_random_bytes(kbytes, q);

    /* store key data */
    xk->keyData=keyData;
    xk->keyLen=kbytes;

    /* set key in algo */
    err=gcry_cipher_setkey(xk->algoHandle, xk->keyData, xk->keyLen);
    if (err) {
      if ((err & GPG_ERR_CODE_MASK)==GPG_ERR_WEAK_KEY) {
        DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): weak key, will try again");
      }
      else {
        DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): %d [%s]", err, gcry_strerror(err));
        GWEN_Crypt_Key_free(k);
        return NULL;
      }
    }
    else
      break;

    /* try it again */
    memset(xk->keyData, 0, xk->keyLen);
    free(xk->keyData);
    xk->keyData=NULL;
    xk->keyLen=0;
  }

  return k;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeySym_fromData(GWEN_CRYPT_CRYPTALGOID cryptAlgoId, int keySize,
                                           GWEN_CRYPT_CRYPTMODE mode,
                                           int algo,
                                           unsigned int flags,
                                           const uint8_t *kd, uint32_t kl)
{
  GWEN_CRYPT_KEY *k;
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

#if 0
  if (kl!=gcry_cipher_get_algo_keylen(algo)) {
    DBG_ERROR(GWEN_LOGDOMAIN, "Invalid key length (is %d, should be %d)",
              (int)kl, (int)gcry_cipher_get_algo_keylen(algo));
    return NULL;
  }
#endif

  k=GWEN_Crypt_Key_new(cryptAlgoId, keySize);
  assert(k);
  GWEN_NEW_OBJECT(GWEN_CRYPT_KEY_SYM, xk);
  GWEN_INHERIT_SETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k, xk, GWEN_Crypt_KeySym_freeData);
  GWEN_Crypt_Key_SetEncipherFn(k, GWEN_Crypt_KeySym_Encipher);
  GWEN_Crypt_Key_SetDecipherFn(k, GWEN_Crypt_KeySym_Decipher);

  /* open algo */
  err=gcry_cipher_open(&xk->algoHandle, algo, GWEN_Crypt_KeySym__MyMode2GMode(mode), flags);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_open(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }
  xk->algoValid=1;
  xk->mode=mode;
  xk->algo=algo;

  /* read key data */
  if (kd==NULL || kl==0) {
    DBG_INFO(GWEN_LOGDOMAIN, "No key data");
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  /* store key data */
  xk->keyData=(uint8_t *) malloc(kl);
  assert(xk->keyData);
  memmove(xk->keyData, kd, kl);
  xk->keyLen=kl;

  /* set key in algo */
  err=gcry_cipher_setkey(xk->algoHandle, xk->keyData, xk->keyLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  return k;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeySym__fromDb(GWEN_CRYPT_CRYPTALGOID cryptAlgoId,
                                          GWEN_CRYPT_CRYPTMODE mode,
                                          int algo,
                                          unsigned int flags,
                                          const char *gname,
                                          GWEN_DB_NODE *db)
{
  gcry_error_t err;
  GWEN_CRYPT_KEY *k;
  GWEN_CRYPT_KEY_SYM *xk;
  //unsigned int nbits;
  GWEN_DB_NODE *dbR;
  unsigned int len;
  const char *p;

  dbR=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, gname);
  if (dbR==NULL) {
    DBG_ERROR(GWEN_LOGDOMAIN, "DB does not contain an %s key (no %s group)",
              gname, gname);
    return NULL;
  }

  k=GWEN_Crypt_Key_fromDb(db);
  if (k==NULL) {
    DBG_INFO(GWEN_LOGDOMAIN, "here");
    return NULL;
  }
  if (GWEN_Crypt_Key_GetCryptAlgoId(k)!=cryptAlgoId) {
    DBG_ERROR(GWEN_LOGDOMAIN, "DB does not contain an RSA key");
    GWEN_Crypt_Key_free(k);
    return NULL;
  }
  //nbits=GWEN_Crypt_Key_GetKeySize(k)*8;

  /* extend key */
  GWEN_NEW_OBJECT(GWEN_CRYPT_KEY_SYM, xk);
  GWEN_INHERIT_SETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k, xk, GWEN_Crypt_KeySym_freeData);
  GWEN_Crypt_Key_SetEncipherFn(k, GWEN_Crypt_KeySym_Encipher);
  GWEN_Crypt_Key_SetDecipherFn(k, GWEN_Crypt_KeySym_Decipher);

  /* open algo */
  err=gcry_cipher_open(&xk->algoHandle, algo, GWEN_Crypt_KeySym__MyMode2GMode(mode), flags);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_open(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }
  xk->algoValid=1;
  xk->mode=mode;
  xk->algo=algo;

  /* read key data */
  p=GWEN_DB_GetBinValue(dbR, "keyData", 0, NULL, 0, &len);
  if (p==NULL || len==0) {
    DBG_INFO(GWEN_LOGDOMAIN, "No key data");
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  /* store key data */
  xk->keyData=(uint8_t *) malloc(len);
  assert(xk->keyData);
  memmove(xk->keyData, p, len);
  xk->keyLen=len;

  /* set key in algo */
  err=gcry_cipher_setkey(xk->algoHandle, xk->keyData, xk->keyLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  return k;
}



int GWEN_Crypt_KeySym__toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db, const char *gname)
{
  GWEN_CRYPT_KEY_SYM *xk;
  GWEN_DB_NODE *dbR;
  int rv;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  /* let key module wirte basic key info */
  rv=GWEN_Crypt_Key_toDb(k, db);
  if (rv)
    return rv;

  /* write sym stuff into our own group */
  dbR=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_OVERWRITE_GROUPS, gname);
  assert(dbR);

  GWEN_DB_SetBinValue(dbR, GWEN_DB_FLAGS_OVERWRITE_VARS,
                      "keyData", xk->keyData, xk->keyLen);

  return 0;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeySym_fromDb(GWEN_CRYPT_CRYPTMODE mode, GWEN_DB_NODE *db)
{
  gcry_error_t err;
  GWEN_CRYPT_KEY *k;
  GWEN_CRYPT_KEY_SYM *xk;
  //unsigned int nbits;
  GWEN_DB_NODE *dbR;
  unsigned int len;
  const char *gname;
  const char *p;

  k=GWEN_Crypt_Key_fromDb(db);
  if (k==NULL) {
    DBG_INFO(GWEN_LOGDOMAIN, "here");
    return NULL;
  }

  gname=GWEN_Crypt_CryptAlgoId_toString(GWEN_Crypt_Key_GetCryptAlgoId(k));

  dbR=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, gname);
  if (dbR==NULL) {
    DBG_ERROR(GWEN_LOGDOMAIN, "DB does not contain an %s key (no %s group)",
              gname, gname);
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  //nbits=GWEN_Crypt_Key_GetKeySize(k)*8;

  /* extend key */
  GWEN_NEW_OBJECT(GWEN_CRYPT_KEY_SYM, xk);
  GWEN_INHERIT_SETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k, xk, GWEN_Crypt_KeySym_freeData);
  GWEN_Crypt_Key_SetEncipherFn(k, GWEN_Crypt_KeySym_Encipher);
  GWEN_Crypt_Key_SetDecipherFn(k, GWEN_Crypt_KeySym_Decipher);

  /* open algo */
  err=gcry_cipher_open(&xk->algoHandle,
                       GWEN_Crypt_Key_GetCryptAlgoId(k),
                       GWEN_Crypt_KeySym__MyMode2GMode(mode),
                       GCRY_CIPHER_SECURE);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_open(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }
  xk->algoValid=1;
  xk->mode=mode;
  xk->algo=GWEN_Crypt_Key_GetCryptAlgoId(k);

  /* read key data */
  p=GWEN_DB_GetBinValue(dbR, "keyData", 0, NULL, 0, &len);
  if (p==NULL || len==0) {
    DBG_INFO(GWEN_LOGDOMAIN, "No key data");
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  /* store key data */
  xk->keyData=(uint8_t *) malloc(len);
  assert(xk->keyData);
  memmove(xk->keyData, p, len);
  xk->keyLen=len;

  /* set key in algo */
  err=gcry_cipher_setkey(xk->algoHandle, xk->keyData, xk->keyLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return NULL;
  }

  return k;
}



int GWEN_Crypt_KeySym_toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db)
{
  GWEN_CRYPT_KEY_SYM *xk;
  GWEN_DB_NODE *dbR;
  int rv;
  const char *gname;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  /* let key module wirte basic key info */
  rv=GWEN_Crypt_Key_toDb(k, db);
  if (rv)
    return rv;

  gname=GWEN_Crypt_CryptAlgoId_toString(GWEN_Crypt_Key_GetCryptAlgoId(k));

  /* write sym stuff into our own group */
  dbR=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_OVERWRITE_GROUPS, gname);
  assert(dbR);

  GWEN_DB_SetBinValue(dbR, GWEN_DB_FLAGS_OVERWRITE_VARS,
                      "keyData", xk->keyData, xk->keyLen);

  return 0;
}



int GWEN_Crypt_KeySym_SetKeyData(GWEN_CRYPT_KEY *k, const uint8_t *kd, uint32_t kl)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  if (!kd || !kl) {
    DBG_ERROR(GWEN_LOGDOMAIN, "Empty keydata not allowed");
    return GWEN_ERROR_INVALID;
  }

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  if (xk->keyData && xk->keyLen) {
    memset(xk->keyData, 0, xk->keyLen);
    free(xk->keyData);
  }

  /* store key data */
  xk->keyData=(uint8_t *)malloc(kl);
  assert(xk->keyData);
  memmove(xk->keyData, kd, kl);
  xk->keyLen=kl;

  /* set key in algo */
  err=gcry_cipher_setkey(xk->algoHandle, xk->keyData, xk->keyLen);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setkey(): %s", gcry_strerror(err));
    GWEN_Crypt_Key_free(k);
    return GWEN_ERROR_GENERIC;
  }

  return 0;
}



uint8_t *GWEN_Crypt_KeySym_GetKeyDataPtr(const GWEN_CRYPT_KEY *k)
{
  GWEN_CRYPT_KEY_SYM *xk;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  return xk->keyData;
}



uint32_t GWEN_Crypt_KeySym_GetKeyDataLen(const GWEN_CRYPT_KEY *k)
{
  GWEN_CRYPT_KEY_SYM *xk;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  return xk->keyLen;
}




GWEN_CRYPT_KEY *GWEN_Crypt_KeyDes3K_Generate(GWEN_CRYPT_CRYPTMODE mode,
                                             int keySize,
                                             int quality)
{
  uint8_t kd[16];
  GWEN_CRYPT_KEY *k;

  GWEN_Crypt_Random(quality, kd, 16);
  k=GWEN_Crypt_KeyDes3K_fromData(mode, keySize, kd, 16);
  memset(kd, 0, 16);

  return k;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyDes3K_fromData(GWEN_CRYPT_CRYPTMODE mode, int keySize,
                                             const uint8_t *kd, uint32_t kl)
{
  if (kl==16) {
    uint8_t new_kd[24];
    GWEN_CRYPT_KEY *k;

    /* 3key DES with only two keys, copy key1 as key3 */
    memmove(new_kd, kd, 16);
    memmove(new_kd+16, new_kd, 8);
    k=GWEN_Crypt_KeySym_fromData(GWEN_Crypt_CryptAlgoId_Des3K, 24,
                                 mode, GCRY_CIPHER_3DES, GCRY_CIPHER_SECURE, new_kd, 24);
    memset(new_kd, 0, 24);
    return k;
  }
  else
    return GWEN_Crypt_KeySym_fromData(GWEN_Crypt_CryptAlgoId_Des3K, keySize,
                                      mode, GCRY_CIPHER_3DES, GCRY_CIPHER_SECURE, kd, kl);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyDes3K_fromDb(GWEN_CRYPT_CRYPTMODE mode,
                                           GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__fromDb(GWEN_Crypt_CryptAlgoId_Des3K, mode,
                                   GCRY_CIPHER_3DES, GCRY_CIPHER_SECURE, "des3k", db);
}



int GWEN_Crypt_KeyDes3K_toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__toDb(k, db, "des3k");
}



int GWEN_Crypt_KeyDes3K_SetKeyData(GWEN_CRYPT_KEY *k, const uint8_t *kd, uint32_t kl)
{
  if (kl==16) {
    uint8_t new_kd[24];
    int rv;

    /* 3key DES with only two keys, copy key1 as key3 */
    memmove(new_kd, kd, 16);
    memmove(new_kd+16, new_kd, 8);
    rv=GWEN_Crypt_KeySym_SetKeyData(k, new_kd, 24);
    memset(new_kd, 0, 24);
    return rv;
  }
  else
    return GWEN_Crypt_KeySym_SetKeyData(k, kd, kl);
}



uint8_t *GWEN_Crypt_KeyDes3K_GetKeyDataPtr(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataPtr(k);
}



uint32_t GWEN_Crypt_KeyDes3K_GetKeyDataLen(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataLen(k);
}



int GWEN_Crypt_KeyDes3K_SetIV(GWEN_CRYPT_KEY *k,
                              const uint8_t *kd,
                              uint32_t kl)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  if (kd==NULL || kl==0) {
    const uint8_t iv[]= {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    err=gcry_cipher_setiv(xk->algoHandle, iv, sizeof(iv));
  }
  else
    err=gcry_cipher_setiv(xk->algoHandle, kd, kl);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setiv(): %s", gcry_strerror(err));
    return GWEN_ERROR_GENERIC;
  }

  return 0;
}







GWEN_CRYPT_KEY *GWEN_Crypt_KeyBlowFish_Generate(GWEN_CRYPT_CRYPTMODE mode,
                                                int keySize,
                                                int quality)
{
  return GWEN_Crypt_KeySym_Generate(GWEN_Crypt_CryptAlgoId_BlowFish, keySize, mode,
                                    GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_SECURE, quality);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyBlowFish_fromData(GWEN_CRYPT_CRYPTMODE mode, int keySize,
                                                const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_fromData(GWEN_Crypt_CryptAlgoId_BlowFish, keySize, mode,
                                    GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_SECURE,
                                    kd, kl);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyBlowFish_fromDb(GWEN_CRYPT_CRYPTMODE mode,
                                              GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__fromDb(GWEN_Crypt_CryptAlgoId_BlowFish, mode,
                                   GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_SECURE, "blowFish", db);
}



int GWEN_Crypt_KeyBlowFish_toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__toDb(k, db, "blowFish");
}



int GWEN_Crypt_KeyBlowFish_SetKeyData(GWEN_CRYPT_KEY *k, const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_SetKeyData(k, kd, kl);
}



uint8_t *GWEN_Crypt_KeyBlowFish_GetKeyDataPtr(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataPtr(k);
}



uint32_t GWEN_Crypt_KeyBlowFish_GetKeyDataLen(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataLen(k);
}




GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes128_Generate(GWEN_CRYPT_CRYPTMODE mode,
                                              int keySize,
                                              int quality)
{
  return GWEN_Crypt_KeySym_Generate(GWEN_Crypt_CryptAlgoId_Aes128, keySize, mode,
                                    GCRY_CIPHER_AES128, GCRY_CIPHER_SECURE, quality);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes128_fromData(GWEN_CRYPT_CRYPTMODE mode, int keySize,
                                              const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_fromData(GWEN_Crypt_CryptAlgoId_Aes128, keySize, mode,
                                    GCRY_CIPHER_AES128, GCRY_CIPHER_SECURE,
                                    kd, kl);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes128_fromDb(GWEN_CRYPT_CRYPTMODE mode,
                                            GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__fromDb(GWEN_Crypt_CryptAlgoId_Aes128, mode,
                                   GCRY_CIPHER_AES128, GCRY_CIPHER_SECURE, "aes128", db);
}



int GWEN_Crypt_KeyAes128_toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__toDb(k, db, "aes128");
}



int GWEN_Crypt_KeyAes128_SetKeyData(GWEN_CRYPT_KEY *k, const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_SetKeyData(k, kd, kl);
}



uint8_t *GWEN_Crypt_KeyAes128_GetKeyDataPtr(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataPtr(k);
}



uint32_t GWEN_Crypt_KeyAes128_GetKeyDataLen(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataLen(k);
}



int GWEN_Crypt_KeyAes128_SetIV(GWEN_CRYPT_KEY *k,
                               const uint8_t *kd,
                               uint32_t kl)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  if (kd==NULL || kl==0) {
    const uint8_t iv[]= {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    err=gcry_cipher_setiv(xk->algoHandle, iv, sizeof(iv));
  }
  else
    err=gcry_cipher_setiv(xk->algoHandle, kd, kl);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setiv(): %s", gcry_strerror(err));
    return GWEN_ERROR_GENERIC;
  }

  return 0;
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes256_Generate(GWEN_CRYPT_CRYPTMODE mode,
                                              int keySize,
                                              int quality)
{
  return GWEN_Crypt_KeySym_Generate(GWEN_Crypt_CryptAlgoId_Aes256, keySize, mode,
                                    GCRY_CIPHER_AES256, GCRY_CIPHER_SECURE, quality);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes256_fromData(GWEN_CRYPT_CRYPTMODE mode, int keySize,
                                              const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_fromData(GWEN_Crypt_CryptAlgoId_Aes256, keySize, mode,
                                    GCRY_CIPHER_AES256, GCRY_CIPHER_SECURE,
                                    kd, kl);
}



GWEN_CRYPT_KEY *GWEN_Crypt_KeyAes256_fromDb(GWEN_CRYPT_CRYPTMODE mode,
                                            GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__fromDb(GWEN_Crypt_CryptAlgoId_Aes256, mode,
                                   GCRY_CIPHER_AES256, GCRY_CIPHER_SECURE, "aes256", db);
}



int GWEN_Crypt_KeyAes256_toDb(const GWEN_CRYPT_KEY *k, GWEN_DB_NODE *db)
{
  return GWEN_Crypt_KeySym__toDb(k, db, "aes256");
}



int GWEN_Crypt_KeyAes256_SetKeyData(GWEN_CRYPT_KEY *k, const uint8_t *kd, uint32_t kl)
{
  return GWEN_Crypt_KeySym_SetKeyData(k, kd, kl);
}



uint8_t *GWEN_Crypt_KeyAes256_GetKeyDataPtr(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataPtr(k);
}



uint32_t GWEN_Crypt_KeyAes256_GetKeyDataLen(const GWEN_CRYPT_KEY *k)
{
  return GWEN_Crypt_KeySym_GetKeyDataLen(k);
}

int GWEN_Crypt_KeyAes256_SetIV(GWEN_CRYPT_KEY *k,
                               const uint8_t *kd,
                               uint32_t kl)
{
  GWEN_CRYPT_KEY_SYM *xk;
  gcry_error_t err;

  assert(k);
  xk=GWEN_INHERIT_GETDATA(GWEN_CRYPT_KEY, GWEN_CRYPT_KEY_SYM, k);
  assert(xk);

  if (kd==NULL || kl==0) {
    const uint8_t iv[]= {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    err=gcry_cipher_setiv(xk->algoHandle, iv, sizeof(iv));
  }
  else
    err=gcry_cipher_setiv(xk->algoHandle, kd, kl);
  if (err) {
    DBG_INFO(GWEN_LOGDOMAIN, "gcry_cipher_setiv(): %s", gcry_strerror(err));
    return GWEN_ERROR_GENERIC;
  }

  return 0;
}





