2020-12-14 22:05:57 +00:00
//
// C o p y r i g h t 2 0 2 0 N e w V e c t o r L t d
//
// L i c e n s e d u n d e r t h e A p a c h e L i c e n s e , V e r s i o n 2 . 0 ( t h e " L i c e n s e " ) ;
// y o u m a y n o t u s e t h i s f i l e e x c e p t i n c o m p l i a n c e w i t h t h e L i c e n s e .
// Y o u m a y o b t a i n a c o p y o f t h e L i c e n s e a t
//
// h t t p : / / w w w . a p a c h e . o r g / l i c e n s e s / L I C E N S E - 2 . 0
//
// U n l e s s r e q u i r e d b y a p p l i c a b l e l a w o r a g r e e d t o i n w r i t i n g , s o f t w a r e
// d i s t r i b u t e d u n d e r t h e L i c e n s e i s d i s t r i b u t e d o n a n " A S I S " B A S I S ,
// W I T H O U T W A R R A N T I E S O R C O N D I T I O N S O F A N Y K I N D , e i t h e r e x p r e s s o r i m p l i e d .
// S e e t h e L i c e n s e f o r t h e s p e c i f i c l a n g u a g e g o v e r n i n g p e r m i s s i o n s a n d
// l i m i t a t i o n s u n d e r t h e L i c e n s e .
//
import UIKit
import KeychainAccess
import MatrixKit
import CommonCrypto
@ objcMembers
class EncryptionKeyManager : NSObject , MXKeyProviderDelegate {
static let shared = EncryptionKeyManager ( )
private static let keychainService : String = BuildSettings . baseBundleIdentifier + " .encryption-manager-service "
private static let contactsIv : KeyValueStoreKey = " contactsIv "
2020-12-16 13:06:07 +00:00
private static let contactsAesKey : KeyValueStoreKey = " contactsAesKey "
private static let accountIv : KeyValueStoreKey = " accountIv "
private static let accountAesKey : KeyValueStoreKey = " accountAesKey "
2021-02-18 15:37:58 +00:00
private static let cryptoOlmPickleKey : KeyValueStoreKey = " cryptoOlmPickleKey "
2021-06-03 12:48:01 +00:00
private static let roomLastMessageIv : KeyValueStoreKey = " roomLastMessageIv "
private static let roomLastMessageAesKey : KeyValueStoreKey = " roomLastMessageAesKey "
2020-12-14 22:05:57 +00:00
2020-12-16 13:06:07 +00:00
private let keychainStore : KeyValueStore = KeychainStore ( withKeychain : Keychain ( service : keychainService , accessGroup : BuildSettings . keychainAccessGroup ) )
2020-12-14 22:05:57 +00:00
private override init ( ) {
2020-12-15 15:55:34 +00:00
super . init ( )
2020-12-16 13:06:07 +00:00
initKeys ( )
2020-12-14 22:05:57 +00:00
}
2020-12-16 13:06:07 +00:00
private func initKeys ( ) {
2020-12-14 22:05:57 +00:00
generateIvIfNotExists ( forKey : EncryptionKeyManager . accountIv )
generateAesKeyIfNotExists ( forKey : EncryptionKeyManager . accountAesKey )
generateIvIfNotExists ( forKey : EncryptionKeyManager . contactsIv )
generateAesKeyIfNotExists ( forKey : EncryptionKeyManager . contactsAesKey )
2021-02-18 15:37:58 +00:00
generateKeyIfNotExists ( forKey : EncryptionKeyManager . cryptoOlmPickleKey , size : 32 )
2021-06-03 12:48:01 +00:00
generateIvIfNotExists ( forKey : EncryptionKeyManager . roomLastMessageIv )
generateAesKeyIfNotExists ( forKey : EncryptionKeyManager . roomLastMessageAesKey )
2020-12-14 22:05:57 +00:00
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsIv ) , " [EncryptionKeyManager] initKeys: Failed to generate IV for acount " )
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsAesKey ) , " [EncryptionKeyManager] initKeys: Failed to generate AES Key for acount " )
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsIv ) , " [EncryptionKeyManager] initKeys: Failed to generate IV for contacts " )
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsAesKey ) , " [EncryptionKeyManager] initKeys: Failed to generate AES Key for contacts " )
2021-02-18 15:37:58 +00:00
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . cryptoOlmPickleKey ) , " [EncryptionKeyManager] initKeys: Failed to generate Key for olm pickle key " )
2021-06-03 12:48:01 +00:00
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . roomLastMessageIv ) , " [EncryptionKeyManager] initKeys: Failed to generate IV for room last message " )
assert ( keychainStore . containsObject ( forKey : EncryptionKeyManager . roomLastMessageAesKey ) , " [EncryptionKeyManager] initKeys: Failed to generate AES Key for room last message encryption " )
2020-12-14 22:05:57 +00:00
}
// MARK: - M X K e y P r o v i d e r D e l e g a t e
func isEncryptionAvailableForData ( ofType dataType : String ) -> Bool {
2020-12-15 15:47:07 +00:00
return dataType = = MXKContactManagerDataType
|| dataType = = MXKAccountManagerDataType
2021-02-18 15:37:58 +00:00
|| dataType = = MXCryptoOlmPickleKeyDataType
2021-06-03 12:48:01 +00:00
|| dataType = = MXRoomLastMessageDataType
2020-12-14 22:05:57 +00:00
}
func hasKeyForData ( ofType dataType : String ) -> Bool {
switch dataType {
2020-12-15 15:47:07 +00:00
case MXKContactManagerDataType :
2020-12-14 22:05:57 +00:00
return keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsIv ) && keychainStore . containsObject ( forKey : EncryptionKeyManager . contactsAesKey )
2020-12-15 15:47:07 +00:00
case MXKAccountManagerDataType :
2020-12-14 22:05:57 +00:00
return keychainStore . containsObject ( forKey : EncryptionKeyManager . accountIv ) && keychainStore . containsObject ( forKey : EncryptionKeyManager . accountAesKey )
2021-02-18 15:37:58 +00:00
case MXCryptoOlmPickleKeyDataType :
return keychainStore . containsObject ( forKey : EncryptionKeyManager . cryptoOlmPickleKey )
2021-06-03 12:48:01 +00:00
case MXRoomLastMessageDataType :
return keychainStore . containsObject ( forKey : EncryptionKeyManager . roomLastMessageIv ) &&
keychainStore . containsObject ( forKey : EncryptionKeyManager . roomLastMessageAesKey )
2020-12-14 22:05:57 +00:00
default :
return false
}
}
func keyDataForData ( ofType dataType : String ) -> MXKeyData ? {
switch dataType {
2020-12-15 15:47:07 +00:00
case MXKContactManagerDataType :
2020-12-14 22:05:57 +00:00
if let ivKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . contactsIv ) ,
let aesKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . contactsAesKey ) {
return MXAesKeyData ( iv : ivKey , key : aesKey )
}
2020-12-15 15:47:07 +00:00
case MXKAccountManagerDataType :
2020-12-14 22:05:57 +00:00
if let ivKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . accountIv ) ,
let aesKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . accountAesKey ) {
return MXAesKeyData ( iv : ivKey , key : aesKey )
}
2021-02-18 15:37:58 +00:00
case MXCryptoOlmPickleKeyDataType :
if let key = try ? keychainStore . data ( forKey : EncryptionKeyManager . cryptoOlmPickleKey ) {
return MXRawDataKey ( key : key )
}
2021-06-03 12:48:01 +00:00
case MXRoomLastMessageDataType :
if let ivKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . roomLastMessageIv ) ,
let aesKey = try ? keychainStore . data ( forKey : EncryptionKeyManager . roomLastMessageAesKey ) {
return MXAesKeyData ( iv : ivKey , key : aesKey )
}
2020-12-14 22:05:57 +00:00
default :
return nil
}
return nil
}
// MARK: - P r i v a t e m e t h o d s
private func generateIvIfNotExists ( forKey key : String ) {
2020-12-15 15:47:07 +00:00
guard ! keychainStore . containsObject ( forKey : key ) else {
return
}
do {
try keychainStore . set ( MXAes . iv ( ) , forKey : key )
} catch {
2021-06-03 08:30:07 +00:00
MXLog . debug ( " [EncryptionKeyManager] initKeys: Failed to generate IV: \( error . localizedDescription ) " )
2020-12-14 22:05:57 +00:00
}
}
private func generateAesKeyIfNotExists ( forKey key : String ) {
generateKeyIfNotExists ( forKey : key , size : kCCKeySizeAES256 )
}
private func generateKeyIfNotExists ( forKey key : String , size : Int ) {
2020-12-15 15:47:07 +00:00
guard ! keychainStore . containsObject ( forKey : key ) else {
return
}
do {
var keyBytes = [ UInt8 ] ( repeating : 0 , count : size )
_ = SecRandomCopyBytes ( kSecRandomDefault , size , & keyBytes )
try keychainStore . set ( Data ( bytes : keyBytes , count : size ) , forKey : key )
} catch {
2021-06-03 08:30:07 +00:00
MXLog . debug ( " [EncryptionKeyManager] initKeys: Failed to generate Key[ \( key ) ]: \( error . localizedDescription ) " )
2020-12-14 22:05:57 +00:00
}
}
}