pkcs1_oaep_encrypt (size_t key_size,
	       void *random_ctx, nettle_random_func *random,
	       /* 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 message_length, const uint8_t *message,
	       mpz_t m)
{
  size_t ps_len = key_size - message_length - (2*hlen) - 2, dbMask_len = key_size - hlen - 1, i;
  uint8_t lHash[hlen], k[hlen], seedMask[hlen], maskedSeed[hlen];
  int ret = 1;

  if (key_size < (2*hlen) - 2 || message_length > key_size - (2*hlen) - 2)
    {
      return 0;
    }
  uint8_t *em, *maskedDB, *dbMask, *db;

  em = o_malloc(dbMask_len + hlen + 1);
  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);

  // DB = lHash || PS || 0x01 || M.

  memcpy(db, lHash, hlen);
  memset(db+hlen, 0, ps_len);
  memset(db+hlen+ps_len, 1, 1);
  memcpy(db+hlen+ps_len+1, message, message_length);

  random(random_ctx, hlen, k);

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

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

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

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

  // EM = 0x00 || maskedSeed || maskedDB.

  em[0] = 0;
  memcpy(em+1, maskedSeed, hlen);
  memcpy(em+1+hlen, maskedDB, dbMask_len);

  nettle_mpz_set_str_256_u(m, dbMask_len + hlen + 1, em);

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

  return ret;
}
pkcs1_oaep_encrypt (size_t key_size,
	       void *random_ctx, nettle_random_func *random,
	        
	       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 message_length, const uint8_t *message,
	       mpz_t m)
{
  size_t ps_len = key_size - message_length - (2*hlen) - 2, dbMask_len = key_size - hlen - 1, i;
  uint8_t lHash[hlen], k[hlen], seedMask[hlen], maskedSeed[hlen];
  int ret = 1;

  if (key_size < (2*hlen) - 2 || message_length > key_size - (2*hlen) - 2)
    {
      return 0;
    }
  uint8_t *em, *maskedDB, *dbMask, *db;

  em = o_malloc(dbMask_len + hlen + 1);
  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);

   

  memcpy(db, lHash, hlen);
  memset(db+hlen, 0, ps_len);
  memset(db+hlen+ps_len, 1, 1);
  memcpy(db+hlen+ps_len+1, message, message_length);

  random(random_ctx, hlen, k);

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

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

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

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

   

  em[0] = 0;
  memcpy(em+1, maskedSeed, hlen);
  memcpy(em+1+hlen, maskedDB, dbMask_len);

  nettle_mpz_set_str_256_u(m, dbMask_len + hlen + 1, em);

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

  return ret;
}