PoC-Doc-Delivery / PoC_Execution / getDeliveryData.js
getDeliveryData.js
Raw
const EthCrypto = require('eth-crypto');
const crypto = require('crypto');
const fs = require('fs');
const { idData, prA, puB, prB } = require('./parameters');

// File paths
const originalFile = './paper.pdf';
const encryptedFile = './C.pdf';
const decryptedFile = './decrypted.pdf';
const keyFile = './k.txt';
const ivFile = './iv.txt';
const HMACFILE = './HMAC.txt';
const hFile = './h.txt';
const idFile = './id.txt';
const fcFile = './fc.txt';


// Function to encrypt the notification message
const encryptM = async () => {

    try {
        // Read the original file into a buffer
        const fileBuffer = fs.readFileSync(originalFile);

        // Encrypt the file buffer using ECIES
        const ECIES_output_params = await EthCrypto.encryptWithPublicKey(
            puB,
            fileBuffer.toString('hex')
        );

        console.log("ECIES output params: ", ECIES_output_params);

        // Compress the ephemeral public key from the encryption output
        const ephemPublicKeyCompressed = EthCrypto.publicKey.compress(
            ECIES_output_params.ephemPublicKey
        );

        // Convert the compressed ephemeral public key to a hex string with '0x' prefix
        const k = `0x${ephemPublicKeyCompressed}`;

        // Convert the initialization vector (IV) from hex to base64
        const bufferIV = Buffer.from(ECIES_output_params.iv, 'hex');
        const iv = bufferIV.toString('base64');

        // Convert the HMAC (Hash-based Message Authentication Code) from hex to base64
        const bufferHMAC = Buffer.from(ECIES_output_params.mac, 'hex');
        const HMAC = bufferHMAC.toString('base64');

        // Save the encryption output params to their respective files
        fs.writeFileSync(encryptedFile, ECIES_output_params.ciphertext, 'hex');
        fs.writeFileSync(keyFile, k);
        fs.writeFileSync(ivFile, iv);
        fs.writeFileSync(HMACFILE, HMAC);
    } catch (error) {
        console.error('Error reading or writing file:', error);
    }
}

// Function to compute h
const getH = async () => {

    try {
        // Read the encrypted file into a buffer
        const fileBuffer = fs.readFileSync(encryptedFile);

        // Create a SHA-256 hash object
        const hashSum = crypto.createHash('sha256');
        hashSum.update(fileBuffer);

        // Compute the hash as a hexadecimal string
        const hex = hashSum.digest('hex');

        // Format the hash as a Solidity-compatible bytes32 string
        const solidityBytes32 = `0x${hex}`;
        console.log('SHA-256 file hash (Bytes32):', solidityBytes32);

        // Write the hash to the specified file
        fs.writeFileSync(hFile, solidityBytes32);
    } catch (error) {
        console.error('Error reading or hashing file:', error);
    }
}

// Function to obtain the notification ID
const getID = async () => {

    try {
        // Read the h file into a buffer
        const fileBuffer = fs.readFileSync(hFile);
        const h = fileBuffer.toString();

        // Calculate the Keccak-256 hash of the given inputs to get the notification ID
        const signHash = EthCrypto.hash.keccak256([
            {
                type: 'address',
                value: idData.addrA
            }, {
                type: 'address',
                value: idData.addrB
            }, {
                type: 'address',
                value: idData.addrSC
            }, {
                type: 'uint256',
                value: idData.tm
            }, {
                type: 'uint256',
                value: idData.td
            }, {
                type: 'bytes32',
                value: h
            }
        ]);

        // Write the calculated hash to the file specified by idFile
        fs.writeFileSync(idFile, signHash);
        console.log("id = ", signHash);
    } catch (error) {
        console.error('Error writing file:', error);
    }
}

// Function to obtain f(C)
const getFC = async () => {

    try {
        // Read the contents of the files idFile, hFile and convert them to a string
        const idBuffer = fs.readFileSync(idFile);
        const id = idBuffer.toString();
        const hBuffer = fs.readFileSync(hFile);
        const h = hBuffer.toString();

        // Create a keccak256 hash of the concatenated values
        const signHash = EthCrypto.hash.keccak256([
            {
                type: 'bytes32',
                value: id
            }, {
                type: 'uint256',
                value: idData.tm
            }, {
                type: 'uint256',
                value: idData.td
            }, {
                type: 'bytes32',
                value: h
            }
        ]);

        // Sign the keccak256 hash with the private key prA
        const fc = EthCrypto.sign(
            prA,
            signHash
        );

        // Write the signed hash (fc) to the fcFile
        fs.writeFileSync(fcFile, fc);
        console.log("Fc: ", fc);
    } catch (error) {
        console.error('Error writing file:', error);
    }
}

// Function to verify the signer of f(C)
const verifyFC = async () => {

    try {
        // Read the contents of the files idFile, hFile, fcFile and convert them to a string
        const idBuffer = fs.readFileSync(idFile);
        const id = idBuffer.toString();
        const hBuffer = fs.readFileSync(hFile);
        const h = hBuffer.toString();
        const fc = fs.readFileSync(fcFile, 'utf8');

        // Compute the keccak256 hash of the given data fields
        const signHash = EthCrypto.hash.keccak256([
            {
                type: 'bytes32',
                value: id
            }, {
                type: 'uint256',
                value: idData.tm
            }, {
                type: 'uint256',
                value: idData.td
            }, {
                type: 'bytes32',
                value: h
            }
        ]);

        // Recover the signer's address from the given signature (fc) and the hash (signHash)
        const signer = EthCrypto.recover(
            fc,
            signHash
        );

        // Log success message and the signer's address (@A)
        console.log('FC verified successfully!');
        console.log('Signer: ', signer);

    } catch (error) {
        console.error('Error reading file:', error);
    }
}

// Function to decrypt C and recover the original file
const decryptC = async () => {

    try {
        // Read encrypted data from file
        const encryptedBuffer = fs.readFileSync(encryptedFile, 'hex');

        // Read HMAC and encryption key from files
        const hmacBase64 = fs.readFileSync(HMACFILE, 'utf8');
        const key = fs.readFileSync(keyFile, 'utf8');

        // Decompress the public key for encryption
        const ephemPublicKey = EthCrypto.publicKey.decompress(
            key.substring(2) // Removing '0x' prefix before decompression
        );

        // Format the decompressed public key with its prefix '04'
        const k = `04${ephemPublicKey}`;

        // Read Initialization Vector (IV) from file and convert from Base64 to string
        const ivBase64 = fs.readFileSync(ivFile, 'utf8');
        const ivBuffer = Buffer.from(ivBase64, 'base64');
        const iv = ivBuffer.toString('hex');

        // Convert HMAC from Base64 to hexadecimal string
        const hmacBuffer = Buffer.from(hmacBase64, 'base64');
        const hmac = hmacBuffer.toString('hex');

        // Prepare parameters required for ECIES decryption
        const ECIES_output_params = {
            iv: iv,
            ephemPublicKey: k,
            ciphertext: encryptedBuffer,
            mac: hmac
        };

        // Decrypt the encrypted data using a private key (prB) 
        const decrypted = await EthCrypto.decryptWithPrivateKey(
            prB,
            ECIES_output_params
        );

        // Convert decrypted data from hexadecimal string to Buffer and write to a file
        const decryptedBuffer = Buffer.from(decrypted, 'hex');
        fs.writeFileSync(decryptedFile, decryptedBuffer);
    } catch (error) {
        console.error('Error reading or writing file:', error);
    }
}

// Execute all functions in order
const execute = async () => {
    await encryptM();
    await getH();
    await getID();
    await getFC();
    await verifyFC();
    await decryptC();
}

execute();