Эх сурвалжийг харах

e2ee 1.2

Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
Marino Faggiana 2 жил өмнө
parent
commit
d172de69c3

+ 1 - 1
Brand/Database.swift

@@ -26,4 +26,4 @@ import Foundation
 // Database Realm
 //
 let databaseName                    = "nextcloud.realm"
-let databaseSchemaVersion: UInt64   = 269
+let databaseSchemaVersion: UInt64   = 274

+ 4 - 4
Nextcloud.xcodeproj/project.pbxproj

@@ -3941,7 +3941,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 5;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -4004,7 +4004,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 5;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -4258,8 +4258,8 @@
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			requirement = {
-				branch = develop;
-				kind = branch;
+				kind = exactVersion;
+				version = 2.1.0;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {

+ 43 - 0
iOSClient/Data/NCManageDatabase+E2EE.swift

@@ -37,6 +37,7 @@ class tableE2eEncryption: Object {
     @objc dynamic var key = ""
     @objc dynamic var initializationVector = ""
     @objc dynamic var metadataKey = ""
+    @objc dynamic var metadataKeyFiledrop = ""
     @objc dynamic var metadataKeyIndex: Int = 0
     @objc dynamic var metadataVersion: Double = 0
     @objc dynamic var mimeType = ""
@@ -60,6 +61,14 @@ class tableE2eEncryptionLock: Object {
     }
 }
 
+class tableE2eMetadata: Object {
+
+    @Persisted(primaryKey: true) var serverUrl = ""
+    @Persisted var account = ""
+    @Persisted var metadataKey = ""
+    @Persisted var version: Double = 0
+}
+
 extension NCManageDatabase {
 
     // MARK: -
@@ -215,4 +224,38 @@ extension NCManageDatabase {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
     }
+
+    // MARK: -
+    // MARK: Table e2ee Metadata
+
+    func getE2eMetadata(account: String, serverUrl: String) -> tableE2eMetadata? {
+
+        let realm = try! Realm()
+
+        guard let result = realm.objects(tableE2eMetadata.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else {
+            return nil
+        }
+
+        return tableE2eMetadata.init(value: result)
+    }
+
+    func setE2eMetadata(account: String, serverUrl: String, metadataKey: String, version: Double) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.write {
+                let addObject = tableE2eMetadata()
+
+                addObject.account = account
+                addObject.metadataKey = metadataKey
+                addObject.serverUrl = serverUrl
+                addObject.version = version
+
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
 }

+ 4 - 5
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -1124,15 +1124,14 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                     if let metadataFolder = metadataFolder, metadataFolder.e2eEncrypted, CCUtility.isEnd(toEndEnabled: self.appDelegate.account) {
                         NextcloudKit.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: nil) { account, e2eMetadata, data, error in
                             if error == .success, let e2eMetadata = e2eMetadata {
-                                if NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: self.serverUrl, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, ownerId: metadataFolder.ownerId) {
+                                let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: self.serverUrl, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, ownerId: metadataFolder.ownerId)
+                                if result.error == .success {
                                     self.reloadDataSource()
                                 } else {
-                                    let error = NKError(errorCode: NCGlobal.shared.errorDecodeMetadata, errorDescription: "_e2e_error_decode_metadata_")
-                                    NCContentPresenter.shared.messageNotification("_error_e2ee_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+                                    NCContentPresenter.shared.showError(error: result.error)
                                 }
                             } else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
-                                let error = NKError(errorCode: NCGlobal.shared.errorDecodeMetadata, errorDescription: "_e2e_error_decode_metadata_")
-                                NCContentPresenter.shared.messageNotification("_error_e2ee_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+                                NCContentPresenter.shared.showError(error: NKError(errorCode: NCGlobal.shared.errorDecodeMetadata, errorDescription: "_e2e_error_decode_metadata_"))
                             }
                             completion(tableDirectory, metadatas, metadatasUpdate, metadatasDelete, error)
                         }

+ 1 - 0
iOSClient/NCGlobal.swift

@@ -225,6 +225,7 @@ class NCGlobal: NSObject {
     @objc let errorFileNotSaved: Int                = -99998
     @objc let errorDecodeMetadata: Int              = -99997
     @objc let errorE2EENotEnabled: Int              = -99996
+    @objc let errorE2EE: Int                        = -99995
     @objc let errorOffline: Int                     = -99994
     @objc let errorCharactersForbidden: Int         = -99993
     @objc let errorCreationFile: Int                = -99992

+ 4 - 1
iOSClient/Networking/E2EE/NCEndToEndEncryption.h

@@ -37,12 +37,14 @@
 
 - (NSString *)createCSR:(NSString *)userId directory:(NSString *)directory;
 - (NSString *)encryptPrivateKey:(NSString *)userId directory: (NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey;
-- (NSData *)decryptPrivateKey:(NSString *)privateKeyCipher passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey;
+- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey;
 
 // Encrypt / Decrypt file material
 
 - (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key;
+- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag;
 - (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key;
+- (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString *)initializationVector authenticationTag:(NSString *)authenticationTag;
 
 // Encrypt/Decrypt asymmetric
 
@@ -59,6 +61,7 @@
 - (void)Encodedkey:(NSString **)key initializationVector:(NSString **)initializationVector;
 - (NSData *)generateKey;
 - (NSString *)createSHA512:(NSString *)string;
+- (NSString *)createSHA256:(NSString *)string;
 - (NSString *)extractPublicKeyFromCertificate:(NSString *)pemCertificate;
 
 @end

+ 145 - 85
iOSClient/Networking/E2EE/NCEndToEndEncryption.m

@@ -332,38 +332,38 @@
 
 - (NSString *)encryptPrivateKey:(NSString *)userId directory:(NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey
 {
-    NSMutableData *privateKeyCipherData = [NSMutableData new];
+    NSMutableData *cipher = [NSMutableData new];
 
     if (!_privateKeyData) {
         if (![self generateCertificateX509WithUserId:userId directory:directory])
             return nil;
     }
     
-    NSMutableData *keyData = [NSMutableData dataWithLength:PBKDF2_KEY_LENGTH/8];
-    NSData *saltData = [self generateSalt:AES_SALT_LENGTH];
+    NSMutableData *key = [NSMutableData dataWithLength:PBKDF2_KEY_LENGTH/8];
+    NSData *salt = [self generateSalt:AES_SALT_LENGTH];
     
     // Remove all whitespaces from passphrase
     passphrase = [passphrase stringByReplacingOccurrencesOfString:@" " withString:@""];
     
-    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, saltData.bytes, saltData.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, keyData.mutableBytes, keyData.length);
+    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, key.mutableBytes, key.length);
     
-    NSData *ivData = [self generateIV:AES_IVEC_LENGTH];
-    NSData *tagData = [NSData new];
+    NSData *initializationVector = [self generateIV:AES_IVEC_LENGTH];
+    NSData *authenticationTag = [NSData new];
     
     NSString *pkEncoded = [_privateKeyData base64EncodedStringWithOptions:0];
     NSData *pkEncodedData = [pkEncoded dataUsingEncoding:NSUTF8StringEncoding];
 
-    BOOL result = [self encryptData:pkEncodedData cipherData:&privateKeyCipherData keyData:keyData keyLen:AES_KEY_256_LENGTH ivData:ivData tagData:&tagData];
+    BOOL result = [self encryptData:pkEncodedData cipher:&cipher key:key keyLen:AES_KEY_256_LENGTH initializationVector:initializationVector authenticationTag:&authenticationTag];
     
-    if (result && privateKeyCipherData) {
+    if (result && cipher) {
         
-        NSString *privateKeyCipherBase64 = [privateKeyCipherData base64EncodedStringWithOptions:0];
-        NSString *initVectorBase64 = [ivData base64EncodedStringWithOptions:0];
-        NSString *saltBase64 = [saltData base64EncodedStringWithOptions:0];
-        NSString *privateKeyCipherWithInitVectorBase64 = [NSString stringWithFormat:@"%@%@%@%@%@", privateKeyCipherBase64, IV_DELIMITER_ENCODED, initVectorBase64, IV_DELIMITER_ENCODED, saltBase64];
+        NSString *cipherString = [cipher base64EncodedStringWithOptions:0];
+        NSString *initializationVectorString = [initializationVector base64EncodedStringWithOptions:0];
+        NSString *saltString = [salt base64EncodedStringWithOptions:0];
+        NSString *encryptPrivateKey = [NSString stringWithFormat:@"%@%@%@%@%@", cipherString, IV_DELIMITER_ENCODED, initializationVectorString, IV_DELIMITER_ENCODED, saltString];
         
         *privateKey = [[NSString alloc] initWithData:_privateKeyData encoding:NSUTF8StringEncoding];
-        return privateKeyCipherWithInitVectorBase64;
+        return encryptPrivateKey;
         
     } else {
         
@@ -371,40 +371,40 @@
     }
 }
 
-- (NSData *)decryptPrivateKey:(NSString *)privateKeyCipher passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey
+- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey
 {
-    NSMutableData *privateKeyData = [NSMutableData new];
+    NSMutableData *plain = [NSMutableData new];
 
-    // Key (data)
-    NSMutableData *keyData = [NSMutableData dataWithLength:PBKDF2_KEY_LENGTH/8];
+    // Key
+    NSMutableData *key = [NSMutableData dataWithLength:PBKDF2_KEY_LENGTH/8];
     
     // Split
-    NSArray *privateKeyCipherArray = [privateKeyCipher componentsSeparatedByString:IV_DELIMITER_ENCODED];
-    if (privateKeyCipherArray.count != 3) {
-        privateKeyCipherArray = [privateKeyCipher componentsSeparatedByString:IV_DELIMITER_ENCODED_OLD];
-        if (privateKeyCipherArray.count != 3) {
+    NSArray *cipherArray = [privateKey componentsSeparatedByString:IV_DELIMITER_ENCODED];
+    if (cipherArray.count != 3) {
+        cipherArray = [privateKey componentsSeparatedByString:IV_DELIMITER_ENCODED_OLD];
+        if (cipherArray.count != 3) {
             return nil;
         }
     }
     
-    NSData *privateKeyCipherData = [[NSData alloc] initWithBase64EncodedString:privateKeyCipherArray[0] options:0];
-    NSString *tagBase64 = [privateKeyCipher substringWithRange:NSMakeRange([(NSString *)privateKeyCipherArray[0] length] - AES_GCM_TAG_LENGTH, AES_GCM_TAG_LENGTH)];
-    NSData *tagData = [[NSData alloc] initWithBase64EncodedString:tagBase64 options:0];
-    NSData *ivData = [[NSData alloc] initWithBase64EncodedString:privateKeyCipherArray[1] options:0];
-    NSData *saltData = [[NSData alloc] initWithBase64EncodedString:privateKeyCipherArray[2] options:0];
+    NSData *cipher = [[NSData alloc] initWithBase64EncodedString:cipherArray[0] options:0];
+    NSString *authenticationTagString = [privateKey substringWithRange:NSMakeRange([(NSString *)cipherArray[0] length] - AES_GCM_TAG_LENGTH, AES_GCM_TAG_LENGTH)];
+    NSData *authenticationTag = [[NSData alloc] initWithBase64EncodedString:authenticationTagString options:0];
+    NSData *initializationVector = [[NSData alloc] initWithBase64EncodedString:cipherArray[1] options:0];
+    NSData *salt = [[NSData alloc] initWithBase64EncodedString:cipherArray[2] options:0];
 
-    // Remove TAG
-    privateKeyCipherData = [privateKeyCipherData subdataWithRange:NSMakeRange(0, privateKeyCipherData.length - AES_GCM_TAG_LENGTH)];
+    // Remove Authentication Tag
+    cipher = [cipher subdataWithRange:NSMakeRange(0, cipher.length - AES_GCM_TAG_LENGTH)];
 
     // Remove all whitespaces from passphrase
     passphrase = [passphrase stringByReplacingOccurrencesOfString:@" " withString:@""];
     
-    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, saltData.bytes, saltData.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, keyData.mutableBytes, keyData.length);
+    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, key.mutableBytes, key.length);
     
-    BOOL result = [self decryptData:privateKeyCipherData plainData:&privateKeyData keyData:keyData keyLen:AES_KEY_256_LENGTH ivData:ivData tagData:tagData];
+    BOOL result = [self decryptData:cipher plain:&plain key:key keyLen:AES_KEY_256_LENGTH initializationVector:initializationVector authenticationTag:authenticationTag];
     
-    if (result && privateKeyData) {
-        return privateKeyData;
+    if (result && plain) {
+        return plain;
     }
 
     return nil;
@@ -416,37 +416,64 @@
 
 - (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key
 {
-    NSMutableData *cipherData;
-    NSData *tagData = [NSData new];
-    
-    NSData *data = [encrypted dataUsingEncoding:NSUTF8StringEncoding];
-    NSString *data64 = [data base64EncodedStringWithOptions:0];
-    data = [data64 dataUsingEncoding:NSUTF8StringEncoding];
+    NSMutableData *cipher;
+    NSData *authenticationTag = [NSData new];
+
+    NSData *encryptedData = [encrypted dataUsingEncoding:NSUTF8StringEncoding];
+    encryptedData = [[encryptedData base64EncodedStringWithOptions:0] dataUsingEncoding:NSUTF8StringEncoding];
 
     // Key
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
 
-    // IV
-    NSData *ivData = [self generateIV:AES_IVEC_LENGTH];
+    // Initialization Vector
+    NSData *initializationVector = [self generateIV:AES_IVEC_LENGTH];
     
-    BOOL result = [self encryptData:data cipherData:&cipherData keyData:keyData keyLen:AES_KEY_128_LENGTH ivData:ivData tagData:&tagData];
+    BOOL result = [self encryptData:encryptedData cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVector authenticationTag:&authenticationTag];
     
-    if (cipherData != nil && result) {
+    if (cipher != nil && result) {
         
-        NSString *cipherBase64 = [cipherData base64EncodedStringWithOptions:0];
-        NSString *ivBase64 = [ivData base64EncodedStringWithOptions:0];
-        NSString *encryptedJson = [NSString stringWithFormat:@"%@%@%@", cipherBase64, IV_DELIMITER_ENCODED, ivBase64];
+        NSString *cipherString = [cipher base64EncodedStringWithOptions:0];
+        NSString *initializationVectorString = [initializationVector base64EncodedStringWithOptions:0];
+        NSString *payload = [NSString stringWithFormat:@"%@%@%@", cipherString, IV_DELIMITER_ENCODED, initializationVectorString];
         
-        return encryptedJson;
+        return payload;
     }
     
     return nil;
 }
 
+- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag
+{
+    NSMutableData *cipher;
+    NSData *authenticationTagData = [NSData new];
+
+    NSData *encryptedData = [encrypted dataUsingEncoding:NSUTF8StringEncoding];
+    encryptedData = [[encryptedData base64EncodedStringWithOptions:0] dataUsingEncoding:NSUTF8StringEncoding];
+
+    // Key
+    NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
+
+    // Initialization Vector
+    NSData *initializationVectorData = [self generateIV:AES_IVEC_LENGTH];
+
+    BOOL result = [self encryptData:encryptedData cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:&authenticationTagData];
+
+    if (cipher != nil && result) {
+
+        *initializationVector = [initializationVectorData base64EncodedStringWithOptions:0];
+        *authenticationTag = [authenticationTagData base64EncodedStringWithOptions:0];
+        NSString *payload = [cipher base64EncodedStringWithOptions:0];
+        
+        return payload;
+    }
+
+    return nil;
+}
+
 
 - (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key
 {
-    NSMutableData *plainData;
+    NSMutableData *plain;
     NSRange range = [encrypted rangeOfString:IV_DELIMITER_ENCODED];
     if (range.location == NSNotFound) {
         range = [encrypted rangeOfString:IV_DELIMITER_ENCODED_OLD];
@@ -462,21 +489,42 @@
     // Key
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
 
-    // IV
-    NSString *iv  = [encrypted substringWithRange:NSMakeRange(range.location + range.length, encrypted.length - (range.location + range.length))];
-    NSData *ivData = [[NSData alloc] initWithBase64EncodedString:iv options:0];
+    // Initialization Vector
+    NSString *initializationVector  = [encrypted substringWithRange:NSMakeRange(range.location + range.length, encrypted.length - (range.location + range.length))];
+    NSData *initializationVectorData = [[NSData alloc] initWithBase64EncodedString:initializationVector options:0];
 
-    // TAG
-    NSString *tag = [cipher substringWithRange:NSMakeRange(cipher.length - AES_GCM_TAG_LENGTH, AES_GCM_TAG_LENGTH)];
-    NSData *tagData = [[NSData alloc] initWithBase64EncodedString:tag options:0];
+    // Authentication Tag
+    NSString *authenticationTag = [cipher substringWithRange:NSMakeRange(cipher.length - AES_GCM_TAG_LENGTH, AES_GCM_TAG_LENGTH)];
+    NSData *authenticationTagData = [[NSData alloc] initWithBase64EncodedString:authenticationTag options:0];
 
-    // REMOVE TAG
+    // Remove Authentication Tag
     cipherData = [cipherData subdataWithRange:NSMakeRange(0, cipherData.length - AES_GCM_TAG_LENGTH)];
 
-    BOOL result = [self decryptData:cipherData plainData:&plainData keyData:keyData keyLen:AES_KEY_128_LENGTH ivData:ivData tagData:tagData];
+    BOOL result = [self decryptData:cipherData plain:&plain key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:authenticationTagData];
 
-    if (plainData != nil && result) {
-        return plainData;
+    if (plain != nil && result) {
+        return plain;
+    }
+
+    return nil;
+}
+
+- (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString *)initializationVector authenticationTag:(NSString *)authenticationTag
+{
+    NSMutableData *plain;
+
+    NSData *cipher = [[NSData alloc] initWithBase64EncodedString:encrypted options:0];
+    NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
+    NSData *initializationVectorData = [[NSData alloc] initWithBase64EncodedString:initializationVector options:0];
+    NSData *authenticationTagData = [[NSData alloc] initWithBase64EncodedString:authenticationTag options:0];
+
+    // Remove Authentication Tag
+    cipher = [cipher subdataWithRange:NSMakeRange(0, cipher.length - AES_GCM_TAG_LENGTH)];
+
+    BOOL result = [self decryptData:cipher plain:&plain key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:authenticationTagData];
+
+    if (plain != nil && result) {
+        return plain;
     }
 
     return nil;
@@ -489,24 +537,24 @@
 - (BOOL)encryptFile:(NSString *)fileName fileNameIdentifier:(NSString *)fileNameIdentifier directory:(NSString *)directory key:(NSString **)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag
 {
     NSMutableData *cipherData;
-    NSData *tagData;
+    NSData *authenticationTagData;
    
     NSData *plainData = [[NSFileManager defaultManager] contentsAtPath:[NSString stringWithFormat:@"%@/%@", directory, fileName]];
     if (plainData == nil)
         return false;
     
     NSData *keyData = [self generateKey:AES_KEY_128_LENGTH];
-    NSData *ivData = [self generateIV:AES_IVEC_LENGTH];
+    NSData *initializationVectorData = [self generateIV:AES_IVEC_LENGTH];
     
-    BOOL result = [self encryptData:plainData cipherData:&cipherData keyData:keyData keyLen:AES_KEY_128_LENGTH ivData:ivData tagData:&tagData];
+    BOOL result = [self encryptData:plainData cipher:&cipherData key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:&authenticationTagData];
     
     if (cipherData != nil && result) {
         
         [cipherData writeToFile:[NSString stringWithFormat:@"%@/%@", directory, fileNameIdentifier] atomically:YES];
         
         *key = [keyData base64EncodedStringWithOptions:0];
-        *initializationVector = [ivData base64EncodedStringWithOptions:0];
-        *authenticationTag = [tagData base64EncodedStringWithOptions:0];
+        *initializationVector = [initializationVectorData base64EncodedStringWithOptions:0];
+        *authenticationTag = [authenticationTagData base64EncodedStringWithOptions:0];
 
         if (key == nil || initializationVector == nil || authenticationTag == nil) {
             return false;
@@ -527,10 +575,10 @@
         return false;
     
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
-    NSData *ivData = [[NSData alloc] initWithBase64EncodedString:initializationVector options:0];
-    NSData *tagData = [[NSData alloc] initWithBase64EncodedString:authenticationTag options:0];
+    NSData *initializationVectorData = [[NSData alloc] initWithBase64EncodedString:initializationVector options:0];
+    NSData *authenticationTagData = [[NSData alloc] initWithBase64EncodedString:authenticationTag options:0];
 
-    BOOL result = [self decryptData:cipherData plainData:&plainData keyData:keyData keyLen:AES_KEY_128_LENGTH ivData:ivData tagData:tagData];
+    BOOL result = [self decryptData:cipherData plain:&plainData key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:authenticationTagData];
     if (plainData != nil && result) {
         [plainData writeToFile:[CCUtility getDirectoryProviderStorageOcId:ocId fileNameView:fileNameView] atomically:YES];
         return true;
@@ -670,7 +718,6 @@
         return nil;
 
     NSData *outData = [[NSData alloc] initWithBytes:out length:outLen];
-    //NSString *out64 = [outData base64EncodedStringWithOptions:0];
 
     if (out)
         free(out);
@@ -683,7 +730,7 @@
 #
 
 // Encryption using GCM mode
-- (BOOL)encryptData:(NSData *)plainData cipherData:(NSMutableData **)cipherData keyData:(NSData *)keyData keyLen:(int)keyLen ivData:(NSData *)ivData tagData:(NSData **)tagData
+- (BOOL)encryptData:(NSData *)plain cipher:(NSMutableData **)cipher key:(NSData *)key keyLen:(int)keyLen initializationVector:(NSData *)initializationVector authenticationTag:(NSData **)authenticationTag
 {
     int status = 0;
     int len = 0;
@@ -692,13 +739,13 @@
     len = keyLen;
     unsigned char cKey[len];
     bzero(cKey, sizeof(cKey));
-    [keyData getBytes:cKey length:len];
+    [key getBytes:cKey length:len];
 
     // set up ivec
     len = AES_IVEC_LENGTH;
     unsigned char cIV[len];
     bzero(cIV, sizeof(cIV));
-    [ivData getBytes:cIV length:len];
+    [initializationVector getBytes:cIV length:len];
     
     // set up tag
     len = AES_GCM_TAG_LENGTH;
@@ -730,10 +777,10 @@
         return NO;
     
     // Provide the message to be encrypted, and obtain the encrypted output
-    *cipherData = [NSMutableData dataWithLength:[plainData length]];
-    unsigned char * cCipher = [*cipherData mutableBytes];
+    *cipher = [NSMutableData dataWithLength:[plain length]];
+    unsigned char * cCipher = [*cipher mutableBytes];
     int cCipherLen = 0;
-    status = EVP_EncryptUpdate(ctx, cCipher, &cCipherLen, [plainData bytes], (int)[plainData length]);
+    status = EVP_EncryptUpdate(ctx, cCipher, &cCipherLen, [plain bytes], (int)[plain length]);
     if (status <= 0)
         return NO;
     
@@ -745,10 +792,10 @@
     
     // Get the tag
     status = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, (int)sizeof(cTag), cTag);
-    *tagData = [NSData dataWithBytes:cTag length:sizeof(cTag)];
+    *authenticationTag = [NSData dataWithBytes:cTag length:sizeof(cTag)];
 
     // Append TAG
-    [*cipherData appendData:*tagData];
+    [*cipher appendData:*authenticationTag];
 
     // Free
     EVP_CIPHER_CTX_free(ctx);
@@ -757,7 +804,7 @@
 }
 
 // Decryption using GCM mode
-- (BOOL)decryptData:(NSData *)cipherData plainData:(NSMutableData **)plainData keyData:(NSData *)keyData keyLen:(int)keyLen ivData:(NSData *)ivData tagData:(NSData *)tagData
+- (BOOL)decryptData:(NSData *)cipher plain:(NSMutableData **)plain key:(NSData *)key keyLen:(int)keyLen initializationVector:(NSData *)initializationVector authenticationTag:(NSData *)authenticationTag
 {    
     int status = 0;
     int len = 0;
@@ -766,19 +813,19 @@
     len = keyLen;
     unsigned char cKey[len];
     bzero(cKey, sizeof(cKey));
-    [keyData getBytes:cKey length:len];
+    [key getBytes:cKey length:len];
     
     // set up ivec
-    len = (int)[ivData length];
+    len = (int)[initializationVector length];
     unsigned char cIV[len];
     bzero(cIV, sizeof(cIV));
-    [ivData getBytes:cIV length:len];
+    [initializationVector getBytes:cIV length:len];
    
     // set up tag
-    len = (int)[tagData length];;
+    len = (int)[authenticationTag length];;
     unsigned char cTag[len];
     bzero(cTag, sizeof(cTag));
-    [tagData getBytes:cTag length:len];
+    [authenticationTag getBytes:cTag length:len];
 
     // Create and initialise the context
     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
@@ -805,10 +852,10 @@
         return NO;
     
     // Provide the message to be decrypted, and obtain the plaintext output
-    *plainData = [NSMutableData dataWithLength:([cipherData length])];
+    *plain = [NSMutableData dataWithLength:([cipher length])];
     int cPlainLen = 0;
-    unsigned char * cPlain = [*plainData mutableBytes];
-    status = EVP_DecryptUpdate(ctx, cPlain, &cPlainLen, [cipherData bytes], (int)([cipherData length]));
+    unsigned char * cPlain = [*plain mutableBytes];
+    status = EVP_DecryptUpdate(ctx, cPlain, &cPlainLen, [cipher bytes], (int)([cipher length]));
     if (status <= 0)
         return NO;
     
@@ -819,7 +866,7 @@
     
     // Finalise the encryption
     EVP_DecryptFinal_ex(ctx,NULL, &cPlainLen);
-    
+
     // Free
     EVP_CIPHER_CTX_free(ctx);
     
@@ -839,6 +886,19 @@
     *initializationVector = [ivData base64EncodedStringWithOptions:0];
 }
 
+- (NSString *)createSHA256:(NSString *)string
+{
+    const char *cstr = [string cStringUsingEncoding:NSASCIIStringEncoding];
+    NSData *data = [NSData dataWithBytes:cstr length:string.length];
+    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
+    CC_SHA256(data.bytes, (unsigned int)data.length, digest);
+    NSMutableString* output = [NSMutableString  stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
+
+    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++)
+        [output appendFormat:@"%02x", digest[i]];
+    return output;
+}
+
 - (NSString *)createSHA512:(NSString *)string
 {
     const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
@@ -846,7 +906,7 @@
     uint8_t digest[CC_SHA512_DIGEST_LENGTH];
     CC_SHA512(data.bytes, (unsigned int)data.length, digest);
     NSMutableString* output = [NSMutableString  stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
-    
+
     for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++)
         [output appendFormat:@"%02x", digest[i]];
     return output;

+ 114 - 72
iOSClient/Networking/E2EE/NCEndToEndMetadata.swift

@@ -55,6 +55,7 @@ class NCEndToEndMetadata: NSObject {
         struct Metadata: Codable {
             let metadataKey: String
             let version: Double
+            let checksum: String?
         }
 
         struct Encrypted: Codable {
@@ -73,6 +74,9 @@ class NCEndToEndMetadata: NSObject {
             let initializationVector: String
             let authenticationTag: String?
             let encrypted: String
+            let encryptedKey: String?
+            let encryptedTag: String?
+            let encryptedInitializationVector: String?
         }
 
         let metadata: Metadata
@@ -94,17 +98,30 @@ class NCEndToEndMetadata: NSObject {
         var filedrop: [String: E2eeV12.Filedrop] = [:]
         var filedropCodable: [String: E2eeV12.Filedrop]?
         let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var fileNameIdentifiers: [String] = []
 
-        for item in items {
+        // let shortVersion: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
+        // var filesCodable: [String: E2eeV12.Files] = [String: E2eeV12.Files]()
+        // var filedropCodable: [String: E2eeV12.Filedrop] = [String: E2eeV12.Filedrop]()
 
-            //
-            // metadata
-            //
-            if let metadatakey = (item.metadataKey.data(using: .utf8)?.base64EncodedString()),
-               let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(metadatakey, publicKey: nil, privateKey: privateKey) {
+        //
+        // metadata
+        //
+        if items.isEmpty, let key = NCEndToEndEncryption.sharedManager()?.generateKey() as? NSData {
+
+            if let key = key.base64EncodedString().data(using: .utf8)?.base64EncodedString(),
+               let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(key, publicKey: nil, privateKey: privateKey) {
                 metadataKey = metadataKeyEncrypted.base64EncodedString()
             }
 
+        } else if let metadatakey = (items.first!.metadataKey.data(using: .utf8)?.base64EncodedString()),
+                  let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(metadatakey, publicKey: nil, privateKey: privateKey) {
+
+            metadataKey = metadataKeyEncrypted.base64EncodedString()
+        }
+
+        for item in items {
+
             //
             // files
             //
@@ -113,11 +130,11 @@ class NCEndToEndMetadata: NSObject {
                 do {
                     // Create "encrypted"
                     let json = try encoder.encode(encrypted)
-                    let encryptedString = String(data: json, encoding: .utf8)
-                    if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(encryptedString, key: item.metadataKey) {
+                    if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(String(data: json, encoding: .utf8), key: item.metadataKey) {
                         let record = E2eeV12.Files(initializationVector: item.initializationVector, authenticationTag: item.authenticationTag, encrypted: encrypted)
                         files.updateValue(record, forKey: item.fileNameIdentifier)
                     }
+                    fileNameIdentifiers.append(item.fileNameIdentifier)
                 } catch let error {
                     print("Serious internal error in encoding metadata (" + error.localizedDescription + ")")
                     return nil
@@ -128,14 +145,21 @@ class NCEndToEndMetadata: NSObject {
             // filedrop
             //
             if item.blob == "filedrop" {
+
+                var encryptedKey: String?
+                var encryptedInitializationVector: NSString?
+                var encryptedTag: NSString?
+
+                if let metadataKeyFiledrop = (item.metadataKeyFiledrop.data(using: .utf8)?.base64EncodedString()),
+                   let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(metadataKeyFiledrop, publicKey: nil, privateKey: privateKey) {
+                    encryptedKey = metadataKeyEncrypted.base64EncodedString()
+                }
                 let encrypted = E2eeV12.Encrypted(key: item.key, filename: item.fileName, mimetype: item.mimeType)
                 do {
                     // Create "encrypted"
                     let json = try encoder.encode(encrypted)
-                    let encryptedString = (json.base64EncodedString())
-                    if let encryptedData = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(encryptedString, publicKey: nil, privateKey: privateKey) {
-                        let encrypted = encryptedData.base64EncodedString()
-                        let record = E2eeV12.Filedrop(initializationVector: item.initializationVector, authenticationTag: item.authenticationTag, encrypted: encrypted)
+                    if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(String(data: json, encoding: .utf8), key: item.metadataKeyFiledrop, initializationVector: &encryptedInitializationVector, authenticationTag: &encryptedTag) {
+                        let record = E2eeV12.Filedrop(initializationVector: item.initializationVector, authenticationTag: item.authenticationTag, encrypted: encrypted, encryptedKey: encryptedKey, encryptedTag: encryptedTag as? String, encryptedInitializationVector: encryptedInitializationVector as? String)
                         filedrop.updateValue(record, forKey: item.fileNameIdentifier)
                     }
                 } catch let error {
@@ -145,8 +169,12 @@ class NCEndToEndMetadata: NSObject {
             }
         }
 
+        // Create checksum
+        let passphrase = CCUtility.getEndToEndPassphrase(account).replacingOccurrences(of: " ", with: "")
+        let checksum = NCEndToEndEncryption.sharedManager().createSHA256(passphrase + fileNameIdentifiers.sorted().joined() + metadataKey)
+
         // Create Json
-        let metadata = E2eeV12.Metadata(metadataKey: metadataKey, version: metadataVersion)
+        let metadata = E2eeV12.Metadata(metadataKey: metadataKey, version: metadataVersion, checksum: checksum)
         if !files.isEmpty { filesCodable = files }
         if !filedrop.isEmpty { filedropCodable = filedrop }
         let e2ee = E2eeV12(metadata: metadata, files: filesCodable, filedrop: filedropCodable)
@@ -154,6 +182,10 @@ class NCEndToEndMetadata: NSObject {
             let data = try encoder.encode(e2ee)
             data.printJson()
             let jsonString = String(data: data, encoding: .utf8)
+            // Updated metadata to 1.2
+            if NCManageDatabase.shared.getE2eMetadata(account: account, serverUrl: serverUrl) == nil {
+                NCManageDatabase.shared.setE2eMetadata(account: account, serverUrl: serverUrl, metadataKey: metadataKey, version: metadataVersion)
+            }
             return jsonString
         } catch let error {
             print("Serious internal error in encoding e2ee (" + error.localizedDescription + ")")
@@ -165,8 +197,10 @@ class NCEndToEndMetadata: NSObject {
     // MARK: Decode JSON Metadata Bridge
     // --------------------------------------------------------------------------------------------
 
-    func decoderMetadata(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String, ownerId: String?) -> Bool {
-        guard let data = json.data(using: .utf8) else { return false }
+    func decoderMetadata(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String, ownerId: String?) -> (version: Double, metadataKey: String, error: NKError) {
+        guard let data = json.data(using: .utf8) else {
+            return (0, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decoding JSON"))
+        }
 
         let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) ?? ""
         data.printJson()
@@ -178,21 +212,22 @@ class NCEndToEndMetadata: NSObject {
         } else if (try? decoder.decode(E2eeV12.self, from: data)) != nil {
             return decoderMetadataV12(json, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: ownerId)
         } else {
-            let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Server E2EE version " + versionE2EE + ", not compatible")
-            NCContentPresenter.shared.showError(error: error)
-            return false
+            return (0, "", NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Server E2EE version " + versionE2EE + ", not compatible"))
         }
     }
 
     // --------------------------------------------------------------------------------------------
-    // MARK: Decode JSON Metadata V1
+    // MARK: Decode JSON Metadata V1.1
     // --------------------------------------------------------------------------------------------
 
-    func decoderMetadataV1(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String) -> Bool {
-        guard let data = json.data(using: .utf8) else { return false }
+    func decoderMetadataV1(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String) -> (version: Double, metadataKey: String, error: NKError) {
+        guard let data = json.data(using: .utf8) else {
+            return (0, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decoding JSON"))
+        }
 
         let decoder = JSONDecoder()
         let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var metadataVersion: Double = 0
 
         do {
             let json = try decoder.decode(E2eeV1.self, from: data)
@@ -200,7 +235,11 @@ class NCEndToEndMetadata: NSObject {
             let metadata = json.metadata
             let files = json.files
             var metadataKeys: [String: String] = [:]
-            let metadataVersion = metadata.version
+
+            metadataVersion = metadata.version
+
+            // DATA
+            NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
 
             //
             // metadata
@@ -214,6 +253,15 @@ class NCEndToEndMetadata: NSObject {
                 }
             }
 
+            //
+            // verify version
+            //
+            if let tableE2eMetadata = NCManageDatabase.shared.getE2eMetadata(account: account, serverUrl: serverUrl) {
+                if tableE2eMetadata.version > metadataVersion {
+                    return (metadataVersion, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error verify version \(tableE2eMetadata.version)"))
+                }
+            }
+
             //
             // files
             //
@@ -251,10 +299,6 @@ class NCEndToEndMetadata: NSObject {
                                 object.mimeType = encrypted.mimetype
                                 object.serverUrl = serverUrl
 
-                                // If exists remove records
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNamePath == %@", object.account, object.fileNamePath))
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNameIdentifier == %@", object.account, object.fileNameIdentifier))
-
                                 // Write file parameter for decrypted on DB
                                 NCManageDatabase.shared.addE2eEncryption(object)
 
@@ -271,29 +315,31 @@ class NCEndToEndMetadata: NSObject {
                             }
 
                         } catch let error {
-                            print("Serious internal error in decoding files (" + error.localizedDescription + ")")
-                            return false
+                            return (metadataVersion, metadataKey, NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decrypt file: " + error.localizedDescription))
                         }
                     }
                 }
             }
         } catch let error {
-            print("Serious internal error in decoding metadata (" + error.localizedDescription + ")")
-            return false
+            return (metadataVersion, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: error.localizedDescription))
         }
 
-        return true
+        return (metadataVersion, "", NKError())
     }
 
     // --------------------------------------------------------------------------------------------
-    // MARK: Decode JSON Metadata V12
+    // MARK: Decode JSON Metadata V1.2
     // --------------------------------------------------------------------------------------------
 
-    func decoderMetadataV12(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String, ownerId: String?) -> Bool {
-        guard let data = json.data(using: .utf8) else { return false }
+    func decoderMetadataV12(_ json: String, serverUrl: String, account: String, urlBase: String, userId: String, ownerId: String?) -> (version: Double, metadataKey: String, error: NKError) {
+        guard let data = json.data(using: .utf8) else {
+            return (0, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decoding JSON"))
+        }
 
         let decoder = JSONDecoder()
         let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var metadataVersion: Double = 0
+        var metadataKey = ""
 
         do {
             let json = try decoder.decode(E2eeV12.self, from: data)
@@ -301,8 +347,9 @@ class NCEndToEndMetadata: NSObject {
             let metadata = json.metadata
             let files = json.files
             let filedrop = json.filedrop
-            var metadataKey = ""
-            let metadataVersion = metadata.version
+            var fileNameIdentifiers: [String] = []
+
+            metadataVersion = metadata.version
 
             //
             // metadata
@@ -313,22 +360,25 @@ class NCEndToEndMetadata: NSObject {
                 let key = String(data: keyData, encoding: .utf8) {
                 metadataKey = key
             } else {
-                print("Serious internal error in decoding metadataKey")
-                return false
+                return (metadataVersion, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decrypt metadataKey"))
             }
 
+            // DATA
+            NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+
             //
             // files
             //
             if let files = files {
-                for files in files {
-                    let fileNameIdentifier = files.key
-                    let files = files.value as E2eeV12.Files
-
+                for file in files {
+                    let fileNameIdentifier = file.key
+                    let files = file.value as E2eeV12.Files
                     let encrypted = files.encrypted
                     let authenticationTag = files.authenticationTag
                     let initializationVector = files.initializationVector
 
+                    fileNameIdentifiers.append(fileNameIdentifier)
+
                     if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(encrypted, key: metadataKey),
                        let decryptedData = Data(base64Encoded: decrypted) {
                         do {
@@ -352,10 +402,6 @@ class NCEndToEndMetadata: NSObject {
                                 object.mimeType = encrypted.mimetype
                                 object.serverUrl = serverUrl
 
-                                // If exists remove records
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNamePath == %@", object.account, object.fileNamePath))
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNameIdentifier == %@", object.account, object.fileNameIdentifier))
-
                                 // Write file parameter for decrypted on DB
                                 NCManageDatabase.shared.addE2eEncryption(object)
 
@@ -372,8 +418,7 @@ class NCEndToEndMetadata: NSObject {
                             }
 
                         } catch let error {
-                            print("Serious internal error in decoding files (" + error.localizedDescription + ")")
-                            return false
+                            return (metadataVersion, metadataKey, NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decrypt file: " + error.localizedDescription))
                         }
                     }
                 }
@@ -386,23 +431,19 @@ class NCEndToEndMetadata: NSObject {
                 for filedrop in filedrop {
                     let fileNameIdentifier = filedrop.key
                     let filedrop = filedrop.value as E2eeV12.Filedrop
+                    var metadataKeyFiledrop: String?
 
-                    let encrypted = filedrop.encrypted
-                    let authenticationTag = filedrop.authenticationTag
-                    let initializationVector = filedrop.initializationVector
-
-                    /*
-                    if let encryptedData = NSData(base64Encoded: encrypted, options: NSData.Base64DecodingOptions(rawValue: 0)),
-                       let encryptedBase64 = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(encryptedData as Data?, privateKey: privateKey),
-                       let encryptedBase64Data = Data(base64Encoded: encryptedBase64, options: NSData.Base64DecodingOptions(rawValue: 0)),
-                       let encrypted = String(data: encryptedBase64Data, encoding: .utf8),
-                       let encryptedData = encrypted.data(using: .utf8) {
-                     */
+                    if let encryptedKey = filedrop.encryptedKey,
+                       let data = Data(base64Encoded: encryptedKey),
+                       let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey) {
+                        let keyData = Data(base64Encoded: decrypted)
+                        metadataKeyFiledrop = String(data: keyData!, encoding: .utf8)
+                    }
 
-                    let data = Data(base64Encoded: encrypted)
-                    if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey),
+                    if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(filedrop.encrypted, key: metadataKeyFiledrop, initializationVector: filedrop.encryptedInitializationVector, authenticationTag: filedrop.encryptedTag),
                        let decryptedData = Data(base64Encoded: decrypted) {
                         do {
+                            decryptedData.printJson()
                             let encrypted = try decoder.decode(E2eeV1.Encrypted.self, from: decryptedData)
 
                             if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
@@ -410,22 +451,19 @@ class NCEndToEndMetadata: NSObject {
                                 let object = tableE2eEncryption()
 
                                 object.account = account
-                                object.authenticationTag = authenticationTag ?? ""
+                                object.authenticationTag = filedrop.authenticationTag ?? ""
                                 object.blob = "filedrop"
                                 object.fileName = encrypted.filename
                                 object.fileNameIdentifier = fileNameIdentifier
                                 object.fileNamePath = CCUtility.returnFileNamePath(fromFileName: encrypted.filename, serverUrl: serverUrl, urlBase: urlBase, userId: userId, account: account)
                                 object.key = encrypted.key
-                                object.initializationVector = initializationVector
+                                object.metadataKeyFiledrop = metadataKeyFiledrop ?? ""
+                                object.initializationVector = filedrop.initializationVector
                                 object.metadataKey = metadataKey
                                 object.metadataVersion = metadataVersion
                                 object.mimeType = encrypted.mimetype
                                 object.serverUrl = serverUrl
 
-                                // If exists remove records
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNamePath == %@", object.account, object.fileNamePath))
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNameIdentifier == %@", object.account, object.fileNameIdentifier))
-
                                 // Write file parameter for decrypted on DB
                                 NCManageDatabase.shared.addE2eEncryption(object)
 
@@ -442,18 +480,22 @@ class NCEndToEndMetadata: NSObject {
                             }
 
                         } catch let error {
-                            print("Serious internal error in decoding filedrop (" + error.localizedDescription + ")")
-                            return false
+                            return (metadataVersion, metadataKey, NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decrypt filedrop: " + error.localizedDescription))
                         }
                     }
                 }
             }
 
+            // verify checksum
+            let passphrase = CCUtility.getEndToEndPassphrase(account).replacingOccurrences(of: " ", with: "")
+            let checksum = NCEndToEndEncryption.sharedManager().createSHA256(passphrase + fileNameIdentifiers.sorted().joined() + metadata.metadataKey)
+            if metadata.checksum != checksum {
+                return (metadataVersion, metadataKey, NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error checksum"))
+            }
         } catch let error {
-            print("Serious internal error in decoding metadata (" + error.localizedDescription + ")")
-            return false
+            return (metadataVersion, metadataKey, NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: error.localizedDescription))
         }
 
-        return true
+        return (metadataVersion, metadataKey, NKError())
     }
 }

+ 38 - 3
iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift

@@ -41,6 +41,7 @@ class NCNetworkingE2EECreateFolder: NSObject {
         let serverUrlFileName = serverUrl + "/" + fileName
         var error = NKError()
 
+        // CREATE FOLDER
         let createFolderResults = await NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName)
         if createFolderResults.error != .success { return createFolderResults.error }
 
@@ -48,6 +49,7 @@ class NCNetworkingE2EECreateFolder: NSObject {
         error = readFileOrFolderResults.error
         if error == .success, let file = readFileOrFolderResults.files.first {
 
+            // MARK AS E2EE
             let markE2EEFolderResults = await NextcloudKit.shared.markE2EEFolder(fileId: file.fileId, delete: false)
             if markE2EEFolderResults.error != .success { return markE2EEFolderResults.error }
 
@@ -59,6 +61,17 @@ class NCNetworkingE2EECreateFolder: NSObject {
             NCManageDatabase.shared.addDirectory(encrypted: true, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrlFileName, account: metadata.account)
             NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, serverUrlFileName))
 
+            // LOCK
+            let lockResults = await NCNetworkingE2EE.shared.lock(account: account, serverUrl: serverUrlFileName)
+            if lockResults.error != .success { return lockResults.error }
+
+            let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: account, serverUrl: serverUrlFileName)
+            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: file.fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadataNew, method: "POST")
+            error = putE2EEMetadataResults.error
+
+            // UNLOCK
+            await NCNetworkingE2EE.shared.unlock(account: account, serverUrl: serverUrlFileName)
+
             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": serverUrl])
         }
 
@@ -120,9 +133,8 @@ class NCNetworkingE2EECreateFolder: NSObject {
         // Get last metadata
         let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken)
         if getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata {
-            if !NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: nil) {
-                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
-            }
+            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: nil)
+            if result.error != .success { return result.error }
             method = "PUT"
         }
 
@@ -155,4 +167,27 @@ class NCNetworkingE2EECreateFolder: NSObject {
         let putE2EEMetadataResults =  await NextcloudKit.shared.putE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, method: method)
         return putE2EEMetadataResults.error
     }
+
+    func markE2EEFolder(account: String, serverUrl: String, fileId: String, ocId: String) async -> (NKError) {
+
+        let markE2EEFolderResult = await NextcloudKit.shared.markE2EEFolder(fileId: fileId, delete: false)
+        if markE2EEFolderResult.error != .success { return markE2EEFolderResult.error }
+
+        NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+        NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: true, richWorkspace: nil, account: account)
+        NCManageDatabase.shared.setMetadataEncrypted(ocId: ocId, encrypted: true)
+
+        // LOCK
+        let lockResults = await NCNetworkingE2EE.shared.lock(account: account, serverUrl: serverUrl)
+        if lockResults.error != .success { return lockResults.error }
+
+        let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: account, serverUrl: serverUrl)
+        let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadataNew, method: "POST")
+        let error = putE2EEMetadataResults.error
+
+        // UNLOCK
+        await NCNetworkingE2EE.shared.unlock(account: account, serverUrl: serverUrl)
+
+        return error
+    }
 }

+ 8 - 5
iOSClient/Networking/E2EE/NCNetworkingE2EEDelete.swift

@@ -43,14 +43,17 @@ class NCNetworkingE2EEDelete: NSObject {
         func sendE2EMetadata(e2eToken: String, fileId: String) async -> (NKError) {
 
             var e2eMetadataNew: String?
-            var method = "PUT"
 
             // Get last metadata
             let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
-            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata, NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId) else {
-                    return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
+
+            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata else {
+                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
             }
 
+            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if result.error != .success { return result.error }
+
             // delete
             NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", metadata.account, metadata.serverUrl, metadata.fileName))
 
@@ -58,11 +61,11 @@ class NCNetworkingE2EEDelete: NSObject {
             if let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) {
                 e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl)
             } else {
-                method = "DELETE"
+                e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: metadata.account, serverUrl: metadata.serverUrl)
             }
 
             // Send metadata
-            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, method: method)
+            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, method: "PUT")
             
             return putE2EEMetadataResults.error
         }

+ 4 - 1
iOSClient/Networking/E2EE/NCNetworkingE2EERename.swift

@@ -44,10 +44,13 @@ class NCNetworkingE2EERename: NSObject {
 
             // Get last metadata
             let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
-            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata, NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId) else {
+            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata else {
                 return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
             }
 
+            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if result.error != .success { return result.error }
+
             // rename
             NCManageDatabase.shared.renameFileE2eEncryption(serverUrl: metadata.serverUrl, fileNameIdentifier: metadata.fileName, newFileName: fileNameNew, newFileNamePath: CCUtility.returnFileNamePath(fromFileName: fileNameNew, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId, account: metadata.account))
 

+ 4 - 4
iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift

@@ -146,9 +146,8 @@ class NCNetworkingE2EEUpload: NSObject {
         // Get last metadata
         let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
         if getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata {
-            if !NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId) {
-                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
-            }
+            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if result.error != .success { return result.error }
             method = "PUT"
         }
 
@@ -176,7 +175,8 @@ class NCNetworkingE2EEUpload: NSObject {
         NCManageDatabase.shared.addE2eEncryption(objectE2eEncryption)
 
         // Rebuild metadata
-        guard let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)), let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl) else {
+        guard let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)),
+              let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl) else {
             return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
         }