Forráskód Böngészése

Generate and store public private keypairs on the server

Vishnu Mohandas 4 éve
szülő
commit
5a25676dc4

+ 18 - 26
lib/core/configuration.dart

@@ -21,10 +21,7 @@ class Configuration {
   static const hasOptedForE2EKey = "has_opted_for_e2e_encryption";
   static const foldersToBackUpKey = "folders_to_back_up";
   static const keyKey = "key";
-  static const kekSaltKey = "kek_salt";
-  static const kekHashKey = "kek_hash";
-  static const encryptedKeyKey = "encrypted_key";
-  static const keyDecryptionNonceKey = "key_decryption_nonce";
+  static const keyAttributesKey = "key_attributes";
 
   SharedPreferences _preferences;
   FlutterSecureStorage _secureStorage;
@@ -58,11 +55,20 @@ class Configuration {
 
     // Hash the passphrase so that its correctness can be compared later
     final kekHash = await CryptoUtil.hash(kek);
+
+    // Generate a public-private keypair and encrypt the latter
+    final keyPair = await CryptoUtil.generateKeyPair();
+    final encryptedSecretKeyData =
+        await CryptoUtil.encrypt(keyPair.sk, key: kek);
+
     final attributes = KeyAttributes(
       Sodium.bin2base64(kekSalt),
       kekHash,
       encryptedKeyData.encryptedData.base64,
       encryptedKeyData.nonce.base64,
+      Sodium.bin2base64(keyPair.pk),
+      encryptedSecretKeyData.encryptedData.base64,
+      encryptedSecretKeyData.nonce.base64,
     );
     await setKey(Sodium.bin2base64(key));
     await setKeyAttributes(attributes);
@@ -146,26 +152,16 @@ class Configuration {
 
   Future<void> setKeyAttributes(KeyAttributes attributes) async {
     await _preferences.setString(
-        kekSaltKey, attributes == null ? null : attributes.kekSalt);
-    await _preferences.setString(
-        kekHashKey, attributes == null ? null : attributes.kekHash);
-    await _preferences.setString(
-        encryptedKeyKey, attributes == null ? null : attributes.encryptedKey);
-    await _preferences.setString(keyDecryptionNonceKey,
-        attributes == null ? null : attributes.keyDecryptionNonce);
+        keyAttributesKey, attributes == null ? null : attributes.toJson());
   }
 
   KeyAttributes getKeyAttributes() {
-    return KeyAttributes(
-      _preferences.getString(kekSaltKey),
-      _preferences.getString(kekHashKey),
-      _preferences.getString(encryptedKeyKey),
-      _preferences.getString(keyDecryptionNonceKey),
-    );
-  }
-
-  String getEncryptedKey() {
-    return _preferences.getString(encryptedKeyKey);
+    final jsonValue = _preferences.getString(keyAttributesKey);
+    if (keyAttributesKey == null) {
+      return null;
+    } else {
+      return KeyAttributes.fromJson(jsonValue);
+    }
   }
 
   Future<void> setKey(String key) async {
@@ -177,10 +173,6 @@ class Configuration {
     return Sodium.base642bin(_key);
   }
 
-  String getBase64EncodedKey() {
-    return _key;
-  }
-
   String getDocumentsDirectory() {
     return _documentsDirectory;
   }
@@ -194,6 +186,6 @@ class Configuration {
   }
 
   bool hasConfiguredAccount() {
-    return getToken() != null && getBase64EncodedKey() != null;
+    return getToken() != null && getKey() != null;
   }
 }

+ 27 - 3
lib/models/key_attributes.dart

@@ -5,12 +5,18 @@ class KeyAttributes {
   final String kekHash;
   final String encryptedKey;
   final String keyDecryptionNonce;
+  final String publicKey;
+  final String encryptedSecretKey;
+  final String secretKeyDecryptionNonce;
 
   KeyAttributes(
     this.kekSalt,
     this.kekHash,
     this.encryptedKey,
     this.keyDecryptionNonce,
+    this.publicKey,
+    this.encryptedSecretKey,
+    this.secretKeyDecryptionNonce,
   );
 
   KeyAttributes copyWith({
@@ -18,12 +24,18 @@ class KeyAttributes {
     String kekHash,
     String encryptedKey,
     String keyDecryptionNonce,
+    String publicKey,
+    String encryptedSecretKey,
+    String secretKeyDecryptionNonce,
   }) {
     return KeyAttributes(
       kekSalt ?? this.kekSalt,
       kekHash ?? this.kekHash,
       encryptedKey ?? this.encryptedKey,
       keyDecryptionNonce ?? this.keyDecryptionNonce,
+      publicKey ?? this.publicKey,
+      encryptedSecretKey ?? this.encryptedSecretKey,
+      secretKeyDecryptionNonce ?? this.secretKeyDecryptionNonce,
     );
   }
 
@@ -33,6 +45,9 @@ class KeyAttributes {
       'kekHash': kekHash,
       'encryptedKey': encryptedKey,
       'keyDecryptionNonce': keyDecryptionNonce,
+      'publicKey': publicKey,
+      'encryptedSecretKey': encryptedSecretKey,
+      'secretKeyDecryptionNonce': secretKeyDecryptionNonce,
     };
   }
 
@@ -44,6 +59,9 @@ class KeyAttributes {
       map['kekHash'],
       map['encryptedKey'],
       map['keyDecryptionNonce'],
+      map['publicKey'],
+      map['encryptedSecretKey'],
+      map['secretKeyDecryptionNonce'],
     );
   }
 
@@ -54,7 +72,7 @@ class KeyAttributes {
 
   @override
   String toString() {
-    return 'KeyAttributes(kekSalt: $kekSalt, kekHash: $kekHash, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce)';
+    return 'KeyAttributes(kekSalt: $kekSalt, kekHash: $kekHash, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, publicKey: $publicKey, encryptedSecretKey: $encryptedSecretKey, secretKeyDecryptionNonce: $secretKeyDecryptionNonce)';
   }
 
   @override
@@ -65,7 +83,10 @@ class KeyAttributes {
         o.kekSalt == kekSalt &&
         o.kekHash == kekHash &&
         o.encryptedKey == encryptedKey &&
-        o.keyDecryptionNonce == keyDecryptionNonce;
+        o.keyDecryptionNonce == keyDecryptionNonce &&
+        o.publicKey == publicKey &&
+        o.encryptedSecretKey == encryptedSecretKey &&
+        o.secretKeyDecryptionNonce == secretKeyDecryptionNonce;
   }
 
   @override
@@ -73,6 +94,9 @@ class KeyAttributes {
     return kekSalt.hashCode ^
         kekHash.hashCode ^
         encryptedKey.hashCode ^
-        keyDecryptionNonce.hashCode;
+        keyDecryptionNonce.hashCode ^
+        publicKey.hashCode ^
+        encryptedSecretKey.hashCode ^
+        secretKeyDecryptionNonce.hashCode;
   }
 }

+ 1 - 1
lib/ui/gallery_app_bar_widget.dart

@@ -108,7 +108,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
             page = EmailEntryPage();
           } else {
             // No key
-            if (Configuration.instance.getEncryptedKey() != null) {
+            if (Configuration.instance.getKey() == null) {
               // Yet to decrypt the key
               page = PassphraseReentryPage();
             } else {

+ 2 - 1
lib/ui/settings_page.dart

@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_email_sender/flutter_email_sender.dart';
+import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/db/files_db.dart';
@@ -289,7 +290,7 @@ class DebugWidget extends StatelessWidget {
       content: SingleChildScrollView(
         child: Column(children: [
           Text("Key", style: TextStyle(fontWeight: FontWeight.bold)),
-          Text(Configuration.instance.getBase64EncodedKey()),
+          Text(Sodium.bin2base64(Configuration.instance.getKey())),
           Padding(padding: EdgeInsets.all(12)),
           Text("Encrypted Key", style: TextStyle(fontWeight: FontWeight.bold)),
           Text(keyAttributes.encryptedKey),

+ 1 - 1
lib/user_authenticator.dart

@@ -65,7 +65,7 @@ class UserAuthenticator {
         await _saveConfiguration(response);
         showToast("Email verification successful!");
         var page;
-        if (Configuration.instance.getEncryptedKey() != null) {
+        if (Configuration.instance.getKeyAttributes() != null) {
           page = PassphraseReentryPage();
         } else {
           page = PassphraseEntryPage();

+ 4 - 0
lib/utils/crypto_util.dart

@@ -190,4 +190,8 @@ class CryptoUtil {
     args["hash"] = utf8.encode(hash);
     return await Computer().compute(cryptoPwhashStrVerify, param: args);
   }
+
+  static Future<KeyPair> generateKeyPair() async {
+    return Sodium.cryptoBoxKeypair();
+  }
 }