/* XmlRsaKey.c */

#include "diCrPKI.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

// Compiler-specific explicit link to library in current directory
// This works in MSVC and Borland - you may need to do otherwise
#pragma comment(lib, ".\\diCrPKI.lib")
// Alternatively, link explicitly to Object/Library Module "diCrPKI.lib"


void ReadInXmlKey(void)
/* Read in a private key from an XML file that we have created ourselves "by hand" */
{
    long res, len;
    const char *xmlfile = "userkey.xml";
    const char *outfile = "userencprivkey.bin";
    char *lpszPrivateKey, *lpszXML;
    FILE *fp;

    // Read in the XML file to a string
    fp = fopen(xmlfile, "rb");
    assert(fp);
    // Get its length
    fseek(fp, 0, SEEK_END);
    len = ftell(fp);
    assert(len > 0);
    rewind(fp);
    // Read into memory - note extra byte for null
    lpszXML = calloc(len+1, 1);
    assert(lpszXML);
    fread(lpszXML, 1, len, fp);
    fclose(fp);

    printf("XML (as read)=\n%s\n", lpszXML);

    // Now convert from XML to crPKI internal format
    len = RSA_FromXMLString(NULL, 0, lpszXML, 0);
    if (len < 0) printf("Error code %ld\n", len);
    assert(len > 0);
    lpszPrivateKey = malloc(len+1);
    res = RSA_FromXMLString(lpszPrivateKey, len, lpszXML, 0);
    assert(res > 0);

    // Display in internal base64 format
    printf("Private key (internal format)=\n%s\n", lpszPrivateKey);

    // Verify that we have a valid RSA key
    res = RSA_CheckKey(lpszPrivateKey, 0);
    printf("%s\n", (res == 0 ? "Key is a valid RSA private key" : "Key is INVALID!"));
    len = RSA_KeyBits(lpszPrivateKey);
    printf("Key is %ld bits long\n", len);

    // You can now use lpszPrivate key to carry out signing/decryption
    //...

    // We can also save this as an encrypted PKCS-8 file
    res = RSA_SaveEncPrivateKey(outfile, lpszPrivateKey, 1024, "password", 0);
    if (res == 0)
        printf("Saved encrypted private key as '%s'.\n", outfile);
    else
        printf("Failed to save encrypted private key: error code %ld\n", res);

    // Free allocated memory
    free(lpszPrivateKey);
    free(lpszXML);

}

void ReadInXmlPublicKey(char *xmlfile)
/* Read in a public key from an XML file that we have created ourselves "by hand" */
{
    long res, len;
    char *lpszPublicKey, *lpszXML;
    const char *outfile = "userpubkey.bin";
    FILE *fp;

    /* We can do this two ways depending what data we have: 
    1) from the public/private key pair data using the PKI_XML_EXCLPRIVATE option
    2) from an XML file that just contains the public key components
    */
    
    // Read in the XML file to a string
    fp = fopen(xmlfile, "rb");
    assert(fp);
    // Get its length
    fseek(fp, 0, SEEK_END);
    len = ftell(fp);
    assert(len > 0);
    rewind(fp);
    // Read into memory - note extra byte for null
    lpszXML = calloc(len+1, 1);
    assert(lpszXML);
    fread(lpszXML, 1, len, fp);
    fclose(fp);

    printf("XML (as read)=\n%s\n", lpszXML);

    // Now convert from XML to crPKI internal format
    len = RSA_FromXMLString(NULL, 0, lpszXML, PKI_XML_EXCLPRIVATE);
    if (len < 0) printf("Error code %ld\n", len);
    assert(len > 0);
    lpszPublicKey = malloc(len+1);
    res = RSA_FromXMLString(lpszPublicKey, len, lpszXML, PKI_XML_EXCLPRIVATE);
    assert(res > 0);

    // Display in internal base64 format
    printf("Public key (internal format)\n=%s\n", lpszPublicKey);

    // Verify that we have an RSA public key (you can't validate it)
    res = RSA_CheckKey(lpszPublicKey, 0);
    printf("%s\n", (res == 1 ? "Key is an RSA public key" : "Key is INVALID!"));
    len = RSA_KeyBits(lpszPublicKey);
    printf("Key is %ld bits long\n", len);


    // We can also save this as a PKCS-1 RSAPublicKey file
    res = RSA_SavePublicKey(outfile, lpszPublicKey, 0);
    if (res == 0)
        printf("Saved public key as '%s'.\n", outfile);
    else
        printf("Failed to save public key: error code %ld\n", res);

    // Free allocated memory
    free(lpszPublicKey);
    free(lpszXML);

}

int main()
{
    ReadInXmlKey();
    ReadInXmlPublicKey("userkey.xml");
    ReadInXmlPublicKey("userpublickey.xml");

    return 0;
}