Document Decryption Guide

Document Decryption Guide

This guide provides a step-by-step explanation of the decryption process for the encrypted file in the result of document/download. The scheme combines RSA (asymmetric encryption) to encrypt a symmetric key and AES (symmetric encryption) in CBC mode to encrypt the file contents. The goal is to decrypt an encrypted file (998159345291_OUT.enc) into a decrypted output file (result.zip) using the provided RSA private key, encrypted symmetric key, and initialization vector (IV).



Prerequisites

After the document/download request - you will receive a response for a .zip file containing the required files.

  • Required Files:

    • RSA private key (e.g., keypair.pem in PEM format).

    • Encrypted symmetric key (e.g., 998159345291_OUT.enc.key, base64-encoded).

    • Initialization vector (IV, e.g., 998159345291_OUT.enc.iv, plaintext or trimmed text).

    • Encrypted file (e.g., 998159345291_OUT.enc, containing base64-encoded AES ciphertext).

  • Cryptographic Library: Use a library supporting RSA and AES (e.g., OpenSSL, PyCryptodome for Python, Crypto++ for C++, or Java's JCE).



Step 1: Understand the Encryption Scheme

  • Hybrid Encryption: The file uses a hybrid approach:

    • A 256-bit symmetric key (AES key) was used to encrypt the file contents.

    • The symmetric key was encrypted with an RSA public key.

    • The file is encrypted using AES-256 in CBC mode, with a fixed IV.

  • File Structure:

    • The encrypted file (998159345291_OUT.enc) contains base64-encoded AES ciphertext.

    • The encrypted symmetric key (998159345291_OUT.enc.key) is base64-encoded.

    • The IV (998159345291_OUT.enc.iv) is plaintext (trimmed of whitespace).

    • The original plaintext (before encryption) is base64-encoded, requiring an additional decode after decryption.

  • Output: The decrypted file will be a ZIP file (result.zip).



Step 2: Load the RSA Private Key

  • Objective: Read and parse the RSA private key to decrypt the symmetric key.

  • Steps:

    1. Read the private key file (e.g., keypair.pem) into memory.

    2. Parse the key using your cryptographic library (e.g., load as PEM format).

    3. Configure RSA decryption with PKCS1 padding (RSA PKCS1 encryption was likely used to encrypt the symmetric key).

  • Example Libraries:

    • Python (PyCryptodome): RSA.import_key(open("keypair.pem").read()).

    • OpenSSL (CLI): Use openssl rsautl -decrypt -inkey keypair.pem.

    • Java (JCE): KeyFactory.getInstance("RSA").generatePrivate() with a PEM parser.

  • Security Note: Ensure the private key is stored securely and not exposed.



Step 3: Decrypt the Symmetric Key

  • Objective: Use the RSA private key to decrypt the encrypted symmetric key.

  • Steps:

    1. Read the encrypted symmetric key file (998159345291_OUT.enc.key).

    2. Base64-decode the contents to get the raw encrypted key (typically 256 bytes for RSA-2048).

    3. Decrypt the key using the RSA private key with PKCS1 padding.

    4. Verify the decrypted key is 32 bytes (256 bits) for AES-256. If not, there may be an issue with the key or padding.

  • Output: A 256-bit (32-byte) AES symmetric key.

  • Error Handling: If decryption fails, check the private key, ensure the encrypted key matches the public key used, or verify padding.



Step 4: Load the Initialization Vector (IV)

  • Objective: Retrieve the IV for AES-CBC decryption.

  • Steps:

    1. Read the IV file (998159345291_OUT.enc.iv).

    2. Trim any whitespace (e.g., newlines) to get the raw IV.

    3. Ensure the IV is 16 bytes (128 bits) for AES-CBC (standard AES block size).

  • Note: If the IV is base64-encoded or in another format, decode it accordingly. The provided code assumes plaintext.


Step 5: Decrypt the File in Chunks

  • Steps:

    1. Open the encrypted file (998159345291_OUT.enc) in read mode and the output file (result.zip) in binary write mode.

    2. Read the encrypted file in chunks (e.g., 7296 bytes, or adjust based on encryption chunking).

    3. For each chunk:

      • Base64-decode the chunk to get the raw AES ciphertext.

      • Initialize an AES-256-CBC cipher with the decrypted symmetric key and IV.

      • Use PKCS7 padding (standard for AES).

      • Decrypt the ciphertext to obtain plaintext.

      • Trim trailing null bytes.

      • Base64-decode the plaintext.

    4. Write the final plaintext to the output file.

    5. Close both files.



Code Examples

Quote
<?php
require 'vendor/autoload.php';

use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\Rijndael;

const PRIVATE_KEY_FILENAME =  __DIR__.'/keypair.pem';
const OUT_ENC_KEY_FILENAME =  __DIR__.'/998159345291_OUT.enc.key';
const OUT_ENC_IV_FILENAME =  __DIR__.'/998159345291_OUT.enc.iv';
const OUT_ENC_FILENAME =  __DIR__.'/998159345291_OUT.enc';

function getKey() {
    $privateKeyContents = file_get_contents(PRIVATE_KEY_FILENAME);
    $privateKey = RSA::load($privateKeyContents)->withPadding(RSA::ENCRYPTION_PKCS1);

    $encryptedKey = base64_decode(file_get_contents(OUT_ENC_KEY_FILENAME));

    $symmetricKey = $privateKey->decrypt($encryptedKey);

    if (strlen($symmetricKey) !== 32) {
        throw new Exception('Decrypted key length is incorrect.');
    }

    return $symmetricKey;
}

function decryptRjnd($ciphertext) {
    $key = getKey();
    $iv = trim(file_get_contents(OUT_ENC_IV_FILENAME));
    $ciphertext = base64_decode($ciphertext);

    $cipher = new Rijndael('cbc');
    $cipher->setKey($key);
    $cipher->setKeyLength(256);
    $cipher->setBlockLength(256);
    $cipher->setIV($iv);
    $cipher->disablePadding();

    try {
        $plaintext = $cipher->decrypt($ciphertext);
        return rtrim($plaintext, "\0");

    } catch (BadDecryptionException $e) {
        throw new Exception('Decryption failed: ' . $e->getMessage());
    }
}

function decrypt_file($input_file, $output_file) {
    $input_file_handle = @fopen($input_file, "r");
    $output_file_handle = @fopen($output_file, 'wb');
    if (!$input_file_handle) {
        throw new Exception("Could not open input file");
    }
    if (!$output_file_handle) {
        throw new Exception("Could not open output file");
    }

    while (!feof($input_file_handle)) {
        $buffer = fread($input_file_handle, 7296);
        $decrypted_string = decryptRjnd($buffer);
        fwrite($output_file_handle, base64_decode($decrypted_string));
    }

    fclose($input_file_handle);
    fclose($output_file_handle);
    return true;
}

decrypt_file(OUT_ENC_FILENAME, __DIR__.'/result.zip');

    • Related Articles

    • Implement Document Signing via Evrotrust Application

      This guide provides a step-by-step process for integrating the Evrotrust API to enable document signing via the Evrotrust mobile app. The flow involves checking user status, sending documents for signing, handling callbacks, checking status ...
    • User Guide - Evrotrust Support Portal - Zoho Desk

      Тable of Contents Summary & Overview Purpose of This Guide How to Use the Evrotrust Support Portal 1. Registration, Login & Forgotten Password 1.1 First-Time Access 1.2 How to Log In 1.3 How to Reset a Password 2. Navigating the Portal 2.1 Home ...
    • How to Generate Your Public and Private Keys

      This guide explains how to generate an RSA 2048-bit key pair in PKCS#8 format, and prepare them for use in API requests. RSA is an asymmetric encryption algorithm where the public key is used for encryption, and the private key for decryption. This ...
    • Receive a Callback From Evrotrust

      This guide explains how to set up and handle callbacks from Evrotrust. Callbacks are asynchronous notifications sent by Evrotrust to your server when certain events occur (e.g., a document is signed, expires, or is rejected). These notifications ...
    • How to generate the Authorization header

      This guide provides a detailed explanation of how to generate an Authorization header for an API request using cryptographic operations. The process involves creating a JSON request body, hashing an API key with SHA-256, and then using that hash to ...