pkcs1_oaep_decrypt (size_t key_size,
	       const mpz_t m,
	       /* Hash function */
	       size_t hlen,
	       void * ctx, const struct nettle_hash *hash, nettle_hash_init_func *hash_init, nettle_hash_update_func *hash_update, nettle_hash_digest_func *hash_digest,
	       size_t label_length, const uint8_t *label,
	       size_t *length, uint8_t *message)
{
  int ret = 1;
  size_t dbMask_len = key_size-1-hlen, i;
  uint8_t lHash[hlen], k[hlen], seedMask[hlen], maskedSeed[hlen];

  uint8_t *em, *maskedDB, *dbMask, *db;

  em = o_malloc(key_size);
  maskedDB = o_malloc(dbMask_len);
  dbMask = o_malloc(dbMask_len);
  db = o_malloc(dbMask_len);

  // lHash = Hash(L)
  hash_init(ctx);
  hash_update(ctx, label_length, label);
  hash_digest(ctx, hlen, lHash);

  nettle_mpz_get_str_256(key_size, em, m);

  if (em[0])
    {
      ret = 0;
    }

  memcpy(maskedSeed, em+1, hlen);
  memcpy(maskedDB, em+1+hlen, key_size-1-hlen);

  // seedMask = MGF(maskedDB, hLen).
  hash_init(ctx);
  hash_update(ctx, dbMask_len, maskedDB);
  pss_mgf1(ctx, hash, hlen, seedMask);

  // seed = maskedSeed \xor seedMask.
  for (i=0; i<hlen; i++)
    {
      k[i] = maskedSeed[i]^seedMask[i];
    }

  // dbMask = MGF(seed, k - hLen - 1).
  hash_init(ctx);
  hash_update(ctx, hlen, k);
  pss_mgf1(ctx, hash, dbMask_len, dbMask);

  // DB = maskedDB \xor dbMask.
  for (i=0; i<dbMask_len; i++)
    {
      db[i] = maskedDB[i]^dbMask[i];
    }

  if (!memeql_sec(db, lHash, hlen))
    {
      ret = 0;
    }

  for (i=hlen; i<dbMask_len-1; i++)
    {
      if (db[i] == 0x01)
      {
        break;
      }
    }

  if (i < dbMask_len-1 && *length >= dbMask_len-i-1 && i < dbMask_len-1)
  {
    *length = dbMask_len-i-1;
    memcpy(message, db+i+1, *length);
  }
  else
  {
    ret = 0;
  }

  o_free(em);
  o_free(maskedDB);
  o_free(dbMask);
  o_free(db);

  return ret;
}
pkcs1_oaep_decrypt (size_t key_size,
	       const mpz_t m,
	        
	       size_t hlen,
	       void * ctx, const struct nettle_hash *hash, nettle_hash_init_func *hash_init, nettle_hash_update_func *hash_update, nettle_hash_digest_func *hash_digest,
	       size_t label_length, const uint8_t *label,
	       size_t *length, uint8_t *message)
{
  int ret = 1;
  size_t dbMask_len = key_size-1-hlen, i;
  uint8_t lHash[hlen], k[hlen], seedMask[hlen], maskedSeed[hlen];

  uint8_t *em, *maskedDB, *dbMask, *db;

  em = o_malloc(key_size);
  maskedDB = o_malloc(dbMask_len);
  dbMask = o_malloc(dbMask_len);
  db = o_malloc(dbMask_len);

   
  hash_init(ctx);
  hash_update(ctx, label_length, label);
  hash_digest(ctx, hlen, lHash);

  nettle_mpz_get_str_256(key_size, em, m);

  if (em[0])
    {
      ret = 0;
    }

  memcpy(maskedSeed, em+1, hlen);
  memcpy(maskedDB, em+1+hlen, key_size-1-hlen);

   
  hash_init(ctx);
  hash_update(ctx, dbMask_len, maskedDB);
  pss_mgf1(ctx, hash, hlen, seedMask);

   
  for (i=0; i<hlen; i++)
    {
      k[i] = maskedSeed[i]^seedMask[i];
    }

   
  hash_init(ctx);
  hash_update(ctx, hlen, k);
  pss_mgf1(ctx, hash, dbMask_len, dbMask);

   
  for (i=0; i<dbMask_len; i++)
    {
      db[i] = maskedDB[i]^dbMask[i];
    }

  if (!memeql_sec(db, lHash, hlen))
    {
      ret = 0;
    }

  for (i=hlen; i<dbMask_len-1; i++)
    {
      if (db[i] == 0x01)
      {
        break;
      }
    }

  if (i < dbMask_len-1 && *length >= dbMask_len-i-1 && i < dbMask_len-1)
  {
    *length = dbMask_len-i-1;
    memcpy(message, db+i+1, *length);
  }
  else
  {
    ret = 0;
  }

  o_free(em);
  o_free(maskedDB);
  o_free(dbMask);
  o_free(db);

  return ret;
}