Skip to content

Decryption

Vedad Kirlić edited this page Dec 30, 2021 · 9 revisions

Reading an encrypted file

In order to decrypt user file, we will need the private key associated to your contract. This should have been given to you when your contract was first created.

Once you've received user data from the query endpoint, you would have received the file content in the encrypted binary form.

In order to decrypt the data:

  • It is recommended that the content size is validated. This can be done by ensuring that the number of bytes >= 352 and is divisible by 16;
  • The encrypted DSK is sourced from the first 256 bytes and is asymmetrically decrypted with decryptRsa2048 using the private key. The output will always be a 32 byte array;
  • The Data Initialisation Vector (DIV) is sourced from the next 16 bytes; the encrypted Hash & Data is sourced from the remaining bytes and is symmetrically decrypted with decryptAes256 using the DIV and DSK. The output will always be a variable length byte array, the first 64 bytes of which is the Data Hash, and the remaining bytes is the actual data.
  • The data is hashed using hashSha512, then the resulting 64 byte Hash is compared to the Data Hash. If they do not match, then the file has been tampered with or corrupted in transit or storage;

File Anatomy

Encrypted DSK DIV Encrypted Hash & Data
256 bytes 16 bytes 80+ bytes

Decryption excerpt adapted from JS SDK (nodejs/typescript):

const BYTES = {
    DSK: [0, 256],
    DIV: [256, 272],
    HASH_DATA: [272],
    HASH: [0, 64],
    DATA: [64],
};

const isValidSize = (data: Buffer): boolean => {
    const bytes = data.length;
    return bytes >= 352 && bytes % 16 === 0;
};

const decryptData = (key: NodeRSA, file: Buffer): Buffer => {
    // Verify file data is of correct length
    if (!isValidSize(file)) {
        throw new FileDecryptionError("File size not valid");
    }

    // Extract DSK and DIV
    const encryptedDSK: Buffer = file.slice(...BYTES.DSK); // initial 256 bytes - DSK encrypted with consumer Private Key
    const dsk: Buffer = key.decrypt(encryptedDSK); // Decrypt DSK with consumer Private Key
    const div: Buffer = file.slice(...BYTES.DIV); // next 16 bytes (256 to 272) - DIV

    // Extract concatenated hash and data
    const encryptedHashAndData = file.slice(...BYTES.HASH_DATA); // remaining bytes - 272 til the end

    // Decrypt concatenated hash and data with DSK, DIV 
    const decipher = crypto.createDecipheriv("aes-256-cbc", dsk, div);
    const hashAndData = Buffer.concat([decipher.update(encryptedHashAndData), decipher.final()]); // decrypt

    // Extract hash and data
    const hash: Buffer = hashAndData.slice(...BYTES.HASH); // initial 64 bytes
    const data: Buffer = hashAndData.slice(...BYTES.DATA); // remaining bytes

    // Hash plain data and compare with extracted hash to validate
    const dataHash: Buffer = crypto.createHash("sha512").update(data).digest();
    if (!dataHash.equals(hash)) {
        throw new FileDecryptionError("Hash is not valid");
    }

    return data;
};

Clone this wiki locally