def cipher_key(self, sender: ID, receiver: ID, generate: bool = False) -> Optional[SymmetricKey]: if receiver.is_broadcast: return SymmetricKey.generate(algorithm=PlainKey.PLAIN) # get key from cache key = self.__cipher_key(sender, receiver) if key is None and generate: key = SymmetricKey.generate(algorithm=SymmetricKey.AES) self.__cache_cipher_key(key=key, sender=sender, receiver=receiver) return key
def decrypt(self, password: DecryptKey = None, private_key: DecryptKey = None) -> bytes: """ Decrypt data 1. decrypt key with private key (such as RSA) to a password 2. decrypt data with password (symmetric key, such as AES, DES, ...) :param password: symmetric key :param private_key: asymmetric private key :return: plaintext """ if self.__plaintext is None: # get symmetric key key = None if password is not None: assert isinstance( password, SymmetricKey), 'password error: %s' % password key = password elif private_key is not None: # assert isinstance(private_key, PrivateKey), 'private key error: %s' % private_key key_data = private_key.decrypt(self.key) key = SymmetricKey.parse(key=json_decode(data=key_data)) # get encrypted data data = self.data if key is not None and data is not None: self.__plaintext = key.decrypt(data=data) return self.__plaintext
def register_key_factories(): # Public Key: ECC factory = GeneralPublicFactory() PublicKey.register(algorithm=AsymmetricKey.ECC, factory=factory) # Public Key: RSA PublicKey.register(algorithm=AsymmetricKey.RSA, factory=factory) PublicKey.register(algorithm='SHA256withRSA', factory=factory) PublicKey.register(algorithm='RSA/ECB/PKCS1Padding', factory=factory) # Private Key: ECC factory = GeneralPrivateFactory(algorithm=AsymmetricKey.ECC) PrivateKey.register(algorithm=AsymmetricKey.ECC, factory=factory) # Private Key: RSA factory = GeneralPrivateFactory(algorithm=AsymmetricKey.RSA) PrivateKey.register(algorithm=AsymmetricKey.RSA, factory=factory) PrivateKey.register(algorithm='SHA256withRSA', factory=factory) PrivateKey.register(algorithm='RSA/ECB/PKCS1Padding', factory=factory) # Symmetric Key: AES factory = GeneralSymmetricFactory(algorithm=SymmetricKey.AES) SymmetricKey.register(algorithm=SymmetricKey.AES, factory=factory) SymmetricKey.register(algorithm='AES/CBC/PKCS7Padding', factory=factory) # Symmetric Key: Plain factory = GeneralSymmetricFactory(algorithm=PlainKey.PLAIN) SymmetricKey.register(algorithm=PlainKey.PLAIN, factory=factory)
def cipher_key(self, sender: ID, receiver: ID, generate: bool = False) -> Optional[SymmetricKey]: if receiver.is_broadcast: return plain_key # get key from cache key = self.__cipher_key(sender, receiver) if key is None and generate: # generate and cache it key = SymmetricKey.generate(algorithm=SymmetricKey.AES) assert key is not None, 'failed to generate key' self.cache_cipher_key(key=key, sender=sender, receiver=receiver) return key
def upload(self, content: FileContent, password: SymmetricKey, msg: InstantMessage): data = content.data if data is None or len(data) == 0: raise ValueError('failed to get file data: %s' % content) # encrypt and upload file data onto CDN and save the URL in message content encrypted = password.encrypt(data=data) if encrypted is None or len(encrypted) == 0: raise ValueError('failed to encrypt file data with key: %s' % password) url = self.messenger.upload_data(data=encrypted, msg=msg) if url is not None: # replace 'data' with 'URL' content.url = url content.data = None return True
def update_keys(self, key_map: dict) -> bool: """ Update cipher key table into memory cache :param key_map: cipher keys(with direction) from local storage :return: False on nothing changed """ changed = False for _from in key_map: sender = ID.parse(identifier=_from) table = key_map.get(_from) assert isinstance( table, dict), 'sender table error: %s, %s' % (_from, table) for _to in table: receiver = ID.parse(identifier=_to) pw = table.get(_to) key = SymmetricKey.parse(key=pw) # TODO: check whether exists an old key changed = True # cache key with direction self.__cache_cipher_key(key, sender, receiver) return changed
def __cache_cipher_key(self, key: SymmetricKey, sender: ID, receiver: ID): table = self.__key_map.get(sender) if table is None: table = {} self.__key_map[sender] = table else: old = table.get(receiver) if old is not None: # check whether same key exists equals = True # assert isinstance(key, dict), 'key info error: %s' % key for k in key: v1 = key.get(k) v2 = old.get(k) if v1 == v2: continue equals = False break if equals: # no need to update return table[receiver] = key
def download(self, content: FileContent, password: SymmetricKey, msg: SecureMessage): url = content.url if url is None or url.find('://') < 0: # download URL not found return False i_msg = InstantMessage.create(head=msg.envelope, body=content) # download from CDN encrypted = self.messenger.download_data(url=url, msg=i_msg) if encrypted is None or len(encrypted) == 0: # save symmetric key for decrypting file data after download from CDN content.password = password return False else: # decrypt file data data = password.decrypt(data=encrypted) if data is None or len(data) == 0: raise ValueError('failed to decrypt file data with key: %s' % password) content.data = data content.url = None return True