comparison sat/memory/params.py @ 3160:330a5f1d9eea

core (memory/crypto): replaced `PyCrypto` by `cryptography`: `PyCrypto` is unmaintained for years but was used in SàT for password hashing. This patch fixes that by replacing `PyCrypto` by the reference `cryptography` module which is well maintained. The behaviour stays the same (except that previously async `hash`, `encrypt` and `decrypt` methods are now synchronous, as they are quick and using a deferToThread may actually be more resource intensive than using blocking methods). It is planed to improve `memory.crypto` by using more up-to-date cryptography/hashing algorithms in the future. PyCrypto is no more a dependency of SàT
author Goffi <goffi@goffi.org>
date Sun, 09 Feb 2020 23:50:26 +0100
parents 559a625a236b
children 7d8a04a1d3a2
comparison
equal deleted inserted replaced
3159:30e08d904208 3160:330a5f1d9eea
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 2
3 3 # SàT: a XMPP client
4 # SAT: a jabber client
5 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org) 4 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org)
6 5
7 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by 7 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or 8 # the Free Software Foundation, either version 3 of the License, or
519 ) # profile password and empty passwords are returned "as is" 518 ) # profile password and empty passwords are returned "as is"
520 if not profile: 519 if not profile:
521 raise exceptions.ProfileNotSetError( 520 raise exceptions.ProfileNotSetError(
522 "The profile is needed to decrypt a password" 521 "The profile is needed to decrypt a password"
523 ) 522 )
524 d = self.host.memory.decryptValue(value, profile) 523 password = self.host.memory.decryptValue(value, profile)
525 524
526 def gotPlainPassword(password): 525 if password is None:
527 if ( 526 raise exceptions.InternalError("password should never be None")
528 password is None 527 return defer.succeed(password)
529 ): # empty value means empty password, None means decryption failure
530 raise exceptions.InternalError(
531 _("The stored password could not be decrypted!")
532 )
533 return password
534
535 return d.addCallback(gotPlainPassword)
536 528
537 def _type_to_str(self, result): 529 def _type_to_str(self, result):
538 """Convert result to string, according to its type """ 530 """Convert result to string, according to its type """
539 if isinstance(result, bool): 531 if isinstance(result, bool):
540 return C.boolConst(result) 532 return C.boolConst(result)
1054 ) 1046 )
1055 d.addCallback( 1047 d.addCallback(
1056 lambda __: PasswordHasher.hash(value) 1048 lambda __: PasswordHasher.hash(value)
1057 ) # profile password is hashed (empty value stays empty) 1049 ) # profile password is hashed (empty value stays empty)
1058 elif value: # other non empty passwords are encrypted with the personal key 1050 elif value: # other non empty passwords are encrypted with the personal key
1059 d = BlockCipher.encrypt(personal_key, value) 1051 d = defer.succeed(BlockCipher.encrypt(personal_key, value))
1060 else: 1052 else:
1061 d = defer.succeed(value) 1053 d = defer.succeed(value)
1062 else: 1054 else:
1063 d = defer.succeed(value) 1055 d = defer.succeed(value)
1064 1056