/*
 * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
 *
 * Author:     Iceyer <me@iceyer.net>
 *
 * Maintainer: Iceyer <me@iceyer.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "license_file.h"
#include "cbc_ase_crypt.h"
#include "rsa_crypt.h"
#include <openssl/hmac.h>

extern void print_it(const char* label, const byte* buff, size_t len);

static unsigned char hmac_key[] = "MIIEogIBAAKCAQEAuahhYKiOxXmsYT+/bMLy4CxAUZlC8yQriA1byzGSZMtv/E63nFE50lckwh4vapU8QIYE0pXEi0F1kjXtyZsbbkbz5n+g9PHDqJU6UVSTJOze0HimEjQcBh+QpHLmI5cmxiXgtSlyKNtl3GpcgvoMK/QfCnbn7UjL5O+NEw8xX1tDPxe4JZaEH4DG1s7lGCcX586iq3WMDTkhXYhuxkJCNGiJznQsfnbi5F2144ZkWmXs+wGO";

static const size_t hmac_digest_size = 32;

struct license_file *created_license_file(
    const char *username,
    const char *authorization_code,
    const char *product,
    const char *copyright,
    const char *edition,
    const char *version,
    const char *machine_code,
    u64  validity_begin,
    u64  validity_end,
    u64 licenses_number,
    const char* private_key_file)
{
    struct license_file * lf = NULL;
    EVP_PKEY *skey = NULL;
    u8 *crypt_data = NULL;
    u8* msg = NULL;
    u8* sig = NULL;
    u8* digest = NULL;
    size_t license_info_size = 0;
    size_t slen = 0;

    lf  = (struct license_file *)malloc(LICENSE_FILE_SIZE);
    memset(lf, 0, LICENSE_FILE_SIZE);

    lf->header.version = LICENSE_VERSION;
    lf->header.type = FileLicense;
    printf("%x\n", lf->header.type);
    lf->header.crypt_type = CryptAes;
    lf->header.crypt_key = CRYPT_KEY_ASEV1;
    lf->header.data_size = LICENSE_FILE_SIZE - LICENSE_FILE_HEADER_SIZE;

    strncpy((char*)lf->license.username, username, ARRAY_SIZE(lf->license.username));
    strncpy((char*)lf->license.authorize_code, authorization_code, ARRAY_SIZE(lf->license.authorize_code));
    strncpy((char*)lf->license.product, product, ARRAY_SIZE(lf->license.product));
    strncpy((char*)lf->license.copyright, copyright, ARRAY_SIZE(lf->license.copyright));
    strncpy((char*)lf->license.edition, edition, ARRAY_SIZE(lf->license.edition));
    strncpy((char*)lf->license.version, version, ARRAY_SIZE(lf->license.version));
    strncpy((char*)lf->license.machine_code, machine_code, ARRAY_SIZE(lf->license.machine_code));
    lf->license.validity_begin = validity_begin;
    lf->license.validity_end = validity_end;
    lf->license.licenses_number = licenses_number;
    license_info_size = sizeof(struct license_info);

    encrypt_init();

    // RSA signature
    FILE *pri = fopen (private_key_file, "r");
    if (NULL == pri) {
        printf("fopen license file '%s' failed", private_key_file);
        goto clean_up;
    }
    skey = (EVP_PKEY*)PEM_read_PrivateKey(pri, NULL, NULL, NULL);
    if (NULL == skey) {
        printf("PEM_read_PrivateKey '%s' failed", private_key_file);
        goto clean_up;
    }
    fclose(pri);
    msg = (u8*)&lf->license;

    rsa_sign(msg, license_info_size, &sig, &slen, skey);
    memcpy((u8*)lf->signature.rsa, sig, slen);

    // HMAC sha256 signature
    digest = HMAC(EVP_sha256(), hmac_key, strlen((char*)hmac_key), (u8*)msg, license_info_size, NULL, NULL);
    memcpy((u8*)lf->signature.ahs, digest, hmac_digest_size);

    crypt_data = (u8*) malloc(lf->header.data_size*2);
    license_aes_encrypt((u8*)&lf->license, lf->header.data_size, crypt_data);

    memcpy((u8*)&lf->license, crypt_data, lf->header.data_size);
    free((u8*)crypt_data);

clean_up:
    encrypt_cleanup();
    OPENSSL_free(sig);
    EVP_PKEY_free(skey);
    return lf;
}
