161 lines
5.0 KiB
Objective-C
161 lines
5.0 KiB
Objective-C
//
|
|
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "SSKPreKeyStore.h"
|
|
#import "AxolotlExceptions.h"
|
|
#import "PreKeyRecord.h"
|
|
#import "SDSKeyValueStore+ObjC.h"
|
|
#import "TSStorageKeys.h"
|
|
#import <SignalCoreKit/Cryptography.h>
|
|
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
|
|
|
#define BATCH_SIZE 100
|
|
|
|
static const int kPreKeyOfLastResortId = 0xFFFFFF;
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
NSString *const TSStorageInternalSettingsCollection = @"TSStorageInternalSettingsCollection";
|
|
NSString *const TSNextPrekeyIdKey = @"TSStorageInternalSettingsNextPreKeyId";
|
|
|
|
#pragma mark - Private Extension
|
|
|
|
@interface SDSKeyValueStore (SSKPreKeyStore)
|
|
|
|
- (nullable PreKeyRecord *)preKeyRecordForKey:(NSString *)key transaction:(SDSAnyReadTransaction *)transaction;
|
|
- (void)setPreKeyRecord:(PreKeyRecord *)record forKey:(NSString *)key transaction:(SDSAnyWriteTransaction *)transaction;
|
|
|
|
@end
|
|
|
|
@implementation SDSKeyValueStore (SSKPreKeyStore)
|
|
|
|
- (nullable PreKeyRecord *)preKeyRecordForKey:(NSString *)key transaction:(SDSAnyReadTransaction *)transaction
|
|
{
|
|
return [self.asObjC objectForKey:key ofExpectedType:PreKeyRecord.class transaction:transaction];
|
|
}
|
|
|
|
- (void)setPreKeyRecord:(PreKeyRecord *)record forKey:(NSString *)key transaction:(SDSAnyWriteTransaction *)transaction
|
|
{
|
|
[self.asObjC setObject:record ofExpectedType:PreKeyRecord.class forKey:key transaction:transaction];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - SSKPreKeyStore
|
|
|
|
@interface SSKPreKeyStore ()
|
|
|
|
@property (nonatomic, readonly) SDSKeyValueStore *metadataStore;
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@implementation SSKPreKeyStore
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (!self) {
|
|
return self;
|
|
}
|
|
|
|
_keyStore = [[SDSKeyValueStore alloc] initWithCollection:@"TSStorageManagerPreKeyStoreCollection"];
|
|
_metadataStore = [[SDSKeyValueStore alloc] initWithCollection:TSStorageInternalSettingsCollection];
|
|
|
|
return self;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (NSArray<PreKeyRecord *> *)generatePreKeyRecords
|
|
{
|
|
NSMutableArray *preKeyRecords = [NSMutableArray array];
|
|
|
|
@synchronized(self) {
|
|
int preKeyId = (int)[self nextPreKeyId];
|
|
|
|
OWSLogInfo(@"building %d new preKeys starting from preKeyId: %d", BATCH_SIZE, preKeyId);
|
|
for (int i = 0; i < BATCH_SIZE; i++) {
|
|
ECKeyPair *keyPair = [Curve25519 generateKeyPair];
|
|
PreKeyRecord *record = [[PreKeyRecord alloc] initWithId:preKeyId
|
|
keyPair:keyPair
|
|
createdAt:[NSDate date]];
|
|
|
|
[preKeyRecords addObject:record];
|
|
preKeyId++;
|
|
}
|
|
|
|
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
|
|
[self.metadataStore setInt:preKeyId key:TSNextPrekeyIdKey transaction:transaction];
|
|
});
|
|
}
|
|
return preKeyRecords;
|
|
}
|
|
|
|
- (void)storePreKeyRecords:(NSArray<PreKeyRecord *> *)preKeyRecords
|
|
{
|
|
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
|
|
for (PreKeyRecord *record in preKeyRecords) {
|
|
[self.keyStore setPreKeyRecord:record
|
|
forKey:[SDSKeyValueStore keyWithInt:record.Id]
|
|
transaction:transaction];
|
|
}
|
|
});
|
|
}
|
|
|
|
- (nullable PreKeyRecord *)loadPreKey:(int)preKeyId
|
|
transaction:(SDSAnyReadTransaction *)transaction
|
|
{
|
|
return [self.keyStore preKeyRecordForKey:[SDSKeyValueStore keyWithInt:preKeyId] transaction:transaction];
|
|
}
|
|
|
|
- (void)storePreKey:(int)preKeyId preKeyRecord:(PreKeyRecord *)record
|
|
transaction:(SDSAnyWriteTransaction *)transaction
|
|
{
|
|
[self.keyStore setPreKeyRecord:record forKey:[SDSKeyValueStore keyWithInt:preKeyId] transaction:transaction];
|
|
}
|
|
|
|
- (void)removePreKey:(int)preKeyId
|
|
transaction:(SDSAnyWriteTransaction *)transaction
|
|
{
|
|
OWSLogInfo(@"Removing prekeyID: %lu", (unsigned long)preKeyId);
|
|
|
|
[self.keyStore removeValueForKey:[SDSKeyValueStore keyWithInt:preKeyId] transaction:transaction];
|
|
}
|
|
|
|
- (NSInteger)nextPreKeyId
|
|
{
|
|
__block NSInteger lastPreKeyId;
|
|
[self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) {
|
|
lastPreKeyId = [self.metadataStore getInt:TSNextPrekeyIdKey defaultValue:0 transaction:transaction];
|
|
}];
|
|
|
|
if (lastPreKeyId < 1) {
|
|
// One-time prekey ids must be > 0 and < kPreKeyOfLastResortId.
|
|
lastPreKeyId = 1 + arc4random_uniform(kPreKeyOfLastResortId - (BATCH_SIZE + 1));
|
|
} else if (lastPreKeyId > kPreKeyOfLastResortId - BATCH_SIZE) {
|
|
// We want to "overflow" to 1 when we reach the "prekey of last resort" id
|
|
// to avoid biasing towards higher values.
|
|
lastPreKeyId = 1;
|
|
}
|
|
OWSAssertDebug(lastPreKeyId > 0 && lastPreKeyId < kPreKeyOfLastResortId);
|
|
|
|
return lastPreKeyId;
|
|
}
|
|
|
|
#if TESTABLE_BUILD
|
|
- (void)removeAll:(SDSAnyWriteTransaction *)transaction
|
|
{
|
|
OWSLogWarn(@"");
|
|
|
|
[self.keyStore removeAllWithTransaction:transaction];
|
|
[self.metadataStore removeAllWithTransaction:transaction];
|
|
}
|
|
#endif
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|