# HG changeset patch # User Pascal Volk # Date 1272875126 0 # Node ID ec19668282460b1fe7ded80e14e17461704d5e6f # Parent ea6d052de24a10841f9947b74edba2818802bd10 VMM/password: Added support Blowfish/SHA-256/SHA-512 crypt(). Also updated Config and man section 5. diff -r ea6d052de24a -r ec1966828246 TODO --- a/TODO Fri Apr 30 08:02:03 2010 +0000 +++ b/TODO Mon May 03 08:25:26 2010 +0000 @@ -4,6 +4,10 @@ ds - domainservices: smtp pop imap sieve??? + +subcommand for displaying support crypt algorithms. + + - Aliases - avoid looping aliases @@ -15,7 +19,9 @@ + alias domains Database: - public.users.passwd: increase to "character varying(150)" - why? `doveadm pw -s SSHA512.hex -p 1` + public.users.passwd: increase to "character varying(250)" + why? len(VirtualMailManager.password.pwhash('1', 'crypt.hex')) -> 249 + if VirtualMailManager.password.CRYPT_SHA512 is True and + misc.crypt_sha512_rounds > 0 public.users.digestmd5: add "character varying(48)" Outlook will love it. (`doveadm pw -s DIGEST-MD5.hex -p 1 -u 0`) diff -r ea6d052de24a -r ec1966828246 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Fri Apr 30 08:02:03 2010 +0000 +++ b/VirtualMailManager/Config.py Mon May 03 08:25:26 2010 +0000 @@ -343,6 +343,9 @@ }, 'misc': { 'base_directory': LCO(str, '/srv/mail', self.get, is_dir), + 'crypt_blowfish_rounds': LCO(int, 0, self.getint), + 'crypt_sha256_rounds': LCO(int, 0, self.getint), + 'crypt_sha512_rounds': LCO(int, 0, self.getint), 'dovecot_version': LCO(str, '1.2.11', self.hexversion, check_version_format), 'password_scheme': LCO(str, 'CRAM-MD5', self.get, diff -r ea6d052de24a -r ec1966828246 VirtualMailManager/password.py --- a/VirtualMailManager/password.py Fri Apr 30 08:02:03 2010 +0000 +++ b/VirtualMailManager/password.py Mon May 03 08:25:26 2010 +0000 @@ -13,7 +13,7 @@ """ from crypt import crypt -from random import choice, shuffle +from random import SystemRandom from subprocess import Popen, PIPE try: @@ -35,7 +35,28 @@ _ = lambda msg: msg cfg_dget = lambda option: None -_get_salt = lambda s_len: ''.join(choice(SALTCHARS) for x in xrange(s_len)) +_sys_rand = SystemRandom() +_get_salt = lambda salt_len: ''.join(_sys_rand.sample(SALTCHARS, salt_len)) + + +def _test_crypt_algorithms(): + """Check for Blowfish/SHA-256/SHA-512 support in crypt.crypt().""" + blowfish_ = sha256_ = sha512_ = False + _blowfish = '$2a$04$0123456789abcdefABCDE.N.drYX5yIAL1LkTaaZotW3yI0hQhZru' + _sha256 = '$5$rounds=1000$0123456789abcdef$K/DksR0DT01hGc8g/kt9McEgrbFMKi\ +9qrb1jehe7hn4' + _sha512 = '$6$rounds=1000$0123456789abcdef$ZIAd5WqfyLkpvsVCVUU1GrvqaZTqvh\ +JoouxdSqJO71l9Ld3tVrfOatEjarhghvEYADkq//LpDnTeO90tcbtHR1' + + if crypt('08/15!test~4711', '$2a$04$0123456789abcdefABCDEF$') == _blowfish: + blowfish_ = True + if crypt('08/15!test~4711', '$5$rounds=1000$0123456789abcdef$') == _sha256: + sha256_ = True + if crypt('08/15!test~4711', '$6$rounds=1000$0123456789abcdef$') == _sha512: + sha512_ = True + return blowfish_, sha256_, sha512_ + +CRYPT_BLOWFISH, CRYPT_SHA256, CRYPT_SHA512 = _test_crypt_algorithms() def _dovecotpw(password, scheme, encoding): @@ -110,10 +131,44 @@ return get_unicode('{%s}%s' % (scheme, password)) +def _get_crypt_blowfish_salt(): + """Generates a salt for Blowfish crypt.""" + rounds = cfg_dget('misc.crypt_blowfish_rounds') + if rounds < 4: + rounds = 4 + elif rounds > 31: + rounds = 31 + return '$2a$%02d$%s$' % (rounds, _get_salt(22)) + + +def _get_crypt_shaxxx_salt(crypt_id): + """Generates a salt for crypt using the SHA-256 or SHA-512 encryption + method. + *crypt_id* must be either `5` (SHA-256) or `6` (SHA1-512). + """ + assert crypt_id in (5, 6), 'invalid crypt id: %r' % crypt_id + if crypt_id is 6: + rounds = cfg_dget('misc.crypt_sha512_rounds') + else: + rounds = cfg_dget('misc.crypt_sha256_rounds') + if rounds < 1000: + rounds = 1000 + elif rounds > 999999999: + rounds = 999999999 + return '$%d$rounds=%d$%s$' % (crypt_id, rounds, _get_salt(16)) + + def _crypt_hash(password, scheme, encoding): """Generates (encoded) CRYPT/MD5/MD5-CRYPT hashes.""" if scheme == 'CRYPT': - salt = _get_salt(2) + if CRYPT_BLOWFISH and cfg_dget('misc.crypt_blowfish_rounds'): + salt = _get_crypt_blowfish_salt() + elif CRYPT_SHA512 and cfg_dget('misc.crypt_sha512_rounds'): + salt = _get_crypt_shaxxx_salt(6) + elif CRYPT_SHA256 and cfg_dget('misc.crypt_sha256_rounds'): + salt = _get_crypt_shaxxx_salt(5) + else: + salt = _get_salt(2) else: salt = '$1$%s$' % _get_salt(8) encrypted = crypt(password, salt) @@ -121,7 +176,7 @@ if encoding == 'HEX': encrypted = encrypted.encode('hex') else: - encrypted = encrypted.encode('base64').rstrip() + encrypted = encrypted.encode('base64').replace('\n', '') return _format_digest(encrypted, scheme, encoding) @@ -335,11 +390,9 @@ The length of the password can be configured in the ``vmm.cfg`` (account.password_length). """ - pw_chars = list(PASSWDCHARS) - shuffle(pw_chars) pw_len = cfg_dget('account.password_length') if pw_len < 8: pw_len = 8 - return ''.join(choice(pw_chars) for x in xrange(pw_len)) + return ''.join(_sys_rand.sample(PASSWDCHARS, pw_len)) -del _, cfg_dget +del _, cfg_dget, _test_crypt_algorithms diff -r ea6d052de24a -r ec1966828246 man/de/man5/vmm.cfg.5.rst --- a/man/de/man5/vmm.cfg.5.rst Fri Apr 30 08:02:03 2010 +0000 +++ b/man/de/man5/vmm.cfg.5.rst Mon May 03 08:25:26 2010 +0000 @@ -355,6 +355,48 @@ Alle Domain-Verzeichnisse werden innerhalb dieses Basis-Verzeichnisses angelegt. +.. _misc.crypt_blowfish_rounds: + +``crypt_blowfish_rounds (Vorgabe: 0)`` : *Int* + Anzahl der Verschlüsselungsdurchgänge für Blowfish-Crypt. + + Diese Einstellung beeinflusst das Verhalten des 'CRYPT'-Passwortschematas. + Standardmäßig verwendet crypt den DES-Algorithmus für die + Kennwortverschlüsselung. |vmm(1)|_ prüft, ob Blowfish-Crypt verfügbar + ist. Wenn der Blowfishalgorithmus unterstützt wird und der Wert dieser + Einstellung größer als 0 ist, wird Blowfish anstelle von DES als + Algorithmus verwendet. + + Der Wert muss im Bereich von **4** - **31** liegen. + +.. _misc.crypt_sha256_rounds: + +``crypt_sha256_rounds (Vorgabe: 0)`` : *Int* + Anzahl der Verschlüsselungdurchgänge für crypt unter Verwendung der SHA-256 + Verschlüsselungsmethode. + + Diese Einstellung beeinflusst das Verhalten des 'CRYPT'-Passwortschematas. + Standardmäßig verwendet crypt den DES-Algorithmus für die + Kennwortverschlüsselung. |vmm(1)|_ prüft, ob crypt die SHA-256 und/oder + SHA-512 Algorithmen unterstützt. Wenn die Algorithmen unterstützt werden + und der Wert dieser Einstellung größer als 0 ist, wird SHA-256 anstelle + von DES als Algorithmus verwendet. + + Wenn der Wert von |misc.crypt_sha512_rounds|_ größer als 0 ist, wird der + SHA-512 Algorithmus anstelle von SHA-256 verwendet. + + Der Wert muss im Bereich von **1000** - **999999999** liegen. + +.. _misc.crypt_sha512_rounds: + +``crypt_sha512_rounds (Vorgabe: 0)`` : *Int* + Anzahl der Verschlüsselungsdurchgänge für crypt unter Verwendung + der SHA-512 Verschlüsselungsmethode. + + Siehe |misc.crypt_sha256_rounds|_ für Details. + + Der Wert muss im Bereich von **1000** - **999999999** liegen. + .. _misc.password_scheme: ``password_scheme (Vorgabe: CRAM-MD5)`` : *String* @@ -381,7 +423,8 @@ [misc] base_directory = /srv/mail - password_scheme = PLAIN + crypt_sha512_rounds = 10000 + password_scheme = CRYPT transport = dovecot: dovecot_version = 2.0.beta4 diff -r ea6d052de24a -r ec1966828246 man/man5/vmm.cfg.5.rst --- a/man/man5/vmm.cfg.5.rst Fri Apr 30 08:02:03 2010 +0000 +++ b/man/man5/vmm.cfg.5.rst Mon May 03 08:25:26 2010 +0000 @@ -339,6 +339,44 @@ ``base_directory (default: /srv/mail)`` : *String* All domain directories will be created inside this directory. +.. _misc.crypt_blowfish_rounds: + +``crypt_blowfish_rounds (default: 0)`` : *Int* + Number of encryption rounds for Blowfish crypt. + + This setting affects the behavior of the 'CRYPT' password scheme. By + default crypt will use the DES algorithm for password encryption. + |vmm(1)|_ checks if Blowfish crypt is available. When the Blowfish + algorithm is supported and the value of this setting is greater than 0 + Blowfish will be used for crypt, instead of DES. + + The value must be in range **4** - **31**. + +.. _misc.crypt_sha256_rounds: + +``crypt_sha256_rounds (default: 0)`` : *Int* + Number of encryption rounds for crypt using the SHA-256 encryption method. + + This setting affects the behavior of the 'CRYPT' password scheme. By + default crypt will use the DES algorithm for password encryption. + |vmm(1)|_ checks if crypt supports the SHA-256 and/or SHA-512 algorithms. + When the algorithms are supported and the value of this setting is greater + than 0, SHA-256 will be used instead of DES. + + When the value of |misc.crypt_sha512_rounds|_ is greater than 0, the + SHA-512 algorithm will be used instead of SHA-256. + + The value must be in range **1000** - **999999999**. + +.. _misc.crypt_sha512_rounds: + +``crypt_sha512_rounds (default: 0)`` : *Int* + Number of encryption rounds for crypt using the SHA-512 encryption method. + + See |misc.crypt_sha256_rounds|_ for details. + + The value must be in range **1000** - **999999999**. + .. _misc.password_scheme: ``password_scheme (default: CRAM-MD5)`` : *String* @@ -365,7 +403,8 @@ [misc] base_directory = /srv/mail - password_scheme = PLAIN + crypt_sha512_rounds = 10000 + password_scheme = CRYPT transport = dovecot: dovecot_version = 2.0.beta4 diff -r ea6d052de24a -r ec1966828246 man/substitute_links_5.rst --- a/man/substitute_links_5.rst Fri Apr 30 08:02:03 2010 +0000 +++ b/man/substitute_links_5.rst Mon May 03 08:25:26 2010 +0000 @@ -2,6 +2,8 @@ .. |account.password_length| replace:: **password_length** .. |mailbox.format| replace:: **format** +.. |misc.crypt_sha256_rounds| replace:: **crypt_sha256_rounds** +.. |misc.crypt_sha512_rounds| replace:: **crypt_sha512_rounds** .. |misc.password_scheme| replace:: **misc.password_scheme** .. |vmm configure| replace:: **vmm configure**