Browse Source

Generate recovery key as per specs

Vishnu Mohandas 4 years ago
parent
commit
d7acc95855
3 changed files with 93 additions and 16 deletions
  1. 43 13
      lib/core/configuration.dart
  2. 48 2
      lib/models/key_attributes.dart
  3. 2 1
      lib/models/private_key_attributes.dart

+ 43 - 13
lib/core/configuration.dart

@@ -111,6 +111,13 @@ class Configuration {
     // Create a master key
     final key = CryptoUtil.generateKey();
 
+    // Create a recovery key
+    final recoveryKey = CryptoUtil.generateKey();
+
+    // Encrypt master key and recovery key with each other
+    final encryptedMasterKey = CryptoUtil.encryptSync(key, recoveryKey);
+    final encryptedRecoveryKey = CryptoUtil.encryptSync(recoveryKey, key);
+
     // Derive a key from the password that will be used to encrypt and
     // decrypt the master key
     final kekSalt = CryptoUtil.getSaltToDeriveKey();
@@ -139,9 +146,13 @@ class Configuration {
       Sodium.bin2base64(encryptedSecretKeyData.nonce),
       memLimit,
       opsLimit,
+      Sodium.bin2base64(encryptedMasterKey.encryptedData),
+      Sodium.bin2base64(encryptedMasterKey.nonce),
+      Sodium.bin2base64(encryptedRecoveryKey.encryptedData),
+      Sodium.bin2base64(encryptedRecoveryKey.nonce),
     );
-    final privateAttributes = PrivateKeyAttributes(
-        Sodium.bin2base64(key), Sodium.bin2base64(keyPair.sk));
+    final privateAttributes = PrivateKeyAttributes(Sodium.bin2base64(key),
+        Sodium.bin2hex(recoveryKey), Sodium.bin2base64(keyPair.sk));
     return KeyGenResult(attributes, privateAttributes);
   }
 
@@ -168,17 +179,36 @@ class Configuration {
     // has not changed
     final existingAttributes = getKeyAttributes();
 
-    final attributes = KeyAttributes(
-      Sodium.bin2base64(kekSalt),
-      Sodium.bin2base64(encryptedKeyData.encryptedData),
-      Sodium.bin2base64(encryptedKeyData.nonce),
-      existingAttributes.publicKey,
-      existingAttributes.encryptedSecretKey,
-      existingAttributes.secretKeyDecryptionNonce,
-      memLimit,
-      opsLimit,
-    );
-    return attributes;
+    if (existingAttributes.recoveryKeyEncryptedWithMasterKey == null) {
+      // Create a recovery key
+      final recoveryKey = CryptoUtil.generateKey();
+
+      // Encrypt master key and recovery key with each other
+      final encryptedMasterKey = CryptoUtil.encryptSync(key, recoveryKey);
+      final encryptedRecoveryKey = CryptoUtil.encryptSync(recoveryKey, key);
+      return existingAttributes.copyWith(
+        kekSalt: Sodium.bin2base64(kekSalt),
+        encryptedKey: Sodium.bin2base64(encryptedKeyData.encryptedData),
+        keyDecryptionNonce: Sodium.bin2base64(encryptedKeyData.nonce),
+        memLimit: memLimit,
+        opsLimit: opsLimit,
+        masterKeyEncryptedWithRecoveryKey:
+            Sodium.bin2base64(encryptedMasterKey.encryptedData),
+        masterKeyDecryptionNonce: Sodium.bin2base64(encryptedMasterKey.nonce),
+        recoveryKeyEncryptedWithMasterKey:
+            Sodium.bin2base64(encryptedRecoveryKey.encryptedData),
+        recoveryKeyDecryptionNonce:
+            Sodium.bin2base64(encryptedRecoveryKey.encryptedData),
+      );
+    } else {
+      return existingAttributes.copyWith(
+        kekSalt: Sodium.bin2base64(kekSalt),
+        encryptedKey: Sodium.bin2base64(encryptedKeyData.encryptedData),
+        keyDecryptionNonce: Sodium.bin2base64(encryptedKeyData.nonce),
+        memLimit: memLimit,
+        opsLimit: opsLimit,
+      );
+    }
   }
 
   Future<void> decryptAndSaveKey(

+ 48 - 2
lib/models/key_attributes.dart

@@ -9,6 +9,10 @@ class KeyAttributes {
   final String secretKeyDecryptionNonce;
   final int memLimit;
   final int opsLimit;
+  final String masterKeyEncryptedWithRecoveryKey;
+  final String masterKeyDecryptionNonce;
+  final String recoveryKeyEncryptedWithMasterKey;
+  final String recoveryKeyDecryptionNonce;
 
   KeyAttributes(
     this.kekSalt,
@@ -19,6 +23,10 @@ class KeyAttributes {
     this.secretKeyDecryptionNonce,
     this.memLimit,
     this.opsLimit,
+    this.masterKeyEncryptedWithRecoveryKey,
+    this.masterKeyDecryptionNonce,
+    this.recoveryKeyEncryptedWithMasterKey,
+    this.recoveryKeyDecryptionNonce,
   );
 
   Map<String, dynamic> toMap() {
@@ -31,12 +39,14 @@ class KeyAttributes {
       'secretKeyDecryptionNonce': secretKeyDecryptionNonce,
       'memLimit': memLimit,
       'opsLimit': opsLimit,
+      'masterKeyEncryptedWithRecoveryKey': masterKeyEncryptedWithRecoveryKey,
+      'masterKeyDecryptionNonce': masterKeyDecryptionNonce,
+      'recoveryKeyEncryptedWithMasterKey': recoveryKeyEncryptedWithMasterKey,
+      'recoveryKeyDecryptionNonce': recoveryKeyDecryptionNonce,
     };
   }
 
   factory KeyAttributes.fromMap(Map<String, dynamic> map) {
-    if (map == null) return null;
-
     return KeyAttributes(
       map['kekSalt'],
       map['encryptedKey'],
@@ -46,6 +56,10 @@ class KeyAttributes {
       map['secretKeyDecryptionNonce'],
       map['memLimit'],
       map['opsLimit'],
+      map['masterKeyEncryptedWithRecoveryKey'],
+      map['masterKeyDecryptionNonce'],
+      map['recoveryKeyEncryptedWithMasterKey'],
+      map['recoveryKeyDecryptionNonce'],
     );
   }
 
@@ -53,4 +67,36 @@ class KeyAttributes {
 
   factory KeyAttributes.fromJson(String source) =>
       KeyAttributes.fromMap(json.decode(source));
+
+  KeyAttributes copyWith({
+    String kekSalt,
+    String encryptedKey,
+    String keyDecryptionNonce,
+    String publicKey,
+    String encryptedSecretKey,
+    String secretKeyDecryptionNonce,
+    int memLimit,
+    int opsLimit,
+    String masterKeyEncryptedWithRecoveryKey,
+    String masterKeyDecryptionNonce,
+    String recoveryKeyEncryptedWithMasterKey,
+    String recoveryKeyDecryptionNonce,
+  }) {
+    return KeyAttributes(
+      kekSalt ?? this.kekSalt,
+      encryptedKey ?? this.encryptedKey,
+      keyDecryptionNonce ?? this.keyDecryptionNonce,
+      publicKey ?? this.publicKey,
+      encryptedSecretKey ?? this.encryptedSecretKey,
+      secretKeyDecryptionNonce ?? this.secretKeyDecryptionNonce,
+      memLimit ?? this.memLimit,
+      opsLimit ?? this.opsLimit,
+      masterKeyEncryptedWithRecoveryKey ??
+          this.masterKeyEncryptedWithRecoveryKey,
+      masterKeyDecryptionNonce ?? this.masterKeyDecryptionNonce,
+      recoveryKeyEncryptedWithMasterKey ??
+          this.recoveryKeyEncryptedWithMasterKey,
+      recoveryKeyDecryptionNonce ?? this.recoveryKeyDecryptionNonce,
+    );
+  }
 }

+ 2 - 1
lib/models/private_key_attributes.dart

@@ -1,6 +1,7 @@
 class PrivateKeyAttributes {
   final String key;
+  final String recoveryKey;
   final String secretKey;
 
-  PrivateKeyAttributes(this.key, this.secretKey);
+  PrivateKeyAttributes(this.key, this.recoveryKey, this.secretKey);
 }