crypto_util.dart 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import 'dart:typed_data';
  2. import 'dart:io' as io;
  3. import 'package:computer/computer.dart';
  4. import 'package:flutter_sodium/flutter_sodium.dart';
  5. import 'package:logging/logging.dart';
  6. import 'package:photos/models/encryption_result.dart';
  7. final int encryptionChunkSize = 4 * 1024 * 1024;
  8. final int decryptionChunkSize =
  9. encryptionChunkSize + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
  10. Uint8List cryptoSecretboxEasy(Map<String, dynamic> args) {
  11. return Sodium.cryptoSecretboxEasy(args["source"], args["nonce"], args["key"]);
  12. }
  13. Uint8List cryptoSecretboxOpenEasy(Map<String, dynamic> args) {
  14. return Sodium.cryptoSecretboxOpenEasy(
  15. args["cipher"], args["nonce"], args["key"]);
  16. }
  17. Uint8List cryptoPwHash(Map<String, dynamic> args) {
  18. return Sodium.cryptoPwhash(
  19. Sodium.cryptoSecretboxKeybytes,
  20. args["password"],
  21. args["salt"],
  22. args["opsLimit"],
  23. args["memLimit"],
  24. Sodium.cryptoPwhashAlgDefault,
  25. );
  26. }
  27. EncryptionResult chachaEncryptFile(Map<String, dynamic> args) {
  28. final encryptionStartTime = DateTime.now().millisecondsSinceEpoch;
  29. final logger = Logger("ChaChaEncrypt");
  30. final sourceFile = io.File(args["sourceFilePath"]);
  31. final destinationFile = io.File(args["destinationFilePath"]);
  32. final sourceFileLength = sourceFile.lengthSync();
  33. logger.info("Encrypting file of size " + sourceFileLength.toString());
  34. final inputFile = sourceFile.openSync(mode: io.FileMode.read);
  35. final key = args["key"] ?? Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
  36. final initPushResult =
  37. Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
  38. var bytesRead = 0;
  39. var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
  40. while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
  41. var chunkSize = encryptionChunkSize;
  42. if (bytesRead + chunkSize >= sourceFileLength) {
  43. chunkSize = sourceFileLength - bytesRead;
  44. tag = Sodium.cryptoSecretstreamXchacha20poly1305TagFinal;
  45. }
  46. final buffer = inputFile.readSync(chunkSize);
  47. bytesRead += chunkSize;
  48. final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
  49. initPushResult.state, buffer, null, tag);
  50. destinationFile.writeAsBytesSync(encryptedData, mode: io.FileMode.append);
  51. }
  52. inputFile.closeSync();
  53. logger.info("Encryption time: " +
  54. (DateTime.now().millisecondsSinceEpoch - encryptionStartTime).toString());
  55. return EncryptionResult(key: key, header: initPushResult.header);
  56. }
  57. void chachaDecrypt(Map<String, dynamic> args) {
  58. final logger = Logger("ChaChaDecrypt");
  59. final decryptionStartTime = DateTime.now().millisecondsSinceEpoch;
  60. final sourceFile = io.File(args["sourceFilePath"]);
  61. final destinationFile = io.File(args["destinationFilePath"]);
  62. final sourceFileLength = sourceFile.lengthSync();
  63. logger.info("Decrypting file of size " + sourceFileLength.toString());
  64. final inputFile = sourceFile.openSync(mode: io.FileMode.read);
  65. final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull(
  66. args["header"], args["key"]);
  67. var bytesRead = 0;
  68. var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
  69. while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
  70. var chunkSize = decryptionChunkSize;
  71. if (bytesRead + chunkSize >= sourceFileLength) {
  72. chunkSize = sourceFileLength - bytesRead;
  73. }
  74. final buffer = inputFile.readSync(chunkSize);
  75. bytesRead += chunkSize;
  76. final pullResult =
  77. Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
  78. destinationFile.writeAsBytesSync(pullResult.m, mode: io.FileMode.append);
  79. tag = pullResult.tag;
  80. }
  81. inputFile.closeSync();
  82. logger.info("ChaCha20 Decryption time: " +
  83. (DateTime.now().millisecondsSinceEpoch - decryptionStartTime).toString());
  84. }
  85. class CryptoUtil {
  86. static Computer _computer = Computer();
  87. static init() {
  88. _computer.turnOn(workersCount: 4);
  89. Sodium.init();
  90. }
  91. static EncryptionResult encryptSync(Uint8List source, Uint8List key) {
  92. final nonce = Sodium.randombytesBuf(Sodium.cryptoSecretboxNoncebytes);
  93. final args = Map<String, dynamic>();
  94. args["source"] = source;
  95. args["nonce"] = nonce;
  96. args["key"] = key;
  97. final encryptedData = cryptoSecretboxEasy(args);
  98. return EncryptionResult(
  99. key: key, nonce: nonce, encryptedData: encryptedData);
  100. }
  101. static Future<Uint8List> decrypt(
  102. Uint8List cipher,
  103. Uint8List key,
  104. Uint8List nonce,
  105. ) async {
  106. final args = Map<String, dynamic>();
  107. args["cipher"] = cipher;
  108. args["nonce"] = nonce;
  109. args["key"] = key;
  110. return _computer.compute(cryptoSecretboxOpenEasy, param: args);
  111. }
  112. static Uint8List decryptSync(
  113. Uint8List cipher,
  114. Uint8List key,
  115. Uint8List nonce,
  116. ) {
  117. final args = Map<String, dynamic>();
  118. args["cipher"] = cipher;
  119. args["nonce"] = nonce;
  120. args["key"] = key;
  121. return cryptoSecretboxOpenEasy(args);
  122. }
  123. static EncryptionResult encryptChaCha(Uint8List source, Uint8List key) {
  124. final initPushResult =
  125. Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
  126. final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
  127. initPushResult.state,
  128. source,
  129. null,
  130. Sodium.cryptoSecretstreamXchacha20poly1305TagFinal);
  131. return EncryptionResult(
  132. encryptedData: encryptedData, header: initPushResult.header);
  133. }
  134. static Uint8List decryptChaCha(
  135. Uint8List source, Uint8List key, Uint8List header) {
  136. final pullState =
  137. Sodium.cryptoSecretstreamXchacha20poly1305InitPull(header, key);
  138. final pullResult =
  139. Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, source, null);
  140. return pullResult.m;
  141. }
  142. static Future<EncryptionResult> encryptFile(
  143. String sourceFilePath,
  144. String destinationFilePath, {
  145. Uint8List key,
  146. }) {
  147. final args = Map<String, dynamic>();
  148. args["sourceFilePath"] = sourceFilePath;
  149. args["destinationFilePath"] = destinationFilePath;
  150. args["key"] = key;
  151. return _computer.compute(chachaEncryptFile, param: args);
  152. }
  153. static Future<void> decryptFile(
  154. String sourceFilePath,
  155. String destinationFilePath,
  156. Uint8List header,
  157. Uint8List key,
  158. ) {
  159. final args = Map<String, dynamic>();
  160. args["sourceFilePath"] = sourceFilePath;
  161. args["destinationFilePath"] = destinationFilePath;
  162. args["header"] = header;
  163. args["key"] = key;
  164. return _computer.compute(chachaDecrypt, param: args);
  165. }
  166. static Uint8List generateKey() {
  167. return Sodium.cryptoSecretboxKeygen();
  168. }
  169. static Uint8List getSaltToDeriveKey() {
  170. return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
  171. }
  172. static Future<Uint8List> deriveKey(
  173. Uint8List password,
  174. Uint8List salt,
  175. int memLimit,
  176. int opsLimit,
  177. ) {
  178. return _computer.compute(cryptoPwHash, param: {
  179. "password": password,
  180. "salt": salt,
  181. "memLimit": memLimit,
  182. "opsLimit": opsLimit,
  183. });
  184. }
  185. static Future<KeyPair> generateKeyPair() async {
  186. return Sodium.cryptoBoxKeypair();
  187. }
  188. static Uint8List openSealSync(
  189. Uint8List input, Uint8List publicKey, Uint8List secretKey) {
  190. return Sodium.cryptoBoxSealOpen(input, publicKey, secretKey);
  191. }
  192. static Uint8List sealSync(Uint8List input, Uint8List publicKey) {
  193. return Sodium.cryptoBoxSeal(input, publicKey);
  194. }
  195. }