/*
 * (c) Copyright 2015 Samsung Research America, Inc.
 *                  All rights reserved
 *
 *  MPS Lab
 *
 * File: jwe.h
 * Author: r.kothari@samsung.com
 * Creation Date: Dec 4, 2015
 * Co-Author: zheng.z@samsung.com
 * Improved Date: Sep 6, 2016
 * Co-Author: jianwei.qian@samsung.com
 * Update Date: Aug 12, 2020
 *
 */
/*
 * Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Mobile Communication Division,
 * Digital Media & Communications Business, Samsung Electronics Co., Ltd.
 *
 * This software and its documentation are confidential and proprietary
 * information of Samsung Electronics Co., Ltd.  No part of the software and
 * documents may be copied, reproduced, transmitted, translated, or reduced to
 * any electronic medium or machine-readable form without the prior written
 * consent of Samsung Electronics.
 *
 * Samsung Electronics makes no representations with respect to the contents,
 * and assumes no responsibility for any errors that might appear in the
 * software and documents. This publication and the contents hereof are subject
 * to change without notice.
 */

#ifndef JWE_H
#define JWE_H
#include <stdint.h>
#include <stdbool.h>

#define DUMPSTRING(label, buf, buflen)  //invalidate DUMPSTRING. DUMPSTRING prints the string in log
#define DBG_DUMP(...)  //invalidate DUMPSTRING.
#define DBG_LOG(...)  //invalidate DUMPSTRING.

#define JWE_OK                            0x00000000

/* General Errors */
#define JWE_GEN_ERROR_INTERNAL                      0x00000101
#define JWE_GEN_ERROR_INVALID_INPUT_PARAM               0x00000102
#define JWE_GEN_ERROR_INVALID_INPUT_SIZE            0x00000103
#define JWE_GEN_ERROR_INVALID_OUTPUT_PARAM_SIZE         0x00000104
#define JWE_GEN_ERROR_BUFFER_OVERFLOW                   0x00000105
#define JWE_GEN_ERROR_BUFFER_NULL               0x00000106
#define JWE_GEN_ERROR_INSUFFICIENT_BUFFER           0x00000107
#define JWE_GEN_ERROR_MISSING_DATA              0x00000108

/* Cryptography (Cert & JWE) Errors */
#define JWE_CRYPT_ERROR_VERIFY_CERT                 0x00000121
#define JWE_CRYPT_ERROR_CERT_PARSE_FAILED           0x00000122
#define JWE_CRYPT_ERROR_KEY_PARSE_FAILED            0x00000123
#define JWE_CRYPT_ERROR_UNWRAP_FAILED               0x00000124
#define JWE_CRYPT_ERROR_WRAP_FAILED                 0x00000125
#define JWE_CRYPT_ERROR_UNEXPECTED_DATA             0x00000126
#define JWE_CRYPT_ERROR_MODULUS_ERROR               0x00000127
#define JWE_CRYPT_ERROR_EXPONENT_ERROR              0x00000128
#define JWE_CRYPT_ERROR_ENCRYPT_ERROR               0x00000129
#define JWE_CRYPT_ERROR_HMAC_ERROR                      0x00000130
#define JWE_CRYPT_ERROR_BASE64_DECODE_FAILED            0x00000131
#define JWE_CRYPT_ERROR_BASE64_ENCODE_FAILED            0x00000132
#define JWE_CRYPT_ERROR_GET_RANDOM_FAILED               0x00000133
#define JWE_CRYPT_ERROR_DECRYPT_ERROR               0x00000134
#define JWE_PROCESS_CP_JSONPARSE_ERROR                  0x00000135

typedef enum
cek_enc_alg_type
{
    CEK_ENC_ALG_NONE,
    CEK_ENC_ALG_RSA1_5,
    CEK_ENC_ALG_RSA_OAEP,
    CEK_ENC_ALG_MAX

} cek_enc_alg_type;

typedef enum
{
    CONTENT_ENC_ALG_NONE,
    CONTENT_ENC_ALG_A128GCM,
    CONTENT_ENC_ALG_A256GCM,
    CONTENT_ENC_ALG_A128CBC_HS256,
    CONTENT_ENC_ALG_MAX

} content_enc_alg_type;

typedef struct
{
    uint8_t * value;
    uint32_t  len;
} key_id;

typedef struct
{
    cek_enc_alg_type alg_type;
    content_enc_alg_type enc_type;
    key_id kid;
} jwe_params;

//#define DEBUG_JWE 1
//#define TEST_JWE  1

#define JWE_MIN_BUF_LEN  1024
#define JWE_JWS_MAX_BUF_LEN  4096//pay set it to 32*1024 but this big buf causes some strange error
#define JWE_MAX_BUF_LEN  JWE_JWS_MAX_BUF_LEN
#define JWE_MAX_CEK_SIZE 1024
#define JWE_MAX_IV_SIZE    16
#define JWE_MAX_TAG_SIZE   32
#define JWE_HEADER_BUF_LEN 1024

#define JWE_MAX_HDR_VALUE_SIZE 1024

/* Used internally to validate input parameters */
#define JWE_MODE_ENC 1
#define JWE_MODE_DEC 2

#define RSA2048_KEY_LEN                        256
#define RSA4096_KEY_LEN                        512
#define RSA_KEY_EXPO_LEN                       3
#define RSA_MAX_KEY_ID_LEN                     64//1024

//typedef struct rsa_pub_info
//{
//    uint8_t modulus[RSA2048_KEY_LEN];
//    uint32_t modulus_len;
//    uint8_t pub_expo[RSA_KEY_EXPO_LEN];
//    uint32_t pub_expo_len;
//} rsa_pubinfo_t;

typedef struct rsa_key_info
{
    uint8_t modulus[RSA2048_KEY_LEN];
    uint32_t modulus_len;
    uint8_t pub_expo[RSA_KEY_EXPO_LEN];
    uint32_t pub_expo_len;
    uint8_t priv_expo[RSA2048_KEY_LEN];
    uint32_t priv_expo_len;
    uint8_t kid[RSA_MAX_KEY_ID_LEN]; //key id, used as a hint of the key
    uint32_t kid_len;
} rsa_key_info_t;

//typedef struct rsa_key_id  // not used.
//{
//    uint32_t len;
//    uint8_t blob[RSA_MAX_KEY_ID_LEN];
//} rsa_keyid_t;

//typedef struct rsa_info
//{
//    rsa_key_id_t key_id;
//    rsa_pubinfo_t pub_info;
//    rsa_privinfo_t priv_info;
//} rsa_info_t;
//
///** Structure presenting long integer
// * If integer is not present, value must be null and len zero.
// **/
//typedef struct {
//    uint8_t *value;
//    uint32_t len;
//} LongInt_t;
//
//typedef struct {
//    LongInt_t  exponent;
//    LongInt_t  modulus;
//    LongInt_t  privateExponent;
//
//    struct {
//        LongInt_t Q;
//        LongInt_t P;
//        LongInt_t DQ;
//        LongInt_t DP;
//        LongInt_t Qinv;
//    } privateCrtKey;
//
//} rsaKey_t;
//
//typedef union
//{
//    rsaKey_t   *rsaKey;            /**< Pointer to RSA key. */
//} Key_t;




// ======================    quick API start    ======================
/**
 * create a JWE object from a plaintext payload using {"alg": "RSA-OAEP", "enc": "A128GCM"}
 */
uint32_t
create_jwe_payload (uint8_t *payload, uint32_t payload_len, rsa_key_info_t *key,
                    uint8_t *out, uint32_t  *out_len);

/**
 * create a JWE object from a plaintext payload using the provided alg_type and enc_type
 */
uint32_t
create_jwe_payload_with_algo (uint8_t *payload, uint32_t payload_len, rsa_key_info_t *key,
		cek_enc_alg_type alg_type, content_enc_alg_type enc_type,
                          uint8_t *out, uint32_t  *out_len);

/**
 * extract decoded plaintext payload from a JWE object using {"alg": "RSA-OAEP", "enc": "A128GCM"}
 */
uint32_t
extract_jwe_payload (uint8_t *payload, uint32_t payload_len, rsa_key_info_t *key,
                     uint8_t *out, uint32_t *out_len);

/**
 * extract decoded plaintext payload from a JWE object using the provided alg_type and enc_type
 */
uint32_t
extract_jwe_payload_with_algo (uint8_t *payload, uint32_t payload_len, rsa_key_info_t *key,
		cek_enc_alg_type alg_type, content_enc_alg_type enc_type,
                           uint8_t *out, uint32_t *out_len);
// ======================    quick API end    ======================




// the following are for internal use.

uint32_t
encode_append (uint8_t * data, uint32_t data_len,
               uint8_t * out_data, uint32_t out_len,
               bool first, uint32_t *bytes_added, uint8_t **pos_added);

uint32_t
extract_header_field (char *tag, uint8_t * in_data, uint32_t in_data_len,
                      char *value, uint32_t *value_len);

uint32_t
generate_jwe_payload (jwe_params * params, rsa_key_info_t * cek_enc_key,
                      const uint8_t * in_data, uint32_t in_len,
                      uint8_t * out_data, uint32_t * out_len);

uint32_t
extract_jwe_payload_internal ( jwe_params * params, rsa_key_info_t * cek_dec_key,
                               const uint8_t * in_data, uint32_t in_len,
                               uint8_t * out_data, uint32_t * out_len );
#endif /* JWE_H */
