瀏覽代碼

SRP: Add method to derive loginKey from keyEncKey

Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com>
Neeraj Gupta 2 年之前
父節點
當前提交
796a6e128a
共有 1 個文件被更改,包括 66 次插入57 次删除
  1. 66 57
      lib/utils/crypto_util.dart

+ 66 - 57
lib/utils/crypto_util.dart

@@ -1,3 +1,4 @@
+import "dart:convert";
 import 'dart:io' as io;
 import 'dart:typed_data';
 
@@ -12,6 +13,9 @@ const int encryptionChunkSize = 4 * 1024 * 1024;
 final int decryptionChunkSize =
     encryptionChunkSize + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
 const int hashChunkSize = 4 * 1024 * 1024;
+const int loginSubKeyLen = 128;
+const int loginSubKeyId = 1;
+const String loginSubKeyContext = "login";
 
 Uint8List cryptoSecretboxEasy(Map<String, dynamic> args) {
   return Sodium.cryptoSecretboxEasy(args["source"], args["nonce"], args["key"]);
@@ -36,6 +40,17 @@ Uint8List cryptoPwHash(Map<String, dynamic> args) {
   );
 }
 
+Uint8List cryptoKdfDeriveFromKey(
+  Map<String, dynamic> args,
+) {
+  return Sodium.cryptoKdfDeriveFromKey(
+    args["subkeyLen"],
+    args["subkeyId"],
+    args["context"],
+    args["key"],
+  );
+}
+
 // Returns the hash for a given file, chunking it in batches of hashChunkSize
 Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
   final sourceFile = io.File(args["sourceFilePath"]);
@@ -61,7 +76,7 @@ Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
 
 EncryptionResult chachaEncryptData(Map<String, dynamic> args) {
   final initPushResult =
-      Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]);
+  Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]);
   final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
     initPushResult.state,
     args["source"],
@@ -86,7 +101,7 @@ Future<EncryptionResult> chachaEncryptFile(Map<String, dynamic> args) async {
   final inputFile = sourceFile.openSync(mode: io.FileMode.read);
   final key = args["key"] ?? Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
   final initPushResult =
-      Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
+  Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
   var bytesRead = 0;
   var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
   while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
@@ -140,7 +155,7 @@ Future<void> chachaDecryptFile(Map<String, dynamic> args) async {
     final buffer = await inputFile.read(chunkSize);
     bytesRead += chunkSize;
     final pullResult =
-        Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
+    Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
     await destinationFile.writeAsBytes(pullResult.m, mode: io.FileMode.append);
     tag = pullResult.tag;
   }
@@ -174,22 +189,20 @@ class CryptoUtil {
     Sodium.init();
   }
 
-  static Uint8List base642bin(
-    String b64, {
+  static Uint8List base642bin(String b64, {
     String? ignore,
     int variant = Sodium.base64VariantOriginal,
   }) {
     return Sodium.base642bin(b64, ignore: ignore, variant: variant);
   }
 
-  static String bin2base64(
-    Uint8List bin, {
+  static String bin2base64(Uint8List bin, {
     bool urlSafe = false,
   }) {
     return Sodium.bin2base64(
       bin,
       variant:
-          urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal,
+      urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal,
     );
   }
 
@@ -223,11 +236,9 @@ class CryptoUtil {
 
   // Decrypts the given cipher, with the given key and nonce using XSalsa20
   // (w Poly1305 MAC).
-  static Future<Uint8List> decrypt(
-    Uint8List cipher,
-    Uint8List key,
-    Uint8List nonce,
-  ) async {
+  static Future<Uint8List> decrypt(Uint8List cipher,
+      Uint8List key,
+      Uint8List nonce,) async {
     final args = <String, dynamic>{};
     args["cipher"] = cipher;
     args["nonce"] = nonce;
@@ -244,11 +255,9 @@ class CryptoUtil {
   // This function runs on the same thread as the caller, so should be used only
   // for small amounts of data where thread switching can result in a degraded
   // user experience
-  static Uint8List decryptSync(
-    Uint8List cipher,
-    Uint8List key,
-    Uint8List nonce,
-  ) {
+  static Uint8List decryptSync(Uint8List cipher,
+      Uint8List key,
+      Uint8List nonce,) {
     final args = <String, dynamic>{};
     args["cipher"] = cipher;
     args["nonce"] = nonce;
@@ -260,10 +269,8 @@ class CryptoUtil {
   // nonce, using XChaCha20 (w Poly1305 MAC).
   // This function runs on the isolate pool held by `_computer`.
   // TODO: Remove "ChaCha", an implementation detail from the function name
-  static Future<EncryptionResult> encryptChaCha(
-    Uint8List source,
-    Uint8List key,
-  ) async {
+  static Future<EncryptionResult> encryptChaCha(Uint8List source,
+      Uint8List key,) async {
     final args = <String, dynamic>{};
     args["source"] = source;
     args["key"] = key;
@@ -277,11 +284,9 @@ class CryptoUtil {
   // Decrypts the given source, with the given key and header using XChaCha20
   // (w Poly1305 MAC).
   // TODO: Remove "ChaCha", an implementation detail from the function name
-  static Future<Uint8List> decryptChaCha(
-    Uint8List source,
-    Uint8List key,
-    Uint8List header,
-  ) async {
+  static Future<Uint8List> decryptChaCha(Uint8List source,
+      Uint8List key,
+      Uint8List header,) async {
     final args = <String, dynamic>{};
     args["source"] = source;
     args["key"] = key;
@@ -297,11 +302,10 @@ class CryptoUtil {
   // randomly generated nonce using XChaCha20 (w Poly1305 MAC), and writes it
   // to the destinationFilePath.
   // If a key is not provided, one is generated and returned.
-  static Future<EncryptionResult> encryptFile(
-    String sourceFilePath,
-    String destinationFilePath, {
-    Uint8List? key,
-  }) {
+  static Future<EncryptionResult> encryptFile(String sourceFilePath,
+      String destinationFilePath, {
+        Uint8List? key,
+      }) {
     final args = <String, dynamic>{};
     args["sourceFilePath"] = sourceFilePath;
     args["destinationFilePath"] = destinationFilePath;
@@ -315,12 +319,10 @@ class CryptoUtil {
 
   // Decrypts the file at sourceFilePath, with the given key and header using
   // XChaCha20 (w Poly1305 MAC), and writes it to the destinationFilePath.
-  static Future<void> decryptFile(
-    String sourceFilePath,
-    String destinationFilePath,
-    Uint8List header,
-    Uint8List key,
-  ) {
+  static Future<void> decryptFile(String sourceFilePath,
+      String destinationFilePath,
+      Uint8List header,
+      Uint8List key,) {
     final args = <String, dynamic>{};
     args["sourceFilePath"] = sourceFilePath;
     args["destinationFilePath"] = destinationFilePath;
@@ -350,11 +352,9 @@ class CryptoUtil {
   }
 
   // Decrypts the input using the given publicKey-secretKey pair
-  static Uint8List openSealSync(
-    Uint8List input,
-    Uint8List publicKey,
-    Uint8List secretKey,
-  ) {
+  static Uint8List openSealSync(Uint8List input,
+      Uint8List publicKey,
+      Uint8List secretKey,) {
     return Sodium.cryptoBoxSealOpen(input, publicKey, secretKey);
   }
 
@@ -371,10 +371,8 @@ class CryptoUtil {
   // the min and max limits for both parameters.
   // At all points, we ensure that the product of these two variables (the area
   // under the graph that determines the amount of work required) is a constant.
-  static Future<DerivedKeyResult> deriveSensitiveKey(
-    Uint8List password,
-    Uint8List salt,
-  ) async {
+  static Future<DerivedKeyResult> deriveSensitiveKey(Uint8List password,
+      Uint8List salt,) async {
     final logger = Logger("pwhash");
     int memLimit = Sodium.cryptoPwhashMemlimitSensitive;
     int opsLimit = Sodium.cryptoPwhashOpslimitSensitive;
@@ -418,10 +416,8 @@ class CryptoUtil {
   // NOTE: This is only used while setting passwords for shared links, as an
   // extra layer of authentication (atop the access token and collection key).
   // More details @ https://ente.io/blog/building-shareable-links/
-  static Future<DerivedKeyResult> deriveInteractiveKey(
-    Uint8List password,
-    Uint8List salt,
-  ) async {
+  static Future<DerivedKeyResult> deriveInteractiveKey(Uint8List password,
+      Uint8List salt,) async {
     final int memLimit = Sodium.cryptoPwhashMemlimitInteractive;
     final int opsLimit = Sodium.cryptoPwhashOpslimitInteractive;
     final key = await deriveKey(password, salt, memLimit, opsLimit);
@@ -430,12 +426,10 @@ class CryptoUtil {
 
   // Derives a key for a given password, salt, memLimit and opsLimit using
   // Argon2id, v1.3.
-  static Future<Uint8List> deriveKey(
-    Uint8List password,
-    Uint8List salt,
-    int memLimit,
-    int opsLimit,
-  ) {
+  static Future<Uint8List> deriveKey(Uint8List password,
+      Uint8List salt,
+      int memLimit,
+      int opsLimit,) {
     return _computer.compute(
       cryptoPwHash,
       param: {
@@ -448,6 +442,21 @@ class CryptoUtil {
     );
   }
 
+  static Future<Uint8List> deriveLoginKey(
+    Uint8List key,
+  ) {
+    return _computer.compute(
+      cryptoKdfDeriveFromKey,
+      param: {
+        "key": key,
+        "subkeyId": loginSubKeyId,
+        "subkeyLen": loginSubKeyLen,
+        "context": utf8.encode(loginSubKeyContext),
+      },
+      taskName: "deriveKey",
+    );
+  }
+
   // Computes and returns the hash of the source file
   static Future<Uint8List> getHash(io.File source) {
     return _computer.compute(