// fboot_decrypt.cpp : Defines the entry point for the console application.
//

//#include "stdafx.h"
#include <cryptlib.h>
#include <rsa.h>
#include <integer.h>

//#pragma comment(lib, "cryptlib.lib")
#pragma comment(lib, "cryptopp.lib")

#define byte unsigned char

namespace pubkey {
    const byte raw_le[] = {
    0xE9, 0xE8, 0xCB, 0x6A, 0xFB, 0x12, 0xE4, 0xEB,
    0xCA, 0xA0, 0x89, 0xFC, 0x92, 0x80, 0x08, 0xE9,
    0x91, 0x32, 0x82, 0xCD, 0xF6, 0x54, 0xA2, 0x46,
    0x82, 0x08, 0x0D, 0x7D, 0x0E, 0x88, 0x0D, 0x78,
    0x19, 0x8F, 0xC8, 0x62, 0x83, 0x6D, 0x92, 0xFD,
    0xF5, 0xF5, 0x66, 0xF2, 0x57, 0x9B, 0xA4, 0xAE,
    0xAE, 0x78, 0xA8, 0xC1, 0xF8, 0x2A, 0x7C, 0xC7,
    0xFA, 0x8E, 0x73, 0x00, 0x50, 0x54, 0x80, 0xF9,
    0x25, 0x71, 0xEA, 0xB2, 0x49, 0x49, 0x68, 0x5D,
    0x19, 0xDC, 0x70, 0x5C, 0x18, 0xA1, 0x95, 0x46,
    0x08, 0x00, 0x47, 0x49, 0xEC, 0xA8, 0xD1, 0xB3,
    0x49, 0xB2, 0xAC, 0xF4, 0xE1, 0xBB, 0x11, 0xCF,
    0x14, 0xD4, 0x21, 0x07, 0x7B, 0x4B, 0x99, 0x98,
    0x91, 0xE0, 0xA6, 0x2F, 0xB0, 0x09, 0x60, 0x4D,
    0x67, 0xFB, 0x7C, 0x95, 0xDC, 0x5F, 0xA4, 0xB7,
    0x1B, 0xE7, 0x3D, 0x72, 0x00, 0x64, 0x9C, 0xAA 
	};

    const size_t size = sizeof(raw_le) / sizeof(byte);
    byte raw_be[size];

    void init()
    {
        static bool initialized = false;
        if (!initialized)
        {
            for (int i = 0, j = size; i < j; i++)
                raw_be[i] = raw_le[size - i - 1];
            initialized = true;
        }
    }

    const byte* get()
    {
        init();
        return raw_be;
    }
}; //namespace pubkey

template <typename _Type>
void reverse(_Type* start, _Type* end)
{
    while (start < end)
    {
        *start ^= *end;
        *end ^= *start;
        *start ^= *end;
        start++;
        end--;
    }
}

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        return 1;
    }

    std::ifstream ifs;
    ifs.open(argv[1], std::ios::binary);
    if (!ifs)
    {
        return 2;
    }

    ifs.seekg(std::streampos(0xB000));

    CryptoPP::word32 size;
    ifs.read((char*)&size, sizeof(size));

    std::string outname;
    const char* name = argv[1];
    const char* ext = strrchr(name, '.');
    if (ext)
    {
        outname.assign(name, ext-name);
        outname += ".dec";
    }
    else
    {
        outname = name;
        outname += ".dec";
    }

    std::ofstream ofs;
    ofs.open(outname.c_str(), std::ios::binary);
    if (!ofs)
    {
        return 3;
    }

    const byte* pubkey_n = pubkey::get();

    CryptoPP::Integer n(pubkey_n, pubkey::size);
    CryptoPP::Integer e(65537);

    std::cout << "n = " << n << std::endl;
    std::cout << "e = " << e << std::endl;

    CryptoPP::RSAFunction rsa;
    rsa.Initialize(n, e);

    while (size > 0)
    {
        byte ciphertext[pubkey::size];
        ifs.read((char*)&ciphertext[0], pubkey::size);

        reverse(&ciphertext[0], &ciphertext[pubkey::size - 1]);
        CryptoPP::Integer c(ciphertext, pubkey::size);
        CryptoPP::Integer d = rsa.ApplyFunction(c);

        std::cout << "d = " << d << std::endl;

        byte plaintext[pubkey::size];
        d.Encode(plaintext, pubkey::size);
        reverse(&plaintext[0], &plaintext[pubkey::size - 1]);

        ofs.write((const char*)&plaintext[0], pubkey::size /*0x78*/);

        size -= pubkey::size;
    }

    return 0;
}
