diff options
author | Eli Collins <elic@assurancetechnologies.com> | 2011-02-24 19:49:27 -0500 |
---|---|---|
committer | Eli Collins <elic@assurancetechnologies.com> | 2011-02-24 19:49:27 -0500 |
commit | bc2304adb4f0232dbb768f3b9b9b1640c5d726bf (patch) | |
tree | f46fea815c34ebdbf206baa012d5ac8c2f9f1d99 /docs/lib | |
parent | 6b522e12345f416c452b1bef87d64b2ccf44fbf6 (diff) | |
download | passlib-bc2304adb4f0232dbb768f3b9b9b1640c5d726bf.tar.gz |
documentation work
==================
updated des crypt, crypt16, bigcrypt, bsdi crypt docs:
* added details of algorithm
* added security issues section
* updated deviations text
* other doc updates
Diffstat (limited to 'docs/lib')
-rw-r--r-- | docs/lib/passlib.hash.bigcrypt.rst | 129 | ||||
-rw-r--r-- | docs/lib/passlib.hash.bsdi_crypt.rst | 127 | ||||
-rw-r--r-- | docs/lib/passlib.hash.crypt16.rst | 95 | ||||
-rw-r--r-- | docs/lib/passlib.hash.des_crypt.rst | 102 | ||||
-rw-r--r-- | docs/lib/passlib.hash.md5_crypt.rst | 32 |
5 files changed, 341 insertions, 144 deletions
diff --git a/docs/lib/passlib.hash.bigcrypt.rst b/docs/lib/passlib.hash.bigcrypt.rst index 9496f21..6a13f06 100644 --- a/docs/lib/passlib.hash.bigcrypt.rst +++ b/docs/lib/passlib.hash.bigcrypt.rst @@ -12,9 +12,7 @@ and has a variable length hash string. .. warning:: - This algorithm is dangerously weak, and should not be used for new applications. - Not only does it suffer from all of the flaws of :class:`~passlib.hash.des_crypt`, - but it reveals information about password length and content. + This algorithm is dangerously weak, and should not be used if at all possible. Usage ===== @@ -22,11 +20,11 @@ This class can be used in exactly the same manner as :class:`~passlib.hash.des_c Functions ========= -.. autoclass:: bigcrypt +.. autoclass:: bigcrypt(checksum=None, salt=None, strict=False) Format ====== -An example hash (of ``passphrase``) is ``S/8NbAAlzbYO66hAa9XZyWy2``. +An example hash (of the string ``passphrase``) is ``S/8NbAAlzbYO66hAa9XZyWy2``. A bigcrypt hash string has the format ``{salt}{checksum_1}{checksum_2...}{checksum_n}`` for some integer ``n>0``, where: * ``{salt}`` is the salt, stored as a 2 character :func:`hash64 <passlib.utils.h64.encode_int12>`-encoded @@ -39,58 +37,101 @@ A bigcrypt hash string has the format ``{salt}{checksum_1}{checksum_2...}{checks * the integer ``n`` (the number of checksums) is determined by the formula ``n=min(1, (len(secret)+7)//8)``. +.. rst-class:: html-toggle + Algorithm ========= The bigcrypt algorithm is designed to re-use the original des-crypt algorithm: -1. given a password and a 12-bit salt... -2. first the password is null-padded to a non-zero multiple of 8 characters. -3. then a 56-bit DES key is generated from the lower 7 bits of the first 8 characters of the password. -4. the first checksum is generated by :func:`des encrypting <passlib.utils.des.mdes_encrypt_int_block>` - a 64-bit input block of null data for 25 rounds, using the DES key from step 3, - and the 12-bit salt from step 1. -5. the 64-bit DES output block is :func:`hash 64 <passlib.utils.h64.encode_dc_int64>`-encoded - to create the first checksum segment. -6. for each additional 8 characters in the padded password from step 2, - an additional checksum is generated by repeated steps 3..5 for each - remaining 8 characters in the password, and then appended - to the resulting hash. Each repetition of step 4 uses - the first two characters of the previous checksum as the new salt, - in place of the salt provided in step 1. - -Because of the chained structure, bigcrypt has the property that -the first 13 characters of any bigcrypt hash form a valid :class:`~passlib.hash.des-crypt` -hash of the same password; and bigcrypt hashes of any passwords -less than 9 characters will be identical to des-crypt. - -.. - - This is also one of it's main flaws: - each segment of the hash is essentially a separate - des-crypt hash, which can be attacked in parallel, - using existing des-crypt attack vectors. Furthermore, - it reveals information about the length of the encoded - password, further reducing the keyspace that needs - to be searched for each of the invididual segments. - Also, the last segment typically uses only a few - characters of the passphrase, and once cracked, - can be used to narrow the overall keyspace. +1. Given a password string and a salt string. + +2. The password is NULL padded at the end to the smallest non-zero multiple of 8 bytes. + +3. The lower 7 bits of the first 8 characters of the password are used + to form a 56-bit integer; with the first character providing + the most significant 7 bits, and the 8th character providing + the least significant 7 bits. + +4. The 2 character salt string is decoded to a 12-bit integer salt value; + The salt string uses little-endian + :func:`hash64 <passlib.utils.h64.decode_int12>` encoding. + +5. 25 repeated rounds of modified DES encryption are performed; + starting with a null input block, + and using the 56-bit integer from step 3 as the DES key. + + The salt is used to to mutate the normal DES encrypt operation + by swapping bits ``i`` and ``i+24`` in the DES E-Box output + if and only if bit ``i`` is set in the salt value. + +6. The 64-bit result of the last round of step 5 is then + lsb-padded with 2 zero bits. + +7. The resulting 66-bit integer is encoded in big-endian order + using the :func:`hash 64 <passlib.utils.h64.encode_int>` format. + This forms the first checksum segment. + +8. For each additional block of 8 bytes in the padded password (from step 2), + an additional checksum is generated by repeating steps 3..7, + with the following changes: + + a. Step 3 uses the specified 8 bytes of the password, instead of the first 8 bytes. + b. Step 4 uses the first two characters from the previous checksum + as the salt for the next checksum. + +9. The final checksum string is the concatenation of the checksum segments + generated from steps 7 and 8, in order. + +.. note:: + + Because of the chained structure, bigcrypt has the property that + the first 13 characters of any bigcrypt hash form a valid :class:`~passlib.hash.des_crypt` + hash of the same password; and bigcrypt hashes of any passwords + less than 9 characters will be identical to des-crypt. + +Security Issues +=============== +BigCrypt is dangerously flawed: + +* It suffers from all the flaws of :class:`~passlib.hash.des_crypt`. + +* Since checksum in it's hash is essentially a separate + des-crypt checksum, they can be attacked in parallel. + +* It reveals information about the length of the encoded + password (to within 8 characters), further reducing the keyspace that needs + to be searched for each of the invididual segments. + +* The last checksum typically contains only a few + characters of the passphrase, and once cracked, + can be used to narrow the overall keyspace. Deviations ========== -This implementation of bigcrypt differs from others in a few ways: +This implementation of bigcrypt differs from others in two ways: -* Before generating a hash, PassLib encodes unicode passwords using UTF-8. - The original bigcrypt was designed for 7-bit us-ascii, so this should not - conflict with most existing hashes. As of this writing, the authors - know of no specification defining the official behavior that should be used - in this situtation. +* Maximum Password Size: -* This implementation currently accepts arbitrarily large passwords, + This implementation currently accepts arbitrarily large passwords, producing arbitrarily large hashes. Other implementation have various limits on maximum password length (commonly, 128 chars), and discard the remaining part of the password. + Thus, while Passlib should be able to verify all existing + bigcrypt hashes, other systems may require hashes generated by Passlib + to be truncated to their specific maximum length. + +* Unicode Policy: + + The original bigcrypt algorithm was designed for 7-bit ``us-ascii`` encoding only + (as evidenced by the fact that it discards the 8th bit of all password bytes). + + In order to provide support for unicode strings, + PassLib will encode unicode passwords using ``utf-8`` + before running them through bigcrypt. If a different + encoding is desired by an application, the password should be encoded + before handing it to PassLib. + References ========== * `<http://www.mail-archive.com/exim-dev@exim.org/msg00970.html>`_ - discussion of bigcrypt & crypt16 diff --git a/docs/lib/passlib.hash.bsdi_crypt.rst b/docs/lib/passlib.hash.bsdi_crypt.rst index 9fc737a..99a918e 100644 --- a/docs/lib/passlib.hash.bsdi_crypt.rst +++ b/docs/lib/passlib.hash.bsdi_crypt.rst @@ -6,26 +6,43 @@ This algorithm was developed by BSDi for their BSD/OS distribution. It's based on :class:`~passlib.hash.des_crypt`, and contains a larger -salt and a variable number of rounds. Nonetheless, since it's based on DES, -and still shares many of des-crypt's other flaws, -it should not be used in new applications. +salt and a variable number of rounds. This algorithm is also +known as "Extended DES Crypt". + +.. warning:: + + This algorithm is weak by modern standards, + and should not be used in new applications. Usage ===== -Aside from differences in format and salt size, -ext-des-crypt usage is exactly the same as :class:`~passlib.hash.des_crypt`. +This class can be used directly as follows:: + + >>> from passlib.hash import bsdi_crypt as bc -.. todo:: + >>> bc.encrypt("password") #generate new salt, encrypt password + '_cD..Bf/46u7tr9IAJ6M' - this needs separate usage, showing rounds parameter. + >>> bc.encrypt("password", rounds=10000) #same, but with explict number of rounds + '_EQ0.amG/Pp5b0hIpggo' -Functions + >>> bc.identify('_cD..Bf/46u7tr9IAJ6M') #check if hash is recognized + True + >>> bc.identify('$1$3azHgidD$SrJPt7B.9rekpmwJwtON31') #check if some other hash is recognized + False + + >>> bc.verify("password", '_cD..Bf/46u7tr9IAJ6M') #verify correct password + True + >>> bc.verify("secret", '_cD..Bf/46u7tr9IAJ6M') #verify incorrect password + False + +Interface ========= -.. autoclass:: bsdi_crypt +.. autoclass:: bsdi_crypt(checksum=None, salt=None, rounds=None, strict=False) Format ====== -An example hash (of ``password``) is ``_EQ0.jzhSVeUyoSqLupI``. +An example hash (of the string ``password``) is ``_EQ0.jzhSVeUyoSqLupI``. An ext_des_crypt hash string consists of a 21 character string of the form ``_{rounds}{salt}{checksum}``. All characters except the underscore prefix are drawn from ``[./0-9A-Za-z]``. @@ -37,37 +54,87 @@ All characters except the underscore prefix are drawn from ``[./0-9A-Za-z]``. A ext_des_crypt configuration string is also accepted by this module; and has the same format as the hash string, but with the checksum portion omitted. +.. rst-class:: html-toggle + Algorithm ========= The checksum is formed by a modified version of the DES cipher in encrypt mode: -* First, the lower 7 bits of the first 8 characters of the password are used - to form a 56-bit DES key, in the same manner as des-crypt. +1. Given a password string, a salt string, and rounds string. + +2. The 4 character rounds string is decoded to a 24-bit integer rounds value; + The rounds string uses little-endian + :func:`hash64 <passlib.utils.h64.decode_int24>` encoding. + +3. The 4 character salt string is decoded to a 24-bit integer salt value; + The salt string uses little-endian + :func:`hash64 <passlib.utils.h64.decode_int24>` encoding. + +4. The password is NULL-padded on the end to the smallests non-zero multiple of 8 bytes. + +5. The lower 7 bits of the first 8 bytes of the password are used + to form a 56-bit integer; with the first byte providing + the most significant 7 bits, and the 8th byte providing + the least significant 7 bits. This is the DES key. + +6. For each additional block of 8 bytes in the padded password: -* Unlike des-crypt, the remainder of the password is also used. For every additional - 8 characters in the password, the key is encrypted using a single round of DES, - with itself as the input block. It is then xor'ed against the lower 7 bits - of the next 8 characters in the password. This is repeated until the password - is used up. + a. The current DES key is encrypted using a single round of normal DES, + with itself as the input block. + b. Step 5 is repeated for the current 8-byte block, and xored against the + existing DES key. -* The checksum is then generated by recursively performing a variable number rounds of DES encryption - starting with a null input block. The 24 bits of salt are used to mutate - the action performed by each block of the DES key schedule (see the source - of :func:`~passlib.utils.des.mdes_encrypt_int_block` for details). +7. Repeated rounds of modified DES encryption are performed; + starting with a null input block, + and using the 56-bit integer from step 5/6 as the DES key. -* The rounds, salt, and checksum are then encoded according the format as described above. + The salt is used to to mutate the normal DES encrypt operation + by swapping bits ``i`` and ``i+24`` in the DES E-Box output + if and only if bit ``i`` is set in the salt value. + + The number of rounds to is controlled by the value decoded in step 2. + +8. The 64-bit result of the last round of step 7 is then + lsb-padded with 2 zero bits. + +9. The resulting 66-bit integer is encoded in big-endian order + using the :func:`hash 64 <passlib.utils.h64.encode_int>` format. + +Security Issues +=============== +BSDi Crypt should not be considered sufficiently secure, for a number of reasons: + +* It's use of the DES stream cipher, which is vulnerable to practical pre-image attacks, + and considered broken, as well as having too-small key and block sizes. + +* The 24-bit salt is too small to defeat rainbow-table attacks + (most modern algorithms provide at least a 48-bit salt). + +* The fact that it only uses the lower 7 bits of each byte of the password + restricts the keyspace which needs to be searched. + +.. note:: + + This algorithm is none-the-less stronger than des-crypt itself, + since it supports variable rounds, a larger salt size, + and uses all bytes of the password. Deviations ========== -This implementation of ext-des-crypt differs from others in one way: +This implementation of bsdi-crypt differs from others in one way: + +* Unicode Policy: + + The original bsdi-crypt algorithm was designed for 7-bit ``us-ascii`` encoding only + (as evidenced by the fact that it discards the 8th bit of all password bytes). -* Before generating a hash, PassLib encodes unicode passwords using UTF-8. - The original ext-des-crypt was designed for 7-bit us-ascii, so this should not - conflict with most existing hashes. As of this writing, the authors - know of no specification defining the official behavior that should be used - in this situtation. + In order to provide support for unicode strings, + PassLib will encode unicode passwords using ``utf-8`` + before running them through bsdi-crypt. If a different + encoding is desired by an application, the password should be encoded + before handing it to Passlib. References ========== -* `<http://fuse4bsd.creo.hu/localcgi/man-cgi.cgi?crypt+3>`_ - primary source used for description of ext-des-crypt format & algorithm -* `<http://ftp.lava.net/cgi-bin/bsdi-man?proto=1.1&query=crypt&msection=3&apropos=0>`_ - another source describing algorithm +* Primary source used for description of bsdi-crypt format & algorithm - `<http://fuse4bsd.creo.hu/localcgi/man-cgi.cgi?crypt+3>`_ - +* Another source describing algorithm - `<http://ftp.lava.net/cgi-bin/bsdi-man?proto=1.1&query=crypt&msection=3&apropos=0>`_ diff --git a/docs/lib/passlib.hash.crypt16.rst b/docs/lib/passlib.hash.crypt16.rst index 40b499c..fa4a9c2 100644 --- a/docs/lib/passlib.hash.crypt16.rst +++ b/docs/lib/passlib.hash.crypt16.rst @@ -10,9 +10,7 @@ which allows passwords of up to 16 characters. .. warning:: - This algorithm is dangerously weak, and should not be used for new applications. - Not only does it suffer from all of the flaws of :class:`~passlib.hash.des_crypt`, - but it's easier to attack, and reveals information about password length and content. + This algorithm is dangerously weak, and should not be used if at all possible. .. note:: @@ -25,13 +23,13 @@ Usage ===== This class can be used in exactly the same manner as :class:`~passlib.hash.des_crypt`. -Functions +Interface ========= -.. autoclass:: crypt16 +.. autoclass:: crypt16(checksum=None, salt=None, strict=False) Format ====== -An example hash (of ``passphrase``) is ``aaX/UmCcBrceQ0kQGGWKTbuE``. +An example hash (of the string ``passphrase``) is ``aaX/UmCcBrceQ0kQGGWKTbuE``. A crypt16 hash string has the format ``{salt}{checksum_1}{checksum_2}``, where: * ``{salt}`` is the salt, stored as a 2 character :func:`hash64 <passlib.utils.h64.encode_int12>`-encoded @@ -41,40 +39,79 @@ A crypt16 hash string has the format ``{salt}{checksum_1}{checksum_2}``, where: :func:`hash64 <passlib.utils.h64.encode_dc_int64>`-encoded 64-bit integer (``X/UmCcBrceQ`` and ``0kQGGWKTbuE`` in the example). +.. rst-class:: html-toggle + Algorithm ========= The crypt16 algorithm uses a weakened version of the des-crypt algorithm: -1. given a password and a 12-bit salt... -2. first the password is null-padded or truncated to 16 characters, as needed. -3. then a 56-bit DES key is generated from the lower 7 bits of the first 8 characters of the password. -4. the first checksum is generated by :func:`des encrypting <passlib.utils.des.mdes_encrypt_int_block>` - a 64-bit input block of null data for 20 rounds, using the DES key from step 3, - and the 12-bit salt from step 1. -5. the 64-bit DES output block is :func:`hash 64 <passlib.utils.h64.encode_dc_int64>`-encoded - to create the first checksum segment. -6. the second checksum is generated by running the 2nd set of 8 characters of the password - through steps 3..5; except that the des-encryption step uses the same salt but only 5 rounds. +1. Given a password string and a salt string. + +2. The 2 character salt string is decoded to a 12-bit integer salt value; + The salt string uses little-endian + :func:`hash64 <passlib.utils.h64.decode_int12>` encoding. + +3. The password is NULL padded at the end or truncated to 16 bytes, as appropriate. + +4. The lower 7 bits of the first 8 characters of the password are used + to form a 56-bit integer; with the first character providing + the most significant 7 bits, and the 8th character providing + the least significant 7 bits. + +5. 20 repeated rounds of modified DES encryption are performed; + starting with a null input block, + and using the 56-bit integer from step 4 as the DES key. + + The salt is used to to mutate the normal DES encrypt operation + by swapping bits ``i`` and ``i+24`` in the DES E-Box output + if and only if bit ``i`` is set in the salt value. + +6. The 64-bit result of the last round of step 5 is then + lsb-padded with 2 zero bits. -.. +7. The resulting 66-bit integer is encoded in big-endian order + using the :func:`hash 64 <passlib.utils.h64.encode_int>` format. + This is the first checksum segment. - This algorithm is much weaker than des-crypt for the following reasons: +8. The second checksum segment is created by repeating + steps 4..7 using the second 8 bytes of the padding password (from step 3). + The only difference is that step 5 uses only 5 rounds. - * smaller number of rounds for each checksum - * passwords under 9 characters all have the same 2nd checksum (for a given salt) - * since both checksums use the same salt, they can be attacked at once - (by doing 5 rounds, checking checksum 2, and doing 15 rounds more). +9. The final checksum string is the concatenation of the two checksum segments, + in order. + +Security Issues +=============== +Crypt16 is dangerously flawed: + +* It suffers from all the flaws of :class:`~passlib.hash.des_crypt`. + +* Compared to des-crypt, it's smaller number of rounds + makes it even *more* vulnerable to brute-force attacks. + +* For a given salt, passwords under 9 characters all have the same 2nd checksum. + Given the 12-bit salt size, all such 2nd checksums can be easily pre-computed; + making an attack easier, and giving away information about password size. + +* Since both checksums use the same salt, they can be attacked at once + (by doing 5 rounds, checking the result against checksum 2, + doing 15 rounds more, and checking the result against checksum 1). Deviations ========== -This implementation of crypt16 deviates from public document of the format in one way: +This implementation of crypt16 deviates from public documentation of the format in one way: + +* Unicode Policy: + + The original crypt16 algorithm was designed for 7-bit ``us-ascii`` encoding only + (as evidenced by the fact that it discards the 8th bit of all password bytes). -* Before generating a hash, PassLib encodes unicode passwords using UTF-8. - The original bigcrypt was designed for 7-bit us-ascii, so this should not - conflict with most existing hashes. As of this writing, the authors - know of no specification defining the official behavior that should be used - in this situtation. + In order to provide support for unicode strings, + PassLib will encode unicode passwords using ``utf-8`` + before running them through crypt16. If a different + encoding is desired by an application, the password should be encoded + before handing it to PassLib. References ========== -* `<http://www.mail-archive.com/exim-dev@exim.org/msg00970.html>`_ - discussion of bigcrypt & crypt16 +* One source of information about bigcrypt & crypt16 - `<http://www.mail-archive.com/exim-dev@exim.org/msg00970.html>`_ - diff --git a/docs/lib/passlib.hash.des_crypt.rst b/docs/lib/passlib.hash.des_crypt.rst index c833ab4..c2f2775 100644 --- a/docs/lib/passlib.hash.des_crypt.rst +++ b/docs/lib/passlib.hash.des_crypt.rst @@ -11,10 +11,7 @@ it is supported for legacy purposes by many Unix flavors. .. warning:: This algorithm is extremely weak by modern standards, - and should not be used for new applications. - It suffers from it's use of the DES cipher, a small number of salt bits, - and fact that it uses only the first 8 characters of the password. - + and should not be used if possible. Usage ===== @@ -35,9 +32,9 @@ This class can be used directly as follows:: >>> dc.verify("secret", 'JQMuyS6H.AGMo') #verify incorrect password False -Functions +Interface ========= -.. autoclass:: des_crypt +.. autoclass:: des_crypt(checksum=None, salt=None, strict=False) Format ====== @@ -49,44 +46,91 @@ forming a hash64-encoded 64-bit integer checksum. A des-crypt configuration string is also accepted by this module, consists of only the first 2 characters, corresponding to the salt only. -An example hash (of ``password``) is ``JQMuyS6H.AGMo``, where the salt is ``JQ``, and the checksum ``MuyS6H.AGMo``. +An example hash (of the string ``password``) is ``JQMuyS6H.AGMo``, where the salt is ``JQ``, and the checksum ``MuyS6H.AGMo``. + +.. rst-class:: html-toggle Algorithm ========= The checksum is formed by a modified version of the DES cipher in encrypt mode: -* First, the lower 7 bits of the first 8 characters of the password are used - to form a 56-bit DES key. The remainder of the password is ignored. - Passwords less than 8 characters are null-padded. +1. Given a password string and a salt string. + +2. The 2 character salt string is decoded to a 12-bit integer salt value; + The salt string uses little-endian + :func:`hash64 <passlib.utils.h64.decode_int12>` encoding. + +3. If the password is less than 8 bytes, it's NULL padded at the end to 8 bytes. + +4. The lower 7 bits of the first 8 bytes of the password are used + to form a 56-bit integer; with the first byte providing + the most significant 7 bits, and the 8th byte providing + the least significant 7 bits. + + The remainder of the password (if any) is ignored. + +5. 25 repeated rounds of modified DES encryption are performed; + starting with a null input block, + and using the 56-bit integer from step 4 as the DES key. + + The salt is used to to mutate the normal DES encrypt operation + by swapping bits ``i`` and ``i+24`` in the DES E-Box output + if and only if bit ``i`` is set in the salt value. Thus, + if the salt is set to ``0``, normal DES encryption is performed. + (This was intended to prevent optimized implementations + of regular DES encryption to be useful in attacking this algorithm). -* The checksum is then generated by recursively performing 25 rounds of DES encryption, - starting with a null input block. The 12 bit salt is used to mutate - the action performed by each block of the DES key schedule, - in a manner dependant on the previous block (see the source - of :func:`~passlib.utils.des.mdes_encrypt_int_block` for details). +6. The 64-bit result of the last round of step 5 is then + lsb-padded with 2 zero bits. -* The checksum and salt are then encoded according the format, as described above. +7. The resulting 66-bit integer is encoded in big-endian order + using the :func:`hash 64 <passlib.utils.h64.encode_int>` format. -.. +Security Issues +=============== +DES-Crypt is no longer considered secure, for a variety of reasons: - swapping bits i and i+24 in the DES E-Box output when bit i is set in the salt +* It's use of the DES stream cipher, which is vulnerable to practical pre-image attacks, + and considered broken, as well as having too-small key and block sizes. + +* The 12-bit salt is considered to small to defeat rainbow-table attacks + (most modern algorithms provide at least a 48-bit salt). + +* The fact that it only uses the lower 7 bits of the first 8 bytes of the password + results in a dangerously small keyspace which needs to be searched. Deviations ========== This implementation of des-crypt differs from others in a few ways: -* Before generating a hash, PassLib encodes unicode passwords using UTF-8. - The original des-crypt was designed for 7-bit us-ascii, so this should not - conflict with most existing hashes. As of this writing, the authors - know of no specification defining the official behavior that should be used - in this situtation. +* Minimum salt string: + + Some implementations of des-crypt allow empty and single-character salt strings. + However, the behavior in these cases varies wildly, including errors and broken hashes. + To avoid all this, Passlib will throw an "invalid salt" if the provided + salt string is not at least 2 characters. + +* Restricted salt string character set: + + The underlying algorithm expects salt strings to use the + :mod:`hash64 <passlib.utils.h64>` character set to encode + a 12-bit integer. Many implementations of des-crypt will + accept a salt containing other characters, but + vary wildly in how they are handled, including errors and implementation-specific value mappings. + To avoid all this, Passlib will throw an "invalid salt" if the salt + string contains any non-standard characters. + +* Unicode Policy: + + The original des-crypt algorithm was designed for 7-bit ``us-ascii`` encoding only + (as evidenced by the fact that it discards the 8th bit of all password bytes). -* Some implementations accept empty and single-character salt strings, - as well as salt strings containing other characters. The various - implementation of des-crypt vary wildy in how they deal with these - border cases, including errors, non-standard algorithms, and unpredicateble results. - To avoid all this, Passlib will throw an "invalid salt" ValueError for these cases. + In order to provide support for unicode strings, + PassLib will encode unicode passwords using ``utf-8`` + before running them through des-crypt. If a different + encoding is desired by an application, the password should be encoded + before handing it to PassLib. References ========== -* `<http://www.dynamic.net.au/christos/crypt/UnixCrypt2.txt>`_ - java implementation of des-crypt, used as base for pure-python implementation +* A java implementation of des-crypt, used as base for Passlib's pure-python implementation, is located at `<http://www.dynamic.net.au/christos/crypt/UnixCrypt2.txt>`_ diff --git a/docs/lib/passlib.hash.md5_crypt.rst b/docs/lib/passlib.hash.md5_crypt.rst index 63a2ec5..949532a 100644 --- a/docs/lib/passlib.hash.md5_crypt.rst +++ b/docs/lib/passlib.hash.md5_crypt.rst @@ -6,7 +6,7 @@ This algorithm was developed for FreeBSD in 1994 by Poul-Henning Kamp, to replace the aging :class:`passlib.hash.des_crypt`. -It has since been adopted by a wide variety of other unix flavors, and is found +It has since been adopted by a wide variety of other Unix flavors, and is found in many other contexts as well. Security-wise it is considered to be steadily weakening (though not yet broken), and most unix flavors have since replaced with with stronger schemes, @@ -48,34 +48,39 @@ An md5-crypt hash string has the format ``$1${salt}${checksum}``, where: * ``{checksum}`` is 22 characters drawn from the same character set as the salt; encoding a 128-bit checksum (``azfrPr6af3Fc7dLblQXVa0`` in the example). +.. _md5-crypt-constant-insertion: + .. rst-class:: html-toggle Algorithm ========= -The MD5-Crypt algorithm is as follows: [#f1]_ +The MD5-Crypt algorithm [#f1]_ calculates a checksum as follows: 1. A password string and salt string are provided. - The salt should not include the magic prefix, - it should match string referred to as ``{salt}`` in the format section. + + (The salt should not include the magic prefix, + it should match string referred to as ``{salt}`` in the format section). 2. If needed, the salt should be truncated to a maximum of 8 characters. +.. + 3. Start MD5 digest B. 4. Add the password to digest B. 5. Add the salt to digest B. -6. Add the password to digest B, again. +6. Add the password to digest B. 7. Finish MD5 digest B. +.. + 8. Start MD5 digest A. 9. Add the password to digest A. -.. _md5-crypt-constant-insertion: - 10. Add the constant string ``$1$`` to digest A. 11. Add the salt to digest A. @@ -87,14 +92,16 @@ The MD5-Crypt algorithm is as follows: [#f1]_ add the first N bytes of digest B to digest A. 14. For each bit of the binary representation of the length - of the password string, starting with the lowest value bit - position, up to and including the largest bit set to 1: + of the password string; starting with the lowest value bit, + up to and including the largest bit set to 1: - a. If the bit is set 1, add the first character of the password to digest A. + a. If the current bit is set 1, add the first character of the password to digest A. b. Otherwise, add a NULL character to digest A. 15. Finish MD5 digest A. +.. + 16. For 1000 rounds (round values 0..999 inclusive), perform the following steps: @@ -113,6 +120,7 @@ The MD5-Crypt algorithm is as follows: [#f1]_ 18. Encode the resulting 16 byte string into a 22 character :mod:`hash 64 <passlib.utils.h64.encode_bytes>`-encoded string (the 2 msb bits encoded by the last hash64 character are used as 0 padding). + This results in the portion of the md5 crypt hash string referred to as ``{checksum}`` in the format section. Security Issues =============== @@ -134,13 +142,13 @@ though it is not yet considered broken: Deviations ========== -This implementation of md5-crypt differs from the reference implmentation (and others) in two ways: +Passlib's implementation of md5-crypt differs from the reference implementation (and others) in two ways: * Restricted salt string character set: The underlying algorithm can unambigously handle salt strings which contain any possible byte value besides ``\x00`` and ``$``. - However, PassLib strictly limits salts to the + However, Passlib strictly limits salts to the :mod:`hash 64 <passlib.utils.h64>` character set, as nearly all implementations of md5-crypt generate and expect salts containing those characters, |