diff --git a/MatrixSDK/Crypto/SecretStorage/MXSecretStorage.m b/MatrixSDK/Crypto/SecretStorage/MXSecretStorage.m index 1f4bfcca6..69b2124d0 100644 --- a/MatrixSDK/Crypto/SecretStorage/MXSecretStorage.m +++ b/MatrixSDK/Crypto/SecretStorage/MXSecretStorage.m @@ -18,12 +18,14 @@ #import "MXSession.h" #import "MXTools.h" +#import "MXKeyBackupPassword.h" #import "MXRecoveryKey.h" #import "MXHkdfSha256.h" #import "MXAesHmacSha2.h" #import "MXBase64Tools.h" #import "MXEncryptedSecretContent.h" +#import #pragma mark - Constants @@ -126,6 +128,112 @@ - (MXHTTPOperation*)createKeyWithKeyId:(nullable NSString*)keyId return operation; } +- (MXHTTPOperation*)createKeyWithKeyId:(nullable NSString*)keyId + keyName:(nullable NSString*)keyName + passphrase:(nullable NSString*)passphrase + success:(void (^)(MXSecretStorageKeyCreationInfo *keyCreationInfo))success + failure:(void (^)(NSError *error))failure +{ + MXLogDebug(@"[MXSecretStorage] createKeyWithKeyId: Creating new key with passphrase"); + keyId = keyId ?: [[NSUUID UUID] UUIDString]; + + MXHTTPOperation *operation = [MXHTTPOperation new]; + + MXWeakify(self); + dispatch_async(processingQueue, ^{ + MXStrongifyAndReturnIfNil(self); + + NSError *error; + + NSData *privateKey; + MXSecretStoragePassphrase *passphraseInfo; + + if (passphrase) + { + // Generate a private key from the passphrase + NSString *salt; + NSUInteger iterations; + privateKey = [MXKeyBackupPassword generatePrivateKeyWithPassword:passphrase + salt:&salt + iterations:&iterations + error:&error]; + if (!error) + { + passphraseInfo = [MXSecretStoragePassphrase new]; + passphraseInfo.algorithm = @"m.pbkdf2"; + passphraseInfo.salt = salt; + passphraseInfo.iterations = iterations; + } + } + else + { + uint8_t randomBytes[32]; + OSStatus status = SecRandomCopyBytes(kSecRandomDefault, sizeof(randomBytes), randomBytes); + + if (status == errSecSuccess) + { + privateKey = [NSData dataWithBytes:randomBytes length:sizeof(randomBytes)]; + } + else + { + MXLogDebug(@"Failed to generate random bytes with error: %d", (int)status); + } + } + + if (error) + { + dispatch_async(dispatch_get_main_queue(), ^{ + MXLogDebug(@"[MXSecretStorage] createKeyWithKeyId: Failed to create a new key - %@", error); + failure(error); + }); + return; + } + + // Build iv and mac + MXEncryptedSecretContent *encryptedZeroString = [self encryptedZeroStringWithPrivateKey:privateKey iv:nil error:&error]; + if (error) + { + dispatch_async(dispatch_get_main_queue(), ^{ + MXLogDebug(@"[MXSecretStorage] createKeyWithKeyId: Failed to create a new key - %@", error); + failure(error); + }); + return; + } + + MXSecretStorageKeyContent *ssssKeyContent = [MXSecretStorageKeyContent new]; + ssssKeyContent.name = keyName; + ssssKeyContent.algorithm = MXSecretStorageKeyAlgorithm.aesHmacSha2; + ssssKeyContent.passphrase = passphraseInfo; + ssssKeyContent.iv = encryptedZeroString.iv; + ssssKeyContent.mac = encryptedZeroString.mac; + + NSString *accountDataId = [self storageKeyIdForKey:keyId]; + MXHTTPOperation *operation2 = [self setAccountData:ssssKeyContent.JSONDictionary forType:accountDataId success:^{ + + MXSecretStorageKeyCreationInfo *keyCreationInfo = [MXSecretStorageKeyCreationInfo new]; + keyCreationInfo.keyId = keyId; + keyCreationInfo.content = ssssKeyContent; + keyCreationInfo.privateKey = privateKey; + keyCreationInfo.recoveryKey = [MXRecoveryKey encode:privateKey]; + + dispatch_async(dispatch_get_main_queue(), ^{ + MXLogDebug(@"[MXSecretStorage] createKeyWithKeyId: Successfully created a new key"); + success(keyCreationInfo); + }); + + } failure:^(NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + MXLogDebug(@"[MXSecretStorage] createKeyWithKeyId: Failed to create a new key - %@", error); + failure(error); + }); + }]; + + [operation mutateTo:operation2]; + }); + + return operation; +} + - (MXHTTPOperation*)deleteKeyWithKeyId:(nullable NSString*)keyId success:(void (^)(void))success failure:(void (^)(NSError *error))failure