VMM/password: Added support Blowfish/SHA-256/SHA-512 crypt().
Also updated Config and man section 5.
--- 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`)
--- 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,
--- 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
--- 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
--- 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
--- 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**