diff --git a/example/encryptFile.html b/example/encryptFile.html new file mode 100644 index 00000000..047b2b68 --- /dev/null +++ b/example/encryptFile.html @@ -0,0 +1,191 @@ + + + + + + + Document + + + + + + + +
+ Tested only in chrome! + To receive precise memory measurement, run Chrome with --enable-precise-memory-info +
    +
  1. Get the credentials at Virgil Dashboard.
  2. +
  3. Upload file or choose size.
  4. +
  5. You will receive encrypted file at the end of the encryption.
  6. +
  7. Upload encrypted file (file size ignored).
  8. +
  9. You will receive decrypted file at the end.
  10. +
+
+ + + +
+
+ + - or - + + +
+
+ + + +
+
+

+    
+
+
+
diff --git a/karma.conf.js b/karma.conf.js
index 2c5ea007..f5a6e60e 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -17,6 +17,9 @@ module.exports = function (config) {
         browserNoActivityTimeout: 60 * 1000,
         singleRun: true,
         reporters: ['spec'],
+        specReporter: {
+            showSpecTiming: true,      // print the time elapsed for each spec
+        },
         preprocessors: {
             'src/**/*.ts': ['rollup'],
         },
diff --git a/package-lock.json b/package-lock.json
index e69b9eb2..5265d138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
     "name": "@virgilsecurity/e3kit",
-    "version": "0.3.7",
+    "version": "0.3.9",
     "lockfileVersion": 1,
     "requires": true,
     "dependencies": {
@@ -77,9 +77,9 @@
             "dev": true
         },
         "@types/fs-extra": {
-            "version": "5.0.5",
-            "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.5.tgz",
-            "integrity": "sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==",
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.1.0.tgz",
+            "integrity": "sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ==",
             "dev": true,
             "requires": {
                 "@types/node": "*"
@@ -112,9 +112,9 @@
             "dev": true
         },
         "@types/lodash": {
-            "version": "4.14.123",
-            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz",
-            "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==",
+            "version": "4.14.126",
+            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.126.tgz",
+            "integrity": "sha512-HxQ+wQnBtnL0LszZrVdMqWIlzZNyKuMLUb6swQ3mo6ysPqpAu7gfnapCQIi0B+Mrf0fNLZh8AWgJs2njejVasg==",
             "dev": true
         },
         "@types/marked": {
@@ -142,15 +142,24 @@
             "dev": true
         },
         "@types/shelljs": {
-            "version": "0.8.3",
-            "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.3.tgz",
-            "integrity": "sha512-miY41hqc5SkRlsZDod3heDa4OS9xv8G77EMBQuSpqq86HBn66l7F+f8y9YKm+1PIuwC8QEZVwN8YxOOG7Y67fA==",
+            "version": "0.8.5",
+            "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.5.tgz",
+            "integrity": "sha512-bZgjwIWu9gHCjirKJoOlLzGi5N0QgZ5t7EXEuoqyWCHTuSddURXo3FOBYDyRPNOWzZ6NbkLvZnVkn483Y/tvcQ==",
             "dev": true,
             "requires": {
                 "@types/glob": "*",
                 "@types/node": "*"
             }
         },
+        "@types/uuid": {
+            "version": "3.4.4",
+            "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
+            "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
+            "dev": true,
+            "requires": {
+                "@types/node": "*"
+            }
+        },
         "@virgilsecurity/keyknox": {
             "version": "0.2.4",
             "resolved": "https://registry.npmjs.org/@virgilsecurity/keyknox/-/keyknox-0.2.4.tgz",
@@ -165,6 +174,15 @@
             "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==",
             "dev": true
         },
+        "abort-controller": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+            "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+            "dev": true,
+            "requires": {
+                "event-target-shim": "^5.0.0"
+            }
+        },
         "accepts": {
             "version": "1.3.5",
             "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
@@ -557,6 +575,15 @@
                 "sprintf-js": "~1.0.2"
             }
         },
+        "arr-diff": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+            "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+            "dev": true,
+            "requires": {
+                "arr-flatten": "^1.0.1"
+            }
+        },
         "arr-flatten": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
@@ -575,6 +602,30 @@
             "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
             "dev": true
         },
+        "array-filter": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+            "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+            "dev": true
+        },
+        "array-map": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+            "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+            "dev": true
+        },
+        "array-reduce": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+            "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+            "dev": true
+        },
+        "array-unique": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+            "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+            "dev": true
+        },
         "arraybuffer.slice": {
             "version": "0.0.7",
             "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
@@ -703,6 +754,16 @@
                 }
             }
         },
+        "babel-runtime": {
+            "version": "6.26.0",
+            "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+            "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+            "dev": true,
+            "requires": {
+                "core-js": "^2.4.0",
+                "regenerator-runtime": "^0.11.0"
+            }
+        },
         "backo2": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
@@ -867,6 +928,17 @@
                 "concat-map": "0.0.1"
             }
         },
+        "braces": {
+            "version": "1.8.5",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+            "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+            "dev": true,
+            "requires": {
+                "expand-range": "^1.8.1",
+                "preserve": "^0.2.0",
+                "repeat-element": "^1.1.2"
+            }
+        },
         "browser-process-hrtime": {
             "version": "0.1.3",
             "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
@@ -1350,6 +1422,74 @@
                 }
             }
         },
+        "cp-file": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
+            "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
+            "requires": {
+                "graceful-fs": "^4.1.2",
+                "make-dir": "^3.0.0",
+                "nested-error-stacks": "^2.0.0",
+                "p-event": "^4.1.0"
+            }
+        },
+        "cpx": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz",
+            "integrity": "sha1-GFvgGFEdhycN7czCkxceN2VauI8=",
+            "dev": true,
+            "requires": {
+                "babel-runtime": "^6.9.2",
+                "chokidar": "^1.6.0",
+                "duplexer": "^0.1.1",
+                "glob": "^7.0.5",
+                "glob2base": "^0.0.12",
+                "minimatch": "^3.0.2",
+                "mkdirp": "^0.5.1",
+                "resolve": "^1.1.7",
+                "safe-buffer": "^5.0.1",
+                "shell-quote": "^1.6.1",
+                "subarg": "^1.0.0"
+            },
+            "dependencies": {
+                "anymatch": {
+                    "version": "1.3.2",
+                    "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+                    "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+                    "dev": true,
+                    "requires": {
+                        "micromatch": "^2.1.5",
+                        "normalize-path": "^2.0.0"
+                    }
+                },
+                "chokidar": {
+                    "version": "1.7.0",
+                    "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+                    "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+                    "dev": true,
+                    "requires": {
+                        "anymatch": "^1.3.0",
+                        "async-each": "^1.0.0",
+                        "fsevents": "^1.0.0",
+                        "glob-parent": "^2.0.0",
+                        "inherits": "^2.0.1",
+                        "is-binary-path": "^1.0.0",
+                        "is-glob": "^2.0.0",
+                        "path-is-absolute": "^1.0.0",
+                        "readdirp": "^2.0.0"
+                    }
+                },
+                "normalize-path": {
+                    "version": "2.1.1",
+                    "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+                    "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+                    "dev": true,
+                    "requires": {
+                        "remove-trailing-separator": "^1.0.1"
+                    }
+                }
+            }
+        },
         "cross-env": {
             "version": "5.2.0",
             "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
@@ -1642,6 +1782,12 @@
             "integrity": "sha1-mFO2ypgpKst97GepUBj6QLzP9Cw=",
             "dev": true
         },
+        "duplexer": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+            "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+            "dev": true
+        },
         "ecc-jsbn": {
             "version": "0.1.2",
             "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -1845,6 +1991,12 @@
             "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
             "dev": true
         },
+        "event-target-shim": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+            "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+            "dev": true
+        },
         "eventemitter3": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
@@ -1857,6 +2009,24 @@
             "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
             "dev": true
         },
+        "expand-brackets": {
+            "version": "0.1.5",
+            "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+            "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+            "dev": true,
+            "requires": {
+                "is-posix-bracket": "^0.1.0"
+            }
+        },
+        "expand-range": {
+            "version": "1.8.2",
+            "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+            "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+            "dev": true,
+            "requires": {
+                "fill-range": "^2.1.0"
+            }
+        },
         "expect": {
             "version": "24.0.0",
             "resolved": "https://registry.npmjs.org/expect/-/expect-24.0.0.tgz",
@@ -2300,6 +2470,15 @@
                 }
             }
         },
+        "extglob": {
+            "version": "0.3.2",
+            "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+            "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+            "dev": true,
+            "requires": {
+                "is-extglob": "^1.0.0"
+            }
+        },
         "extsprintf": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -2363,6 +2542,25 @@
                 "object-assign": "^4.1.0"
             }
         },
+        "filename-regex": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+            "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+            "dev": true
+        },
+        "fill-range": {
+            "version": "2.2.4",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+            "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+            "dev": true,
+            "requires": {
+                "is-number": "^2.1.0",
+                "isobject": "^2.0.0",
+                "randomatic": "^3.0.0",
+                "repeat-element": "^1.1.2",
+                "repeat-string": "^1.5.2"
+            }
+        },
         "finalhandler": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
@@ -2395,6 +2593,12 @@
                 }
             }
         },
+        "find-index": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz",
+            "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=",
+            "dev": true
+        },
         "find-parent-dir": {
             "version": "0.3.0",
             "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz",
@@ -2421,6 +2625,15 @@
             "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
             "dev": true
         },
+        "for-own": {
+            "version": "0.1.5",
+            "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+            "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+            "dev": true,
+            "requires": {
+                "for-in": "^1.0.1"
+            }
+        },
         "forever-agent": {
             "version": "0.6.1",
             "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -2921,11 +3134,38 @@
                 "path-is-absolute": "^1.0.0"
             }
         },
+        "glob-base": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+            "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+            "dev": true,
+            "requires": {
+                "glob-parent": "^2.0.0",
+                "is-glob": "^2.0.0"
+            }
+        },
+        "glob-parent": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+            "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+            "dev": true,
+            "requires": {
+                "is-glob": "^2.0.0"
+            }
+        },
+        "glob2base": {
+            "version": "0.0.12",
+            "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
+            "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=",
+            "dev": true,
+            "requires": {
+                "find-index": "^0.1.1"
+            }
+        },
         "graceful-fs": {
             "version": "4.1.11",
             "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-            "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-            "dev": true
+            "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
         },
         "growl": {
             "version": "1.10.5",
@@ -2934,9 +3174,9 @@
             "dev": true
         },
         "handlebars": {
-            "version": "4.1.1",
-            "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz",
-            "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==",
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
+            "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
             "dev": true,
             "requires": {
                 "neo-async": "^2.6.0",
@@ -3259,12 +3499,33 @@
             "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
             "dev": true
         },
+        "is-dotfile": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+            "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+            "dev": true
+        },
+        "is-equal-shallow": {
+            "version": "0.1.3",
+            "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+            "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+            "dev": true,
+            "requires": {
+                "is-primitive": "^2.0.0"
+            }
+        },
         "is-extendable": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
             "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
             "dev": true
         },
+        "is-extglob": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+            "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+            "dev": true
+        },
         "is-fullwidth-code-point": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
@@ -3274,12 +3535,30 @@
                 "number-is-nan": "^1.0.0"
             }
         },
+        "is-glob": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+            "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+            "dev": true,
+            "requires": {
+                "is-extglob": "^1.0.0"
+            }
+        },
         "is-module": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
             "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
             "dev": true
         },
+        "is-number": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+            "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+            "dev": true,
+            "requires": {
+                "kind-of": "^3.0.2"
+            }
+        },
         "is-obj": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
@@ -3312,6 +3591,18 @@
                 }
             }
         },
+        "is-posix-bracket": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+            "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+            "dev": true
+        },
+        "is-primitive": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+            "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+            "dev": true
+        },
         "is-promise": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
@@ -3369,6 +3660,15 @@
             "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
             "dev": true
         },
+        "isobject": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+            "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+            "dev": true,
+            "requires": {
+                "isarray": "1.0.0"
+            }
+        },
         "isstream": {
             "version": "0.1.2",
             "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -3406,9 +3706,9 @@
             "dev": true
         },
         "js-yaml": {
-            "version": "3.12.0",
-            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
-            "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=",
+            "version": "3.13.1",
+            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+            "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
             "dev": true,
             "requires": {
                 "argparse": "^1.0.7",
@@ -3499,6 +3799,12 @@
                 "graceful-fs": "^4.1.6"
             }
         },
+        "jsonify": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+            "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+            "dev": true
+        },
         "jsprim": {
             "version": "1.4.1",
             "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -4261,6 +4567,21 @@
                 "sourcemap-codec": "^1.4.1"
             }
         },
+        "make-dir": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
+            "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
+            "requires": {
+                "semver": "^6.0.0"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "6.0.0",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
+                    "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
+                }
+            }
+        },
         "map-cache": {
             "version": "0.2.2",
             "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -4282,12 +4603,50 @@
             "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==",
             "dev": true
         },
+        "math-random": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+            "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+            "dev": true
+        },
         "media-typer": {
             "version": "0.3.0",
             "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
             "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
             "dev": true
         },
+        "micromatch": {
+            "version": "2.3.11",
+            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+            "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+            "dev": true,
+            "requires": {
+                "arr-diff": "^2.0.0",
+                "array-unique": "^0.2.1",
+                "braces": "^1.8.2",
+                "expand-brackets": "^0.1.4",
+                "extglob": "^0.3.1",
+                "filename-regex": "^2.0.0",
+                "is-extglob": "^1.0.0",
+                "is-glob": "^2.0.1",
+                "kind-of": "^3.0.2",
+                "normalize-path": "^2.0.1",
+                "object.omit": "^2.0.0",
+                "parse-glob": "^3.0.4",
+                "regex-cache": "^0.4.2"
+            },
+            "dependencies": {
+                "normalize-path": {
+                    "version": "2.1.1",
+                    "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+                    "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+                    "dev": true,
+                    "requires": {
+                        "remove-trailing-separator": "^1.0.1"
+                    }
+                }
+            }
+        },
         "mime": {
             "version": "2.4.0",
             "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
@@ -4483,11 +4842,16 @@
             "dev": true
         },
         "neo-async": {
-            "version": "2.6.0",
-            "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
-            "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==",
+            "version": "2.6.1",
+            "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+            "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
             "dev": true
         },
+        "nested-error-stacks": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
+            "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug=="
+        },
         "next-tick": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
@@ -4615,6 +4979,16 @@
                 }
             }
         },
+        "object.omit": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+            "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+            "dev": true,
+            "requires": {
+                "for-own": "^0.1.4",
+                "is-extendable": "^0.1.1"
+            }
+        },
         "object.pick": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
@@ -4720,11 +5094,18 @@
                 "os-tmpdir": "^1.0.0"
             }
         },
+        "p-event": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz",
+            "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==",
+            "requires": {
+                "p-timeout": "^2.0.1"
+            }
+        },
         "p-finally": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-            "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
-            "dev": true
+            "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
         },
         "p-map": {
             "version": "1.2.0",
@@ -4732,6 +5113,26 @@
             "integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=",
             "dev": true
         },
+        "p-timeout": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
+            "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+            "requires": {
+                "p-finally": "^1.0.0"
+            }
+        },
+        "parse-glob": {
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+            "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+            "dev": true,
+            "requires": {
+                "glob-base": "^0.3.0",
+                "is-dotfile": "^1.0.0",
+                "is-extglob": "^1.0.0",
+                "is-glob": "^2.0.0"
+            }
+        },
         "parse5": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
@@ -4835,6 +5236,12 @@
             "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
             "dev": true
         },
+        "preserve": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+            "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+            "dev": true
+        },
         "prettier": {
             "version": "1.14.3",
             "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz",
@@ -4907,6 +5314,31 @@
             "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
             "dev": true
         },
+        "randomatic": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+            "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+            "dev": true,
+            "requires": {
+                "is-number": "^4.0.0",
+                "kind-of": "^6.0.0",
+                "math-random": "^1.0.1"
+            },
+            "dependencies": {
+                "is-number": {
+                    "version": "4.0.0",
+                    "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+                    "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+                    "dev": true
+                },
+                "kind-of": {
+                    "version": "6.0.2",
+                    "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+                    "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+                    "dev": true
+                }
+            }
+        },
         "range-parser": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
@@ -5273,6 +5705,21 @@
             "integrity": "sha1-MRvwxrY814LyKKgavhRqK/qcVvI=",
             "dev": true
         },
+        "regenerator-runtime": {
+            "version": "0.11.1",
+            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+            "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+            "dev": true
+        },
+        "regex-cache": {
+            "version": "0.4.4",
+            "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+            "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+            "dev": true,
+            "requires": {
+                "is-equal-shallow": "^0.1.3"
+            }
+        },
         "regex-not": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -5955,6 +6402,18 @@
             "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
             "dev": true
         },
+        "shell-quote": {
+            "version": "1.6.1",
+            "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+            "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+            "dev": true,
+            "requires": {
+                "array-filter": "~0.0.0",
+                "array-map": "~0.0.0",
+                "array-reduce": "~0.0.0",
+                "jsonify": "~0.0.0"
+            }
+        },
         "shelljs": {
             "version": "0.8.3",
             "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
@@ -6357,6 +6816,23 @@
             "dev": true,
             "optional": true
         },
+        "subarg": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+            "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+            "dev": true,
+            "requires": {
+                "minimist": "^1.1.0"
+            },
+            "dependencies": {
+                "minimist": {
+                    "version": "1.2.0",
+                    "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+                    "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+                    "dev": true
+                }
+            }
+        },
         "supports-color": {
             "version": "5.5.0",
             "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -6931,9 +7407,9 @@
             }
         },
         "virgil-crypto": {
-            "version": "3.2.2",
-            "resolved": "https://registry.npmjs.org/virgil-crypto/-/virgil-crypto-3.2.2.tgz",
-            "integrity": "sha512-9M8Ar95M9B/hBwRQwOqj3hur59aXiuMb3GASZulUwxB9Oit25IzIMrdIZ8qYbFP3Neuld7UR2ebq+J299JfSjw==",
+            "version": "3.2.3",
+            "resolved": "https://registry.npmjs.org/virgil-crypto/-/virgil-crypto-3.2.3.tgz",
+            "integrity": "sha512-S+Qo39isymVE2DbKDJNZZu4ENQa/niWNwtA0kDfn6+EoFRDzUL9A1QxwR3pTNoWwzcJqJujR2/hKQZSezANCwA==",
             "requires": {
                 "node-fetch": "^2.1.2",
                 "readable-stream": "^3.0.6",
diff --git a/package.json b/package.json
index f0b48b9c..aed69f3f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "@virgilsecurity/e3kit",
-    "version": "0.3.9",
+    "version": "0.4.0",
     "description": "End-to-end encryption with multiple device support powered by Virgil Security",
     "main": "./dist/e3kit.browser.es.js",
     "module": "./dist/e3kit.browser.es.js",
@@ -22,7 +22,8 @@
         "prettier": "prettier 'src/**/*.ts' --write",
         "precommit": "lint-staged",
         "test": "karma start",
-        "docs": "typedoc src"
+        "docs": "typedoc src && npm run build:browser:umd && npm run encryptFileDoc",
+        "encryptFileDoc": "cpx example/encryptFile.html docs && cpx dist/e3kit.browser.umd.min.js docs"
     },
     "lint-staged": {
         "src/**/*.ts": [
@@ -32,13 +33,16 @@
     },
     "dependencies": {
         "@virgilsecurity/keyknox": "^0.2.4",
-        "virgil-crypto": "^3.2.2",
+        "virgil-crypto": "^3.2.3",
         "virgil-pythia": "^0.2.3",
         "virgil-sdk": "^5.2.2"
     },
     "peerDependencies": {},
     "devDependencies": {
         "@types/mocha": "^5.2.5",
+        "@types/uuid": "^3.4.4",
+        "abort-controller": "^3.0.0",
+        "cpx": "^1.5.0",
         "cross-env": "^5.2.0",
         "dotenv": "^6.0.0",
         "es6-symbol": "^3.1.1",
@@ -70,7 +74,8 @@
         "tslint-plugin-prettier": "^1.3.0",
         "typedoc": "^0.14.2",
         "typedoc-plugin-markdown": "^1.1.27",
-        "typescript": "^3.0.1"
+        "typescript": "^3.0.1",
+        "uuid": "^3.3.2"
     },
     "sideEffects": false
 }
diff --git a/src/EThree.ts b/src/EThree.ts
index d4a7bb40..d0a43498 100644
--- a/src/EThree.ts
+++ b/src/EThree.ts
@@ -24,51 +24,32 @@ import {
     LookupError,
     DUPLICATE_IDENTITIES,
     EMPTY_ARRAY,
+    throwIllegalInvocationError,
+    IntegrityCheckFailedError,
 } from './errors';
-import { isArray, isString, isVirgilPublicKey } from './utils/typeguards';
-import { hasDuplicates, getObjectValues } from './utils/array';
+import { isArray, isString, isFile, isVirgilPublicKey } from './utils/typeguards';
 import { withDefaults } from './utils/object';
-
-export interface IEThreeInitOptions {
-    /**
-     * Implementation of IKeyEntryStorage. Used IndexedDB Key Storage from
-     * [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript) by default.
-     */
-    keyEntryStorage?: IKeyEntryStorage;
-    /**
-     * Url of the Card Services. Used for development purposes.
-     */
-    apiUrl?: string;
-}
-/**
- * @hidden
- */
-export interface IEThreeCtorOptions extends IEThreeInitOptions {
-    /**
-     * Implementation of IAccessTokenProvider from [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript);
-     */
-    accessTokenProvider: IAccessTokenProvider;
-}
-
-type KeyPair = {
-    privateKey: VirgilPrivateKey;
-    publicKey: VirgilPublicKey;
-};
-
-export type LookupResult = {
-    [identity: string]: VirgilPublicKey;
-};
-
-const throwIllegalInvocationError = (method: string) => {
-    throw new Error(`Calling ${method} two or more times in a row is not allowed.`);
-};
-
-type EncryptVirgilPublicKeyArg = LookupResult | VirgilPublicKey;
+import { getObjectValues, hasDuplicates } from './utils/array';
+import { processFile, onChunkCallback } from './utils/processFile';
+import {
+    VIRGIL_STREAM_SIGNING_STATE,
+    VIRGIL_STREAM_ENCRYPTING_STATE,
+    VIRGIL_STREAM_DECRYPTING_STATE,
+    VIRGIL_STREAM_VERIFYING_STATE,
+    DEFAULT_API_URL,
+    STORAGE_NAME,
+} from './utils/constants';
+import {
+    EncryptVirgilPublicKeyArg,
+    LookupResult,
+    EThreeInitializeOptions,
+    EncryptFileOptions,
+    DecryptFileOptions,
+} from './types';
+import { KeyPair, EThreeCtorOptions } from './utils/innerTypes';
 
 const _inProcess = Symbol('inProcess');
 const _keyLoader = Symbol('keyLoader');
-const STORAGE_NAME = '.virgil-local-storage';
-const DEFAULT_API_URL = 'https://api.virgilsecurity.com';
 
 export default class EThree {
     /**
@@ -109,9 +90,9 @@ export default class EThree {
      */
     static async initialize(
         getToken: () => Promise,
-        options: IEThreeInitOptions = {},
+        options: EThreeInitializeOptions = {},
     ): Promise {
-        const opts = withDefaults(options as IEThreeCtorOptions, {
+        const opts = withDefaults(options as EThreeCtorOptions, {
             accessTokenProvider: new CachingJwtProvider(getToken),
         });
         const token = await opts.accessTokenProvider.getToken({ operation: 'get' });
@@ -123,7 +104,7 @@ export default class EThree {
      * @hidden
      * @param identity - Identity of the current user.
      */
-    constructor(identity: string, options: IEThreeCtorOptions) {
+    constructor(identity: string, options: EThreeCtorOptions) {
         const opts = withDefaults(options, { apiUrl: DEFAULT_API_URL });
         this.identity = identity;
         this.accessTokenProvider = opts.accessTokenProvider;
@@ -228,8 +209,8 @@ export default class EThree {
     }
 
     /**
-     * Encrypts data for recipient(s) public key(s). If there is no recipient and message encrypted
-     * for the current user, omit public key.
+     * Encrypts and signs data for recipient public key or `LookupResult` dictionary for multiple recipients.
+     * If there is no recipient and message encrypted for the current user, omit public key.
      */
     async encrypt(
         message: ArrayBuffer,
@@ -239,22 +220,13 @@ export default class EThree {
     async encrypt(message: Buffer, publicKey?: EncryptVirgilPublicKeyArg): Promise;
     async encrypt(message: Data, publicKeys?: EncryptVirgilPublicKeyArg): Promise {
         const isMessageString = isString(message);
-        let argument: VirgilPublicKey[];
-
-        if (publicKeys == null) argument = [];
-        else if (isVirgilPublicKey(publicKeys)) argument = [publicKeys];
-        else argument = getObjectValues(publicKeys) as VirgilPublicKey[];
 
         const privateKey = await this[_keyLoader].loadLocalPrivateKey();
         if (!privateKey) throw new RegisterRequiredError();
 
-        const ownPublicKey = this.virgilCrypto.extractPublicKey(privateKey);
-
-        if (!this._isOwnPublicKeysIncluded(ownPublicKey, argument)) {
-            argument.push(ownPublicKey);
-        }
+        const publicKeysArray = this._addOwnPublicKey(privateKey, publicKeys);
 
-        const res: Data = this.virgilCrypto.signThenEncrypt(message, privateKey, argument);
+        const res: Data = this.virgilCrypto.signThenEncrypt(message, privateKey, publicKeysArray);
         if (isMessageString) return res.toString('base64');
         return res;
     }
@@ -278,6 +250,210 @@ export default class EThree {
         return res as Buffer;
     }
 
+    /**
+     * Signs and encrypts File or Blob for recipient public key or `LookupResult` dictionary for multiple
+     * recipients. If there is no recipient and the message is encrypted for the current user, omit the
+     * public key parameter. You can define chunk size and a callback, that will be invoked on each chunk.
+     *
+     * The file will be read twice during this method execution:
+     * 1. To calculate the signature of the plaintext file.
+     * 2. To encrypt the file with encoded signature.
+     */
+    async encryptFile(
+        file: File | Blob,
+        publicKeys?: EncryptVirgilPublicKeyArg,
+        options: EncryptFileOptions = {},
+    ): Promise {
+        const chunkSize = options.chunkSize ? options.chunkSize : 64 * 1024;
+        if (!Number.isInteger(chunkSize)) throw TypeError('chunkSize should be an integer value');
+        const fileSize = file.size;
+
+        const privateKey = await this[_keyLoader].loadLocalPrivateKey();
+        if (!privateKey) throw new RegisterRequiredError();
+
+        const publicKeysArray = this._addOwnPublicKey(privateKey, publicKeys);
+
+        const streamSigner = this.virgilCrypto.createStreamSigner();
+
+        const signaturePromise = new Promise((resolve, reject) => {
+            const onChunkCallback: onChunkCallback = (chunk, offset) => {
+                if (options.onProgress) {
+                    options.onProgress({
+                        state: VIRGIL_STREAM_SIGNING_STATE,
+                        bytesProcessed: offset,
+                        fileSize: fileSize,
+                    });
+                }
+                streamSigner.update(chunk);
+            };
+
+            const onFinishCallback = () => resolve(streamSigner.sign(privateKey));
+
+            const onErrorCallback = (err: any) => {
+                streamSigner.dispose();
+                reject(err);
+            };
+
+            processFile({
+                file,
+                chunkSize,
+                onChunkCallback,
+                onFinishCallback,
+                onErrorCallback,
+                signal: options.signal,
+            });
+        });
+
+        const streamCipher = this.virgilCrypto.createStreamCipher(publicKeysArray, {
+            signature: await signaturePromise,
+        });
+
+        const encryptedChunksPromise = new Promise((resolve, reject) => {
+            const encryptedChunks: Buffer[] = [];
+            encryptedChunks.push(streamCipher.start());
+
+            const onChunkCallback: onChunkCallback = (chunk, offset) => {
+                encryptedChunks.push(streamCipher.update(chunk));
+                if (options.onProgress) {
+                    options.onProgress({
+                        state: VIRGIL_STREAM_ENCRYPTING_STATE,
+                        bytesProcessed: offset,
+                        fileSize: fileSize,
+                    });
+                }
+            };
+
+            const onFinishCallback = () => {
+                encryptedChunks.push(streamCipher.final());
+                resolve(encryptedChunks);
+            };
+
+            const onErrorCallback = (err: any) => {
+                reject(err);
+                streamCipher.dispose();
+            };
+
+            processFile({
+                file,
+                chunkSize,
+                onChunkCallback,
+                onFinishCallback,
+                onErrorCallback,
+                signal: options.signal,
+            });
+        });
+
+        const encryptedChunks = await encryptedChunksPromise;
+        if (isFile(file)) return new File(encryptedChunks, file.name, { type: file.type });
+        return new Blob(encryptedChunks, { type: file.type });
+    }
+    /**
+     * Decrypts and verifies integrity of File or Blob for recipient public key. If there is no recipient
+     * and the message is encrypted for the current user, omit the public key parameter. You can define
+     * chunk size and a callback, that will be invoked on each chunk.
+     *
+     * The file will be read twice during this method execution:
+     * 1. To decrypt encrypted file.
+     * 2. To verify the validity of the signature over the decrypted file for the public key.
+     */
+    async decryptFile(
+        file: File | Blob,
+        publicKey?: VirgilPublicKey,
+        options: DecryptFileOptions = {},
+    ): Promise {
+        const fileSize = file.size;
+        const chunkSize = options.chunkSize ? options.chunkSize : 64 * 1024;
+        if (!Number.isInteger(chunkSize)) throw TypeError('chunkSize should be an integer value');
+
+        const privateKey = await this[_keyLoader].loadLocalPrivateKey();
+        if (!privateKey) throw new RegisterRequiredError();
+        if (!publicKey) publicKey = this.virgilCrypto.extractPublicKey(privateKey);
+
+        const streamDecipher = this.virgilCrypto.createStreamDecipher(privateKey);
+
+        type decryptStreamResult = { signature: Buffer; decryptedChunks: Buffer[] };
+        const decryptedChunksPromise = new Promise((resolve, reject) => {
+            const decryptedChunks: Buffer[] = [];
+
+            const onChunkCallback: onChunkCallback = (chunk, offset) => {
+                decryptedChunks.push(streamDecipher.update(chunk));
+                if (options.onProgress) {
+                    options.onProgress({
+                        state: VIRGIL_STREAM_DECRYPTING_STATE,
+                        bytesProcessed: offset,
+                        fileSize: fileSize,
+                    });
+                }
+            };
+
+            const onFinishCallback = () => {
+                decryptedChunks.push(streamDecipher.final(false));
+                const signature = streamDecipher.getSignature();
+                streamDecipher.dispose();
+                if (!signature) throw new IntegrityCheckFailedError('Signature not present.');
+                resolve({ decryptedChunks, signature });
+            };
+
+            const onErrorCallback = (err: any) => {
+                streamDecipher.dispose();
+                reject(err);
+            };
+
+            processFile({
+                file,
+                chunkSize,
+                onChunkCallback,
+                onFinishCallback,
+                onErrorCallback,
+                signal: options.signal,
+            });
+        });
+
+        const { decryptedChunks, signature } = await decryptedChunksPromise;
+        const streamVerifier = this.virgilCrypto.createStreamVerifier(signature, 'utf8');
+
+        let decryptedFile: File | Blob;
+        if (isFile(file)) decryptedFile = new File(decryptedChunks, file.name, { type: file.type });
+        decryptedFile = new Blob(decryptedChunks, { type: file.type });
+        const decryptedFileSize = decryptedFile.size;
+
+        const verifyPromise = new Promise((resolve, reject) => {
+            const onChunkCallback: onChunkCallback = (chunk, offset) => {
+                streamVerifier.update(chunk);
+                if (options.onProgress) {
+                    options.onProgress({
+                        state: VIRGIL_STREAM_VERIFYING_STATE,
+                        bytesProcessed: offset,
+                        fileSize: decryptedFileSize,
+                    });
+                }
+            };
+
+            const onFinishCallback = () => resolve(streamVerifier.verify(publicKey!));
+            const onErrorCallback = (err: any) => {
+                streamVerifier.dispose();
+                reject(err);
+            };
+
+            processFile({
+                file: decryptedFile,
+                chunkSize,
+                onChunkCallback,
+                onFinishCallback,
+                onErrorCallback,
+                signal: options.signal,
+            });
+        });
+
+        const isVerified = await verifyPromise;
+
+        if (!isVerified) {
+            throw new IntegrityCheckFailedError('Signature verification has failed.');
+        }
+
+        return decryptedFile;
+    }
+
     /**
      * Find public keys for user identities registered on Virgil Cloud.
      */
@@ -357,4 +533,19 @@ export default class EThree {
         );
         return stringKeys.some((key, i) => key === selfPublicKey);
     }
+
+    private _addOwnPublicKey(privateKey: VirgilPrivateKey, publicKeys?: EncryptVirgilPublicKeyArg) {
+        let argument: VirgilPublicKey[];
+
+        if (publicKeys == null) argument = [];
+        else if (isVirgilPublicKey(publicKeys)) argument = [publicKeys];
+        else argument = getObjectValues(publicKeys) as VirgilPublicKey[];
+
+        const ownPublicKey = this.virgilCrypto.extractPublicKey(privateKey);
+
+        if (!this._isOwnPublicKeysIncluded(ownPublicKey, argument)) {
+            argument.push(ownPublicKey);
+        }
+        return argument;
+    }
 }
diff --git a/src/__tests__/EThree.test.ts b/src/__tests__/EThree.test.ts
index b60cbeea..8fad75a7 100644
--- a/src/__tests__/EThree.test.ts
+++ b/src/__tests__/EThree.test.ts
@@ -1,3 +1,4 @@
+import { LookupResult, onEncryptProgressSnapshot, onDecryptProgressSnapshot } from './../types';
 import {
     RegisterRequiredError,
     LookupNotFoundError,
@@ -8,6 +9,7 @@ import {
     DUPLICATE_IDENTITIES,
     PrivateKeyNoBackupError,
     EMPTY_ARRAY,
+    IntegrityCheckFailedError,
 } from '../errors';
 import {
     generator,
@@ -18,10 +20,21 @@ import {
     createFetchToken,
     virgilCrypto,
     initializeEThree,
+    initializeETheeFromIdentity,
+    readFile,
 } from './utils.test';
 import { IKeyEntry } from 'virgil-sdk';
 import { getObjectValues } from '../utils/array';
 import expect from 'expect';
+import uuid from 'uuid/v4';
+import { EThree } from '..';
+import {
+    VIRGIL_STREAM_SIGNING_STATE,
+    VIRGIL_STREAM_ENCRYPTING_STATE,
+    VIRGIL_STREAM_DECRYPTING_STATE,
+    VIRGIL_STREAM_VERIFYING_STATE,
+} from '../utils/constants';
+import 'abort-controller/polyfill';
 
 describe('EThree.register()', () => {
     before(clear);
@@ -591,3 +604,181 @@ describe('hasPrivateKey()', () => {
         return;
     });
 });
+
+describe('EThree.encryptFile/EThree.decryptFile', async () => {
+    const identity1 = uuid();
+    const identity2 = uuid();
+    const identity3 = uuid();
+
+    let sdk1: EThree, sdk2: EThree, sdk3: EThree, lookupResult: LookupResult;
+
+    const originString = 'foo'.repeat(1024 * 3);
+
+    const originFile = new File([originString], 'foo.txt', {
+        type: 'text/plain',
+    });
+
+    before(async () => {
+        [sdk1, sdk2, sdk3] = await Promise.all([
+            initializeETheeFromIdentity(identity1),
+            initializeETheeFromIdentity(identity2),
+            initializeETheeFromIdentity(identity3),
+        ]);
+
+        await Promise.all([sdk1.register(), sdk2.register(), sdk3.register()]);
+        lookupResult = await sdk1.lookupPublicKeys([identity1, identity2, identity3]);
+    });
+
+    it('should decrypt file for one public key', async () => {
+        const [publicKey2, publicKey1] = await Promise.all([
+            sdk1.lookupPublicKeys(identity2),
+            sdk2.lookupPublicKeys(identity1),
+        ]);
+
+        const encryptedFile = await sdk1.encryptFile(originFile, publicKey2);
+        const decryptedFile = await sdk2.decryptFile(encryptedFile, publicKey1);
+
+        const decryptedString = await readFile(decryptedFile);
+
+        expect(originString).toEqual(decryptedString);
+    });
+
+    it('should encrypt for multiple keys', async () => {
+        const onlyTwoKeys = await sdk1.lookupPublicKeys([identity1, identity2]);
+        const encryptedFile = await sdk1.encryptFile(originFile, onlyTwoKeys);
+        const decryptedFile = await sdk2.decryptFile(encryptedFile, onlyTwoKeys[identity1]);
+
+        const decryptedString = await readFile(decryptedFile);
+
+        expect(originString).toBe(decryptedString);
+
+        try {
+            await sdk3.decryptFile(encryptedFile, onlyTwoKeys[identity1]);
+        } catch (e) {
+            return expect(e).toBeInstanceOf(Error);
+        }
+
+        throw new Error('should throw');
+    });
+
+    it('should take input as string, file or blob', async () => {
+        const keypair = virgilCrypto.generateKeys();
+
+        const originBlob = new Blob(['foo'], {
+            type: 'text/plain',
+        });
+
+        const encryptedFile = await sdk1.encryptFile(originFile, keypair.publicKey);
+        const encryptedBlob = await sdk1.encryptFile(originBlob, keypair.publicKey);
+
+        expect(encryptedFile).toBeInstanceOf(File);
+        expect(encryptedBlob).toBeInstanceOf(Blob);
+        expect(encryptedBlob).not.toBeInstanceOf(File);
+    });
+
+    it('should process different chunks of data', async () => {
+        const encryptedSnapshots: onEncryptProgressSnapshot[] = [];
+
+        const originString = 'foo';
+
+        const originFile = new File([originString], 'foo.txt', {
+            type: 'text/plain',
+        });
+
+        expect(originFile.size).toBe(3);
+
+        const encryptedFile = await sdk1.encryptFile(originFile, lookupResult[identity2], {
+            chunkSize: 2,
+            onProgress: encryptedSnapshots.push.bind(encryptedSnapshots),
+        });
+
+        expect(encryptedSnapshots.length).toEqual(4);
+        expect(encryptedSnapshots[0]).toMatchObject({
+            fileSize: originFile.size,
+            bytesProcessed: 2,
+            state: VIRGIL_STREAM_SIGNING_STATE,
+        });
+        expect(encryptedSnapshots[1]).toMatchObject({
+            fileSize: originFile.size,
+            bytesProcessed: 3,
+            state: VIRGIL_STREAM_SIGNING_STATE,
+        });
+        expect(encryptedSnapshots[2]).toMatchObject({
+            fileSize: originFile.size,
+            bytesProcessed: 2,
+            state: VIRGIL_STREAM_ENCRYPTING_STATE,
+        });
+        expect(encryptedSnapshots[3]).toMatchObject({
+            fileSize: originFile.size,
+            bytesProcessed: 3,
+            state: VIRGIL_STREAM_ENCRYPTING_STATE,
+        });
+
+        const decryptedSnapshots: onDecryptProgressSnapshot[] = [];
+
+        await sdk2.decryptFile(encryptedFile, lookupResult[identity1], {
+            chunkSize: Math.ceil(encryptedFile.size / 2),
+            onProgress: decryptedSnapshots.push.bind(decryptedSnapshots),
+        });
+
+        expect(decryptedSnapshots.length).toEqual(3);
+        expect(decryptedSnapshots[0]).toMatchObject({
+            fileSize: encryptedFile.size,
+            bytesProcessed: Math.ceil(encryptedFile.size / 2),
+            state: VIRGIL_STREAM_DECRYPTING_STATE,
+        });
+        expect(decryptedSnapshots[1]).toMatchObject({
+            fileSize: encryptedFile.size,
+            bytesProcessed: encryptedFile.size,
+            state: VIRGIL_STREAM_DECRYPTING_STATE,
+        });
+        expect(decryptedSnapshots[2]).toMatchObject({
+            fileSize: originFile.size,
+            bytesProcessed: originFile.size,
+            state: VIRGIL_STREAM_VERIFYING_STATE,
+        });
+    });
+
+    it('should abort encryptFile', async () => {
+        const encryptAbort = new AbortController();
+        const decryptAbort = new AbortController();
+
+        const encryptPromise = sdk1.encryptFile(originFile, lookupResult[identity2]);
+        const encryptAbortedPromise = sdk1.encryptFile(originFile, lookupResult[identity2], {
+            chunkSize: 1,
+            signal: encryptAbort.signal,
+        });
+
+        encryptAbort.abort();
+
+        try {
+            await encryptAbortedPromise;
+        } catch (err) {
+            expect(err).toBeInstanceOf(Error);
+        }
+        try {
+            await sdk1.decryptFile(await encryptPromise, lookupResult[identity1], {
+                chunkSize: Math.floor(originFile.size / 3),
+                signal: decryptAbort.signal,
+                onProgress: decryptAbort.abort,
+            });
+        } catch (err) {
+            expect(err).toBeInstanceOf(Error);
+            return;
+        }
+
+        throw new Error('should throw');
+    });
+
+    it('should verify the signature', async () => {
+        const receiverPublicKey = await sdk1.lookupPublicKeys(identity2);
+        const encryptedFile = await sdk1.encryptFile(originFile, receiverPublicKey);
+        try {
+            await sdk2.decryptFile(encryptedFile);
+        } catch (err) {
+            expect(err).toBeInstanceOf(IntegrityCheckFailedError);
+            return;
+        }
+        throw new Error('should throw');
+    });
+});
diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts
index 29db3e5c..75154e80 100644
--- a/src/__tests__/utils.test.ts
+++ b/src/__tests__/utils.test.ts
@@ -53,6 +53,9 @@ export const createFetchToken = (identity: string) => () =>
 export const initializeEThree = (fetchToken: () => Promise) =>
     EThree.initialize(fetchToken, { apiUrl: process.env.API_URL });
 
+export const initializeETheeFromIdentity = (identity: string) =>
+    EThree.initialize(createFetchToken(identity));
+
 export const createSyncStorage = async (identity: string, password: string) => {
     const fetchToken = createFetchToken(identity);
 
@@ -78,3 +81,13 @@ export const createSyncStorage = async (identity: string, password: string) => {
 };
 
 export const clear = () => keyStorage.clear();
+
+export const readFile = (file: Blob) => {
+    const reader = new FileReader();
+
+    const promise = new Promise(r => reader.addEventListener('loadend', () => r(reader.result!)));
+
+    reader.readAsText(file);
+
+    return promise;
+};
diff --git a/src/errors.ts b/src/errors.ts
index 1aefa58b..745f1462 100644
--- a/src/errors.ts
+++ b/src/errors.ts
@@ -6,9 +6,17 @@ export const DUPLICATE_IDENTITIES = 'Identities in array should be unique';
  * @hidden
  */
 export const EMPTY_ARRAY = `Array should be non empty`;
+/**
+ * @hidden
+ */
+export const throwIllegalInvocationError = (method: string) => {
+    throw new Error(`Calling ${method} two or more times in a row is not allowed.`);
+};
+
 /**
  * Custom error class for errors specific to Virgil E3kit.
  */
+
 export class SdkError extends Error {
     name: string;
     constructor(m: string, name: string = 'SdkError') {
@@ -116,3 +124,21 @@ export class LookupNotFoundError extends SdkError {
         super(`${identity} not found`, 'LookupNotFoundError');
     }
 }
+
+/**
+ * Error thrown by {@link EThree.decryptFile} in case if signature of the file is not valid.
+ */
+export class IntegrityCheckFailedError extends SdkError {
+    constructor(message: string) {
+        super(message, 'IntegrityCheckFailedError');
+    }
+}
+
+/**
+ * Error thrown by {@link EThree.decryptFile} or {@link EThree.encryptFile} if user aborts an operation.
+ */
+export class AbortError extends SdkError {
+    constructor() {
+        super('Operation aborted by user', 'AbortError');
+    }
+}
diff --git a/src/index.ts b/src/index.ts
index 6f6a9873..a162c032 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,6 @@
 import 'es6-symbol/implement';
 
-export { default as EThree } from './EThree';
+export * from './EThree';
 export * from './errors';
+export * from './types';
+export { default as EThree } from './EThree';
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 00000000..a453b497
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,104 @@
+import { VirgilPublicKey } from 'virgil-crypto';
+import {
+    VIRGIL_STREAM_SIGNING_STATE,
+    VIRGIL_STREAM_ENCRYPTING_STATE,
+    VIRGIL_STREAM_VERIFYING_STATE,
+    VIRGIL_STREAM_DECRYPTING_STATE,
+} from './utils/constants';
+import { IKeyEntryStorage } from 'virgil-sdk';
+
+export interface EThreeInitializeOptions {
+    /**
+     * Implementation of IKeyEntryStorage. Used IndexedDB Key Storage from
+     * [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript) by default.
+     */
+    keyEntryStorage?: IKeyEntryStorage;
+    /**
+     * Url of the Card Services. Used for development purposes.
+     */
+    apiUrl?: string;
+}
+
+/**
+ * Dictionary returned from lookupPublicKey method
+ */
+
+export type LookupResult = {
+    [identity: string]: VirgilPublicKey;
+};
+
+/**
+ * Argument for encrypt function can be single VirgilPublicKey or LookupResult
+ */
+export type EncryptVirgilPublicKeyArg = LookupResult | VirgilPublicKey;
+
+/**
+ * Callback invoked for each chunk being processed in encryptFile method.
+ */
+export type onEncryptProgressCallback = (snapshot: onEncryptProgressSnapshot) => void;
+
+/**
+ * Callback invoked for each chunk being processed in decryptFile method.
+ */
+export type onDecryptProgressCallback = (snapshot: onDecryptProgressSnapshot) => void;
+
+interface onProgressSnapshot {
+    /**
+     * Total size of the file being processed.
+     */
+    fileSize: number;
+    /**
+     * Size of the file being encrypted in bytes.
+     */
+    bytesProcessed: number;
+}
+
+/**
+ * An argument of the onEncryptProgressCallback.
+ */
+export interface onEncryptProgressSnapshot extends onProgressSnapshot {
+    /**
+     * Current status of processing. Can be "Signing" then "Encrypting".
+     */
+    state: VIRGIL_STREAM_SIGNING_STATE | VIRGIL_STREAM_ENCRYPTING_STATE;
+}
+
+export interface onDecryptProgressSnapshot extends onProgressSnapshot {
+    /**
+     * Current status of processing. Can be "Decrypting" then "Verifying".
+     */
+    state: VIRGIL_STREAM_DECRYPTING_STATE | VIRGIL_STREAM_VERIFYING_STATE;
+}
+
+interface FileOptions {
+    /**
+     * Size of chunk being processed at one time. Bigger chunks make function execute faster, but
+     * consume more memory in one time and can cause a performance hit. Default value is 64kb.
+     */
+    chunkSize?: number;
+    /**
+     * Instance of `AbortSignal` which can be received from `AbortController`. Used to cancel encryptFile
+     * operation.
+     */
+    signal?: AbortSignal;
+}
+
+/**
+ * Options for encryptedFile method.
+ */
+export interface EncryptFileOptions extends FileOptions {
+    /**
+     * `onEncryptProgressCallback` parameter.
+     */
+    onProgress?: onEncryptProgressCallback;
+}
+
+/**
+ * Options for decryptedFile method.
+ */
+export interface DecryptFileOptions extends FileOptions {
+    /**
+     * `onDecryptProgressCallback` parameter.
+     */
+    onProgress?: onDecryptProgressCallback;
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
new file mode 100644
index 00000000..b1de31eb
--- /dev/null
+++ b/src/utils/constants.ts
@@ -0,0 +1,20 @@
+/**
+ * @hidden
+ */
+export const STORAGE_NAME = '.virgil-local-storage';
+/**
+ * @hidden
+ */
+export const DEFAULT_API_URL = 'https://api.virgilsecurity.com';
+
+export type VIRGIL_STREAM_SIGNING_STATE = 'Signing';
+export const VIRGIL_STREAM_SIGNING_STATE = 'Signing';
+
+export type VIRGIL_STREAM_ENCRYPTING_STATE = 'Encrypting';
+export const VIRGIL_STREAM_ENCRYPTING_STATE = 'Encrypting';
+
+export type VIRGIL_STREAM_DECRYPTING_STATE = 'Decrypting';
+export const VIRGIL_STREAM_DECRYPTING_STATE = 'Decrypting';
+
+export type VIRGIL_STREAM_VERIFYING_STATE = 'Verifying';
+export const VIRGIL_STREAM_VERIFYING_STATE = 'Verifying';
diff --git a/src/utils/innerTypes.ts b/src/utils/innerTypes.ts
new file mode 100644
index 00000000..b8b131d3
--- /dev/null
+++ b/src/utils/innerTypes.ts
@@ -0,0 +1,21 @@
+import { VirgilPrivateKey, VirgilPublicKey } from 'virgil-crypto';
+import { IAccessTokenProvider } from 'virgil-sdk';
+import { EThreeInitializeOptions } from '../types';
+
+/**
+ * @hidden
+ */
+export interface EThreeCtorOptions extends EThreeInitializeOptions {
+    /**
+     * Implementation of IAccessTokenProvider from [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript);
+     */
+    accessTokenProvider: IAccessTokenProvider;
+}
+
+/**
+ * @hidden
+ */
+export type KeyPair = {
+    privateKey: VirgilPrivateKey;
+    publicKey: VirgilPublicKey;
+};
diff --git a/src/utils/processFile.ts b/src/utils/processFile.ts
new file mode 100644
index 00000000..27390f7d
--- /dev/null
+++ b/src/utils/processFile.ts
@@ -0,0 +1,73 @@
+import { AbortError } from '../errors';
+
+/**
+ * @hidden
+ */
+export type onChunkCallback = (chunk: string | ArrayBuffer, offset: number) => void;
+
+/**
+ * @hidden
+ */
+export type processFileOptions = {
+    file: Blob;
+    chunkSize: number;
+    signal?: AbortSignal;
+    onChunkCallback: onChunkCallback;
+    onFinishCallback: () => void;
+    onErrorCallback: (err: any) => void;
+};
+
+/**
+ * @hidden
+ */
+export function processFile({
+    file,
+    chunkSize,
+    signal,
+    onChunkCallback,
+    onFinishCallback,
+    onErrorCallback,
+}: processFileOptions) {
+    const reader = new FileReader();
+
+    const dataSize = file.size;
+
+    let offset = 0;
+    let endOffset = Math.min(offset + chunkSize, dataSize);
+
+    if (signal) {
+        const onAbort = () => {
+            reader.abort();
+            onErrorCallback(new AbortError());
+        };
+        if (signal.aborted) return onAbort();
+        else signal.addEventListener('abort', onAbort);
+    }
+
+    reader.onload = () => {
+        if (!reader.result) throw new Error('reader.result is null');
+
+        try {
+            onChunkCallback(reader.result, endOffset);
+        } catch (err) {
+            return onErrorCallback(err);
+        }
+
+        offset = endOffset;
+        endOffset = Math.min(offset + chunkSize, dataSize);
+
+        if (offset === dataSize) {
+            try {
+                onFinishCallback();
+            } catch (err) {
+                onErrorCallback(err);
+            }
+        } else {
+            reader.readAsArrayBuffer(file.slice(offset, endOffset));
+        }
+    };
+
+    reader.onerror = () => onErrorCallback(reader.error);
+
+    reader.readAsArrayBuffer(file.slice(offset, endOffset));
+}
diff --git a/src/utils/typeguards.ts b/src/utils/typeguards.ts
index babf7724..03637916 100644
--- a/src/utils/typeguards.ts
+++ b/src/utils/typeguards.ts
@@ -20,6 +20,18 @@ export const isWithoutErrors = (arr: Array): arr is Array => {
 export const isString = (val: any): val is string => {
     return typeof val === 'string';
 };
+/**
+ * @hidden
+ */
+export const isBlob = (val: any): val is Blob => {
+    return val instanceof Blob;
+};
+/**
+ * @hidden
+ */
+export const isFile = (val: any): val is File => {
+    return val instanceof File;
+};
 /**
  * @hidden
  */
diff --git a/tsconfig.json b/tsconfig.json
index 7f3886d6..bc095f41 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,38 +1,39 @@
 {
-  "compilerOptions": {
-    "target": "es5",
-    "lib": [
-      "es2015",
-      "es2016",
-      "es2017",
-      "es2018"
+    "compilerOptions": {
+        "target": "es5",
+        "lib": [
+            "dom",
+            "es2015",
+            "es2016",
+            "es2017",
+            "es2018"
+        ],
+        "declaration": true,
+        "declarationDir": "./dist/types",
+        "strict": true,
+        "moduleResolution": "node",
+        "esModuleInterop": true,
+        "allowSyntheticDefaultImports": true,
+        "noUnusedLocals": true,
+    },
+    "include": [
+        "src"
     ],
-    "declaration": true,
-    "declarationDir": "./dist/types",
-    "strict": true,
-    "moduleResolution": "node",
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "noUnusedLocals": true,
-  },
-  "include": [
-    "src"
-  ],
-  "typedocOptions": {
-    "out": "docs",
-    "mode": "file",
-    "target": "ES6",
-    "module": "es6",
-    "moduleResolution": "node",
-    "exclude": "**/__tests__/**",
-    "ignoreCompilerErrors": true,
-    "excludePrivate": true,
-    "excludeNotExported": true,
-    "stripInternal": true,
-    "excludeExternals": true,
-    "suppressExcessPropertyErrors": true,
-    "suppressImplicitAnyIndexErrors": true,
-    "hideGenerator": true,
-    "readme": "none"
-  }
+    "typedocOptions": {
+        "out": "docs",
+        "mode": "file",
+        "target": "ES6",
+        "module": "es6",
+        "moduleResolution": "node",
+        "exclude": "**/__tests__/**",
+        "ignoreCompilerErrors": true,
+        "excludePrivate": true,
+        "excludeNotExported": true,
+        "stripInternal": true,
+        "excludeExternals": true,
+        "suppressExcessPropertyErrors": true,
+        "suppressImplicitAnyIndexErrors": true,
+        "hideGenerator": true,
+        "readme": "none"
+    }
 }