/*
    $Source: /local/data/cvs/yellowbank/lib/c/clib/y_clib.h,v $
    $Revision: 1.4 $
    $State: Exp $
    $Date: 2007/10/26 18:36:15 $
    $Author: yrp001 $
    $Locker:  $

    Copyright 2007 (Y) Yellowbank
    https://www.yellowbank.com/
    Ronald Peterson

    All rights reserved.

    This file is part of y_clib.

    y_clib is free software; you can redistribute it and/or modify it
    under the terms of the GNU Affero GPL version 3.0.  These license
    terms can be found in the included file agpl-3.0.txt.
*/

#ifndef _Y_CLIB_
#define _Y_CLIB_

// #include <stdlib.h>
// #include <stdio.h>
#include <sys/types.h>
// #include <fcntl.h>
// #include <unistd.h>

#include <gmp.h>
#include <mhash.h>

// Undefine conflicting macros used by autoconf that
// shouldn't be in library headers anyway
#undef PACKAGE_VERSION
#undef PACKAGE_TARNAME
#undef PACKAGE_STRING
#undef PACKAGE_NAME
#undef PACKAGE_BUGREPORT

#define MAX_ERR_LEN 256
#define MAX_HASH_FILE_SIZE 2000000000

#define Y_OK 0
#define Y_OUT_OF_RANGE 1

#define Y_BAD_RANDOM -1
#define Y_NO_RANDOM 0
#define Y_GOOD_RANDOM 1

#define Y_HASH_ALLOC_FAILURE -1
#define Y_HASH_INIT_FAILURE 0
#define Y_HASH_OK 1

#define Y_LABEL_TOO_LONG 1
#define Y_MESSAGE_TOO_LONG 2
#define Y_HASH_ERROR 3

// in octets
#define Y_RAND_SEED_SIZE 8
#define Y_RAND_STATE_SIZE 128

typedef unsigned char y_oct_bin_t;
typedef unsigned char *y_oct_bin;
typedef struct {
      // This structure intentionally matches PostgreSQL's
      // expectation of TOAST'able data (i.e. varlena).
      u_int32_t length;
      y_oct_bin buf;
} y_octstr[1];

// NOTE: these structures must be initialized before use,
//       and cleared when no longer needed.
typedef struct {
      mpz_t n; // RSA modulus
      mpz_t e; // RSA public exponent
      mpz_t d; // RSA private exponent
} y_full_key;
//
typedef struct {
      mpz_t mod; // RSA modulus
      mpz_t exp; // RSA exponent (public or private)
} y_part_key;

#define Y_OS_LEN(os) (os->length)
#define Y_OS_STR(os) (os->buf)
#define Y_FULL_KEY_MOD(key_p) ((key_p)->n)   // modulus
#define Y_FULL_KEY_PUB(key_p) ((key_p)->e)   // public exponent
#define Y_FULL_KEY_PRIV(key_p) ((key_p)->d)  // private exponent
#define Y_PART_KEY_MOD(key_p) ((key_p)->mod) // modulus
#define Y_PART_KEY_EXP(key_p) ((key_p)->exp) // exponent

void y_octstr_init( y_octstr );
// zero all bytes and free memory
void y_octstr_clear( y_octstr );

void y_full_key_init( y_full_key * );
// zero all bytes and free memory
void y_full_key_clear( y_full_key * );
void y_part_key_init( y_part_key * );
// zero all bytes and free memory
void y_part_key_clear( y_part_key * );

// args: os (return), byte, number of bytes
void y_octstr_set( y_octstr, int, uint );
// args: os (return), byte, start (zero indexed), number of bytes
void y_octstr_set_count( y_octstr, int, uint, uint );
// args: os (return), number of bits to set. e.g.
// setting 6 bits -> 11111100
// setting 9 bits -> 11111111 10000000
void y_octstr_set_mask( y_octstr, uint );
// set all bits in 'string' where 'mask' bits are 1 to zero.
// args: os, mask
void y_octstr_mask_out( y_octstr, y_octstr );
// args: os (return), replacement string, insert position (zero indexed)
void y_octstr_replace_substr( y_octstr, y_octstr, uint );
// set from null terminated hex string
void y_octstr_set_from_cp_hex( y_octstr, char * );
// set from null terminated hex string
char *y_cp_hex_realloc_from_octstr( char *, y_octstr );

// return TRUE or FALSE
bool y_are_octstr_equal( y_octstr left, y_octstr right );
void y_print_os_as_hex( y_octstr );

uint y_octets_required_by_bigint( mpz_t );

// equivalent to PKCS 1v2.1 I2OSP function
// len of required octstr passed as argument
void y_octstr_set_from_gmp_int_xlen( y_octstr, mpz_t, uint );
// Same as above, but calc len internally.  Must use above version
// to properly implement RSA PKCS standard.
void y_octstr_set_from_gmp_int( y_octstr, mpz_t );

// equivalent to PKCS 1v2.1 OS2IP function
void y_gmp_int_set_from_octstr( mpz_t, y_octstr );

// args: destination, source
void y_octstr_copy( y_octstr, y_octstr );
// args: dest (return), left, right
void y_octstr_concat( y_octstr, y_octstr, y_octstr );

// encryption/decryption primitives
// args: cipher (return), pubkey, message
void RSAEP( mpz_t *, y_part_key *, mpz_t );
// args: message (return), privkey, cipher
void RSADP( mpz_t *, y_part_key *, mpz_t );

// signature/verification primitives
// args: signature (return), private key, message
void RSASP1( mpz_t *, y_part_key *, mpz_t );
// args: message (return), public key, signature
void RSAVP1( mpz_t *, y_part_key *, mpz_t );

// args: os, byte_count, random_source ("random" or "urandom")
// uint y_get_uint_dev_random( uint, uint, const char * );
// args: octet string (return), octets, random source
// int y_get_os_dev_random( y_octstr, uint, const char * );
int y_get_os_dev_random( y_octstr, uint );
// args: hex, octets
char *y_realloc_random_hex( char *, uint );

// args: rand (return), random_source, seed_len, max_bits
void y_gen_mpz_random( mpz_t, const char *, uint, uint );
// args: rand (return), random_source, seed_len, bits
void y_gen_mpz_random_of_bit_len( mpz_t, uint, uint );
// args: prime (return), random_source, seed_len, bits );
void y_generate_random_prime( mpz_t, uint, uint );
// args: key (return), random_source, seed_length, bits

// args: ret (return), left, right
void y_exclusive_or( y_octstr, y_octstr, y_octstr );

// args: masked string (return), string, mask length, hash type
void y_mgf1( y_octstr, y_octstr, uint, char * );

// args: EM (return), message, hash type, label, k (length of modulus 'n')
void y_eme_oaep( y_octstr, y_octstr, char *, char *, uint );

// args: EM - encoded message (return),
//        M - message,
//        emBits,
//        emLen,
//        hash_type,
//        sLen - salt length
void y_emsa_pss_encode( y_octstr, y_octstr, uint, uint, char *, uint );


#define CONSISTENT 1
#define INCONSISTENT 0
// return: CONSISTENT or INCONSISTENT
// args: M - message,
//       EM - encoded message,
//       emBits (= modBits - 1),
//       hash_type,
//       saltLen
int
y_emsa_pss_verify( y_octstr, y_octstr, uint, char *, uint );


////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// PUBLIC FUNCTIONS


//_______________________________________________________________________
// args: hash (return),
//       hash type,
//       data,
//       data length,
//       hash length (return)
//_______________________________________________________________________
int
y_calc_mhash( y_octstr,
              const char *,
              char *,
              uint,
              uint * );



//_______________________________________________________________________
//_______________________________________________________________________
void
y_generate_rsa_keys( y_full_key *,
                     uint,
                     uint );


//_______________________________________________________________________
//_______________________________________________________________________
void
y_set_pub_key( y_part_key *,
               y_full_key );


//_______________________________________________________________________
//_______________________________________________________________________
void
y_set_priv_key( y_part_key *,
                y_full_key );


//_______________________________________________________________________
// args: ciphertext (return),
//       message,
//       public key,
//       hash type,
//       label (empty string by default)
//_______________________________________________________________________
void
y_rsaes_oaep_encrypt( y_octstr,
                      y_octstr,
                      y_part_key *,
                      char *,
                      char * );
 

//_______________________________________________________________________
// args: message (return),
//       ciphertext,
//       private key,
//       hash type,
//       label
//_______________________________________________________________________
void
y_rsaes_oaep_decrypt( y_octstr,
                      y_octstr,
                      y_part_key *,
                      char *,
                      char * );


//_______________________________________________________________________
// args: S - signature (return),
//       M - message,
//       K - private key,
//       hash_type,
//       saltLen
//_______________________________________________________________________
void
y_rsassa_pss_sign( y_octstr,
                   y_octstr,
                   y_part_key *,
                   char *,
                   uint );


//_______________________________________________________________________
#define VALID_SIGNATURE 1
#define INVALID_SIGNATURE 0
// return: VALID_SIGNATURE or INVALID_SIGNATURE
// args:
//       M - message to be verified,
//       S - signature to be verified
//       K - public key),
//       hash_type
//       saltLen
//_______________________________________________________________________
int
y_rsassa_pss_verify( y_octstr,
                     y_octstr,
                     y_part_key *,
                     char *,
                     uint );



//______________________________________________________________________
//______________________________________________________________________
int
y_octstr_from_file( y_octstr filedat,
                    const char *filename,
                    char *errstr );


//______________________________________________________________________
// append 'depth' directories to 'basedir' using characters from the
// beginning of 'hash'.  E.g. - if 'basedir' is '/some/place', 'hash' is
// 'abc123', and 'depth' is 2, then the result would be
// '/some/place/a/b'.
//______________________________________________________________________
char
*y_mkdir_and_realloc_hashdir_name( char *hashdir,
                                   const char *basedir,
                                   const char *hash,
                                   uint depth,
                                   char *errstr );


//______________________________________________________________________
// be sure to free hashFile and errstr
//______________________________________________________________________
char
*y_octstr_to_hashfile( y_octstr os,
                      const char *basedir,
                      const char *hashType,
                      uint depth,
                      char *errstr );

#endif // _Y_CLIB_
