diff --git a/AUDITING.md b/AUDITING.md new file mode 100644 index 0000000..ca52227 --- /dev/null +++ b/AUDITING.md @@ -0,0 +1,139 @@ +# Auditing + +## Purpose of this document + +This document is meant to highlight security-relevant aspects of this tool that +might be relevant to facilitate a rigorous audit process. + +## Data exfiltration + +These are some of the built-in protections to prevent data exfiltration. + +### Content Security Policy (CSP) + +Content Security Policy (CSP) is used to limit communication with the outside +world. In particular, no external resources are allowed to be loaded. You can +verify this by assessing the contents of the corresponding `` tag and note +that no external content is allowed. + +### Navigation + +- **`window.open`:** `window.open`, or similar functions that can be used to + make requests to external resources, is not used. +- **Form submissions:** No forms with an external `action` are used. This is + further enforced with CSP. +- Links: Links to external resources use statically-defined URLs that do not + depend on user input. No links to external resources are opened without user + interaction. + +### Dynamic resource loading + +- **`fetch()` / `XMLHttpRequest`:** Only used on local resources. Also + restricted by CSP. +- **`import()`:** Not used. Also restricted by CSP. +- **`ping` attribute**: Not used. Also restricted by CSP. +- **Other dynamic resources**: Not used. Also restricted by CSP. + +### Additional measures + +All cryptographic operations are sandboxed where possible. This places +additional restrictions on the flow of data. + +## Correctness + +### Cryptographic primitives + +This application relies on the primitives exposed by the `SubtleCypto` API, and +the cryptographic operations used are restricted to what is needed to construct +and parse a Cryptographic Message Syntax (CMS) payload. + +The following methods of the `SubtleCypto` API are used: + +- **`decrypt`:** When decrypting a file, this function is used to decrypt the + Content Encryption Key (CEK) with a password-derived Key Encryption Key (KEK), + and to use that CEK to decrypt the file and file name. +- **`deriveKey`:** When encrypting or decrypting a file, this function is used + to derive the Key Encryption Key (KEK) from a user-supplied password. +- **`encrypt`:** When encrypting a file, this function is used to encrypt the + Content Encryption Key (CEK) with a password-derived Key Encryption Key (KEK), + and to use that CEK to encrypt the file and file name. +- **`exportKey`:** When encrypting a file, this function is used to export the + randomly-generated Content Encryption Key (CEK). This is needed so that it can + then be encrypted using the Key Encryption Key (KEK) and included, in + encrypted form, in the CMS payload. +- **`generateKey`:** When encrypting a file, this function is used to generate + a random AES-256-GCM Content Encryption Key (CEK), which is subsequently used + to encrypt user-supplied data. +- **`importKey`:** When encrypting or decrypting a file, this function is used + on the user-supplied password in order to derive the Key Encryption Key (KEK). + Additionally, when decrypting a file, this function is used to import the + Content Encryption Key (CEK) after it has been decrypted. + +In addition, the `getRandomValues` method of the `Crypto` API is used as an +entropy source when encrypting a file. This is used to derive a salt, used in +the KEK derivation process, as well as to generate initialisation vectors (IVs) +for encrypted payloads. + +### Password-based key derivation + +The user-supplied password is used to derive the Key Encryption Key (KEK) using +the PBKDF2 algorithm. This is implemented in the file `src/lib/deriveKEK.ts`. + +### Data encryption and decryption + +#### Data encryption + +User-supplied data (file and file name) are encrypted in two separate steps, one +for file contents and another for a file name. The base implementation for +encryption can be found in the file `src/lib/fileEncryptionCms.ts`. In addition, +the file `src/sandbox/fileEncryptionCms.ts` implements the two distinct steps +used for contents and name. + +#### Data decryption + +User-supplied data (file and file name) are decrypted in two separate steps, one +for file contents and another for a file name. The base implementation for +decryption can be found in the file `src/lib/fileDecryptionCms.ts`. In addition, +the file `src/sandbox/fileDecryptionCms.ts` implements the two distinct steps +used for contents and name. + +#### Initialisation vector (IV) reuse + +Because this application uses AES-256-GCM, it is of paramount importance that +initialisation vectors are not reused. This is accomplished by generating fresh +initialisation vectors each time one is needed. + +#### Other relevant files + +- **`src/lib/constructCmsData.ts`:** This file implements construction of a + CMS payload (used after encryption). It does not handle unprotected user data, + but is used to produce a payload that is derived from user input. +- **`src/lib/fixBrokenSandboxSecureContext.ts`:** This file is used to define + various methods provided by the `SubtleCrypto` API if they are not available. + Certain browsers do not consider the sandboxed environment a _secure context_, + which means that the `SubtleCrypto` API is not available. In those cases, this + file is used to define those methods with an external implementation, provided + by the top document. While this is necessary in these situations, it negates + some of isolation that a fully sandboxed environment would provide. +- **`src/lib/parseCmsData.ts`:** This file implements partial parsing of a CMS + payload (used before decryption). It does not handle unprotected user data, + but it receives user-supplied input that will ultimately be used to recover + encrypted user data. +- **`src/lib/setupConstructCmsSandbox.ts`:** This file implements the creation + of a sandbox for constructing a CMS payload. The sandbox entrypoint is that + from `src/sandbox/constructCmsData.ts`. +- **`src/lib/setupDecryptionSandbox.ts`:** This file implments the creation of + two sandboxes used during decryption, one to derive the KEK and another one to + decrypt data. The sandbox entrypoints are those from + `src/sandbox/deriveKEK.ts` and `src/lib/fileDecryptionCms.ts`. +- **`src/lib/setupEncryptionSandbox.ts`:** This file implments the creation of + two sandboxes used during encryption, one to derive the KEK and another one to + encrypt data. The sandbox entrypoints are those from + `src/sandbox/deriveKEK.ts` and `src/lib/fileEncryptionCms.ts`. +- **`src/lib/setupParseCmsSandbox.ts`:** This file implements the creation + of a sandbox for parsing a CMS payload. The sandbox entrypoint is that + from `src/sandbox/parseCmsData.ts`. +- **`src/sandbox/constructCmsData.ts`:** Wrapper around + `src/lib/constructCmsData.ts`. +- **`src/sandbox/deriveKEK.ts`:** Wrapper around `src/sandbox/deriveKEK.ts`. +- **`src/sandbox/parseCmsData.ts`:** Wrapper around `src/lib/parseCmsData.ts`. diff --git a/README.md b/README.md index ed0ba09..29e6e51 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Using this secure file sharing utility is simple: - Share the generated HTML file with your recipient. 3. **Decrypt the File**: + - Your recipient can open the HTML file in their browser. - They will be prompted to enter the password you provided and will need to click on the "Next →" button to decrypt the file and confirm details @@ -65,6 +66,21 @@ decrypted content. Want to see how it works? Check out the live demo at . +## 🌐 Browser Support + +The following is a non-comprehensive list of browsers that have been tested. +Even though we have tested with older versions for compatibility support and +reporting, we strongly recommend using up-to-date browsers that still receive +security updates. + +- Chrome: ✅️ 77– +- Edge: ✅️ 79– +- Firefox: ✅️ 69– +- Internet Explorer: ❌ Not supported +- Opera: ✅️ 63– +- Pale Moon: ❌ Not supported [yet](https://repo.palemoon.org/MoonchildProductions/UXP/issues/2534) +- Safari: ✅️ 14– + ## 🔒 Security Considerations This utility is designed with security in mind. By using the CMS standard, PWRI, @@ -77,6 +93,9 @@ security of this tool _greatly_ depend on the strength of the password you choose. We recommend using a strong, unique password to protect your files. Weak or compromised passwords can put your data at risk. +For more detailed information about the security of this tool and how it works, +see [`AUDITING.md`](./AUDITING.md). + ## ❗️ Disclaimer This tool is provided in the hope that it will be helpful, but it comes with @@ -113,7 +132,7 @@ or feature requests, please feel free to submit them. This project is licensed under the Apache 2.0 License with the LLVM exception. You are free to use this package in compliance with the terms of the license. -For more information, see the `LICENSE` file. +For more information, see the [`LICENSE`](./LICENSE) file. We hope you find this secure file sharing utility useful! If you have any questions or feedback, please don't hesitate to reach out. diff --git a/package-lock.json b/package-lock.json index 4924de6..4b9c203 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@exact-realty/cms-ep-sfx", - "version": "1.0.6", + "version": "1.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@exact-realty/cms-ep-sfx", - "version": "1.0.6", + "version": "1.0.7", "license": "Apache-2.0 WITH LLVM-exception", "devDependencies": { "@exact-realty/asn1-der": "^1.0.1", diff --git a/package.json b/package.json index 0f436a8..4a2c516 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@exact-realty/cms-ep-sfx", - "version": "1.0.6", + "version": "1.0.7", "description": "Secure File Sharing Utility", "type": "module", "main": "-", diff --git a/src/fallbackMessage.inline.ts b/src/fallbackMessage.inline.ts index 033ad77..ee338e3 100644 --- a/src/fallbackMessage.inline.ts +++ b/src/fallbackMessage.inline.ts @@ -66,7 +66,12 @@ self.onerror = function ( return false; } as unknown as Window['onerror']; -if (typeof Reflect === [] + [][0]) +if ( + typeof Reflect === [] + [][0] || + typeof Blob !== 'function' || + !Blob.prototype || + typeof Blob.prototype.arrayBuffer !== 'function' +) self.onload = function ( _document: Document, _body$: HTMLElement, diff --git a/src/lib/generateHtml.ts b/src/lib/generateHtml.ts index 705f929..a0345de 100644 --- a/src/lib/generateHtml.ts +++ b/src/lib/generateHtml.ts @@ -78,7 +78,7 @@ const generateHtml_ = async ( ' http-equiv="content-security-policy"' + // Safari / WebKit seem to require frame-ancestors 'self' for starting // sandboxes - ` content="default-src 'none'; script-src 'self' 'unsafe-eval' data:; script-src-elem blob: data: '${fallbackMessage.sri}' '${loader.sri}' '${mainScriptTextSriDigest}'; script-src-attr 'none'; style-src data: '${cssTextSriDigest}'; child-src blob:; connect-src blob: data:; frame-ancestors 'self'; form-action data:"` + + ` content="default-src 'none'; script-src 'self' 'unsafe-eval' blob: data:; script-src-elem blob: data: '${fallbackMessage.sri}' '${loader.sri}' '${mainScriptTextSriDigest}'; script-src-attr 'none'; style-src data: '${cssTextSriDigest}'; child-src blob:; connect-src blob: data:; frame-src blob:; worker-src blob:; frame-ancestors 'self'; form-action data:"` + '/>' + `HTML CMS Tool` + `