Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypt rooms' last messages #1718

Merged
merged 14 commits into from
Feb 21, 2023
9 changes: 9 additions & 0 deletions MatrixSDK/Data/MXRoomLastMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ FOUNDATION_EXPORT NSString *const MXRoomLastMessageDataType;

- (instancetype)initWithEvent:(MXEvent *)event;

/**
Returns an archived (possibly encrypted) version of MXRoomLastMessage sensitive data.
These include:
- `text`
- `attributedText`
- `others`
*/
- (nullable NSData*)sensitiveData;

#pragma mark - CoreData Model

- (instancetype)initWithManagedObject:(MXRoomLastMessageMO *)model;
Expand Down
78 changes: 59 additions & 19 deletions MatrixSDK/Data/MXRoomLastMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#import <Security/Security.h>
#import <CommonCrypto/CommonCryptor.h>
#import <Foundation/Foundation.h>

NSString *const MXRoomLastMessageDataType = @"org.matrix.sdk.keychain.MXRoomLastMessage";

Expand Down Expand Up @@ -58,6 +59,27 @@ - (instancetype)initWithEvent:(MXEvent *)event
return self;
}

- (nullable NSData*)sensitiveData;
{
NSError* error;
NSData* archived = [NSKeyedArchiver archivedDataWithRootObject:[self sensitiveDataDictionary]
requiringSecureCoding:NO
error:&error];

if (error) {
MXLogDebug(@"[MXRoomLastMessage] did fail to archive sensitiveDataDictionary. Error: %@", error.description);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future reference: errors are best logged via MXLogErrorDetails which will also send them to Sentry (if enabled), or even MXLogFailureDetails if we do not expect this error to ever occur

}

if (archived && self.isEncrypted)
{
return [self encrypt:archived];
}
else
{
return archived;
}
}

- (NSComparisonResult)compareOriginServerTs:(MXRoomLastMessage *)otherMessage
{
NSComparisonResult result = NSOrderedAscending;
Expand Down Expand Up @@ -87,16 +109,27 @@ - (instancetype)initWithManagedObject:(MXRoomLastMessageMO *)model
_originServerTs = model.s_originServerTs;
_isEncrypted = model.s_isEncrypted;
_sender = model.s_sender;
_text = model.s_text;
if (model.s_attributedText)

NSData* archivedSensitiveData;
if (model.s_sensitiveData && model.s_isEncrypted)
{
_attributedText = [NSKeyedUnarchiver unarchiveObjectWithData:model.s_attributedText];
archivedSensitiveData = [self decrypt:model.s_sensitiveData];
}
if (model.s_others)
else
{
_others = [NSKeyedUnarchiver unarchiveObjectWithData:model.s_others];
archivedSensitiveData = model.s_sensitiveData;
}

if (archivedSensitiveData)
{
NSDictionary* sensitiveDataDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:archivedSensitiveData];

_text = sensitiveDataDictionary[kCodingKeyText];
_attributedText = sensitiveDataDictionary[kCodingKeyAttributedText];
_others = sensitiveDataDictionary[kCodingKeyOthers];
}
}

return self;
}

Expand Down Expand Up @@ -142,20 +175,7 @@ - (void)encodeWithCoder:(NSCoder *)coder
[coder encodeObject:_sender forKey:kCodingKeySender];

// Build last message sensitive data
NSMutableDictionary *lastMessageDictionary = [NSMutableDictionary dictionary];
if (_text)
{
lastMessageDictionary[kCodingKeyText] = _text;
}
if (_attributedText)
{
lastMessageDictionary[kCodingKeyAttributedText] = _attributedText;
}
if (_others)
{
lastMessageDictionary[kCodingKeyOthers] = _others;
}

NSDictionary *lastMessageDictionary = [self sensitiveDataDictionary];
// And encrypt it if necessary
if (_isEncrypted)
{
Expand All @@ -173,6 +193,26 @@ - (void)encodeWithCoder:(NSCoder *)coder
}
}

- (NSDictionary*)sensitiveDataDictionary
{
NSMutableDictionary *lastMessageDictionary = [NSMutableDictionary dictionary];

if (_text)
{
lastMessageDictionary[kCodingKeyText] = _text;
}
if (_attributedText)
{
lastMessageDictionary[kCodingKeyAttributedText] = _attributedText;
}
if (_others)
{
lastMessageDictionary[kCodingKeyOthers] = _others;
}

return lastMessageDictionary;
}

#pragma mark - Data encryption

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="20086" systemVersion="21E258" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="MXRoomLastMessage" representedClassName="MXRoomLastMessageMO" syncable="YES">
<attribute name="s_attributedText" optional="YES" attributeType="Binary" valueTransformerName=""/>
<attribute name="s_eventId" attributeType="String"/>
<attribute name="s_isEncrypted" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="s_originServerTs" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="s_others" optional="YES" attributeType="Binary"/>
<attribute name="s_sender" attributeType="String"/>
<attribute name="s_text" optional="YES" attributeType="String"/>
<attribute name="s_sensitiveData" optional="YES" attributeType="Binary"/>
<relationship name="s_ofRoom" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MXRoomSummary" inverseName="s_lastMessage" inverseEntity="MXRoomSummary"/>
</entity>
<entity name="MXRoomMembersCount" representedClassName="MXRoomMembersCountMO" syncable="YES">
Expand Down Expand Up @@ -62,10 +60,4 @@
<attribute name="s_usersCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="s_ofRoom" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MXRoomSummary" inverseName="s_trust" inverseEntity="MXRoomSummary"/>
</entity>
<elements>
<element name="MXRoomLastMessage" positionX="117" positionY="90" width="128" height="149"/>
<element name="MXRoomMembersCount" positionX="297.1484375" positionY="-66.14453125" width="128" height="89"/>
<element name="MXRoomSummary" positionX="-63" positionY="-18" width="128" height="509"/>
<element name="MXUsersTrustLevelSummary" positionX="236.4921875" positionY="519.4296875" width="128" height="104"/>
</elements>
pixlwave marked this conversation as resolved.
Show resolved Hide resolved
</model>
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ public class MXRoomLastMessageMO: NSManagedObject {
@NSManaged public var s_originServerTs: UInt64
@NSManaged public var s_isEncrypted: Bool
@NSManaged public var s_sender: String
@NSManaged public var s_text: String?
@NSManaged public var s_attributedText: Data?
@NSManaged public var s_others: Data?
@NSManaged public var s_sensitiveData: Data?

@discardableResult
internal static func insert(roomLastMessage lastMessage: MXRoomLastMessage,
Expand All @@ -47,19 +45,6 @@ public class MXRoomLastMessageMO: NSManagedObject {
s_originServerTs = lastMessage.originServerTs
s_isEncrypted = lastMessage.isEncrypted
s_sender = lastMessage.sender
s_text = lastMessage.text

if let attributedText = lastMessage.attributedText {
s_attributedText = NSKeyedArchiver.archivedData(withRootObject: attributedText)
} else {
s_attributedText = nil
}

if let others = lastMessage.others {
s_others = NSKeyedArchiver.archivedData(withRootObject: others)
} else {
s_others = nil
}
s_sensitiveData = lastMessage.sensitiveData()
}

}
2 changes: 1 addition & 1 deletion MatrixSDK/Data/Store/MXFileStore/MXFileStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#import "MatrixSDKSwiftHeader.h"
#import "MXFileRoomSummaryStore.h"

static NSUInteger const kMXFileVersion = 81;
static NSUInteger const kMXFileVersion = 82;

static NSString *const kMXFileStoreFolder = @"MXFileStore";
static NSString *const kMXFileStoreMedaDataFile = @"MXFileStore";
Expand Down
2 changes: 2 additions & 0 deletions changelog.d/pr-1718.change
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Encryption: add encryption to rooms' last messages.
WARNING: the migration to this database version will cause an initial full sync.