You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					481 lines
				
				18 KiB
			
		
		
			
		
	
	
					481 lines
				
				18 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"""passlib.tests.test_handlers - tests for passlib hash algorithms"""
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# imports
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# core
							 | 
						||
| 
								 | 
							
								import logging
							 | 
						||
| 
								 | 
							
								log = logging.getLogger(__name__)
							 | 
						||
| 
								 | 
							
								import warnings
							 | 
						||
| 
								 | 
							
								# site
							 | 
						||
| 
								 | 
							
								# pkg
							 | 
						||
| 
								 | 
							
								from passlib import hash
							 | 
						||
| 
								 | 
							
								from passlib.utils.compat import u
							 | 
						||
| 
								 | 
							
								from passlib.tests.utils import TestCase, HandlerCase
							 | 
						||
| 
								 | 
							
								from passlib.tests.test_handlers import UPASS_WAV
							 | 
						||
| 
								 | 
							
								# module
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# ldap_pbkdf2_{digest}
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs,
							 | 
						||
| 
								 | 
							
								#       they don't extensive separate testing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ldap_pbkdf2_test(TestCase):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_wrappers(self):
							 | 
						||
| 
								 | 
							
								        """test ldap pbkdf2 wrappers"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertTrue(
							 | 
						||
| 
								 | 
							
								            hash.ldap_pbkdf2_sha1.verify(
							 | 
						||
| 
								 | 
							
								                "password",
							 | 
						||
| 
								 | 
							
								                '{PBKDF2}1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI',
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertTrue(
							 | 
						||
| 
								 | 
							
								            hash.ldap_pbkdf2_sha256.verify(
							 | 
						||
| 
								 | 
							
								                "password",
							 | 
						||
| 
								 | 
							
								                '{PBKDF2-SHA256}1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg'
							 | 
						||
| 
								 | 
							
								                '.fJPeq1h/gXXY7acBp9/6c.tmQ'
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertTrue(
							 | 
						||
| 
								 | 
							
								            hash.ldap_pbkdf2_sha512.verify(
							 | 
						||
| 
								 | 
							
								                "password",
							 | 
						||
| 
								 | 
							
								                '{PBKDF2-SHA512}1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1'
							 | 
						||
| 
								 | 
							
								                '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww'
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# pbkdf2 hashes
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								class atlassian_pbkdf2_sha1_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.atlassian_pbkdf2_sha1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # generated using Jira
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        ("admin", '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/p'),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								                  "{PKCS5S2}cE9Yq6Am5tQGdHSHhky2XLeOnURwzaLBG2sur7FHKpvy2u0qDn6GcVGRjlmJoIUy"),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    known_malformed_hashes = [
							 | 
						||
| 
								 | 
							
								        # bad char                                    ---\/
							 | 
						||
| 
								 | 
							
								        '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy!0IPksHChwoTAVYFrhsgoq8/p'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # bad size, missing padding
							 | 
						||
| 
								 | 
							
								        '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # bad size, with correct padding
							 | 
						||
| 
								 | 
							
								        '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/='
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class pbkdf2_sha1_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.pbkdf2_sha1
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        ("password", '$pbkdf2$1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI'),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								            '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc'),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    known_malformed_hashes = [
							 | 
						||
| 
								 | 
							
								        # zero padded rounds field
							 | 
						||
| 
								 | 
							
								        '$pbkdf2$01212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # empty rounds field
							 | 
						||
| 
								 | 
							
								        '$pbkdf2$$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # too many field
							 | 
						||
| 
								 | 
							
								        '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc$',
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class pbkdf2_sha256_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.pbkdf2_sha256
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        ("password",
							 | 
						||
| 
								 | 
							
								            '$pbkdf2-sha256$1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg.fJPeq1h/gXXY7acBp9/6c.tmQ'
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								            '$pbkdf2-sha256$1212$3SABFJGDtyhrQMVt1uABPw$WyaUoqCLgvz97s523nF4iuOqZNbp5Nt8do/cuaa7AiI'
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class pbkdf2_sha512_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.pbkdf2_sha512
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        ("password",
							 | 
						||
| 
								 | 
							
								            '$pbkdf2-sha512$1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1'
							 | 
						||
| 
								 | 
							
								            '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww'
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								            '$pbkdf2-sha512$1212$KkbvoKGsAIcF8IslDR6skQ$8be/PRmd88Ps8fmPowCJt'
							 | 
						||
| 
								 | 
							
								            'tH9G3vgxpG.Krjt3KT.NP6cKJ0V4Prarqf.HBwz0dCkJ6xgWnSj2ynXSV7MlvMa8Q'
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class cta_pbkdf2_sha1_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.cta_pbkdf2_sha1
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # test vectors from original implementation
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        (u("hashy the \N{SNOWMAN}"), '$p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0='),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # custom
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        ("password", "$p5k2$1$$h1TDLGSw9ST8UMAPeIE13i0t12c="),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								            "$p5k2$4321$OTg3NjU0MzIx$jINJrSvZ3LXeIbUdrJkRpN62_WQ="),
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class dlitz_pbkdf2_sha1_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.dlitz_pbkdf2_sha1
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # test vectors from original implementation
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        ('cloadm',  '$p5k2$$exec$r1EWMCMk7Rlv3L/RNcFXviDefYa0hlql'),
							 | 
						||
| 
								 | 
							
								        ('gnu',     '$p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g'),
							 | 
						||
| 
								 | 
							
								        ('dcl',     '$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL'),
							 | 
						||
| 
								 | 
							
								        ('spam',    '$p5k2$3e8$H0NX9mT/$wk/sE8vv6OMKuMaqazCJYDSUhWY9YB2J'),
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								                    '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ'),
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class grub_pbkdf2_sha512_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.grub_pbkdf2_sha512
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # test vectors generated from cmd line tool
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # salt=32 bytes
							 | 
						||
| 
								 | 
							
								        (UPASS_WAV,
							 | 
						||
| 
								 | 
							
								            'grub.pbkdf2.sha512.10000.BCAC1CEC5E4341C8C511C529'
							 | 
						||
| 
								 | 
							
								            '7FA877BE91C2817B32A35A3ECF5CA6B8B257F751.6968526A'
							 | 
						||
| 
								 | 
							
								            '2A5B1AEEE0A29A9E057336B48D388FFB3F600233237223C21'
							 | 
						||
| 
								 | 
							
								            '04DE1752CEC35B0DD1ED49563398A282C0F471099C2803FBA'
							 | 
						||
| 
								 | 
							
								            '47C7919CABC43192C68F60'),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # salt=64 bytes
							 | 
						||
| 
								 | 
							
								        ('toomanysecrets',
							 | 
						||
| 
								 | 
							
								            'grub.pbkdf2.sha512.10000.9B436BB6978682363D5C449B'
							 | 
						||
| 
								 | 
							
								            'BEAB322676946C632208BC1294D51F47174A9A3B04A7E4785'
							 | 
						||
| 
								 | 
							
								            '986CD4EA7470FAB8FE9F6BD522D1FC6C51109A8596FB7AD48'
							 | 
						||
| 
								 | 
							
								            '7C4493.0FE5EF169AFFCB67D86E2581B1E251D88C777B98BA'
							 | 
						||
| 
								 | 
							
								            '2D3256ECC9F765D84956FC5CA5C4B6FD711AA285F0A04DCF4'
							 | 
						||
| 
								 | 
							
								            '634083F9A20F4B6F339A52FBD6BED618E527B'),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# scram hash
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								class scram_test(HandlerCase):
							 | 
						||
| 
								 | 
							
								    handler = hash.scram
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # TODO: need a bunch more reference vectors from some real
							 | 
						||
| 
								 | 
							
								    # SCRAM transactions.
							 | 
						||
| 
								 | 
							
								    known_correct_hashes = [
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # taken from example in SCRAM specification (rfc 5802)
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								                   'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        # custom
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # same as 5802 example hash, but with sha-256 & sha-512 added.
							 | 
						||
| 
								 | 
							
								        ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								                   'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								                   'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
							 | 
						||
| 
								 | 
							
								                   'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
							 | 
						||
| 
								 | 
							
								                       'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # test unicode passwords & saslprep (all the passwords below
							 | 
						||
| 
								 | 
							
								        # should normalize to the same value: 'IX \xE0')
							 | 
						||
| 
								 | 
							
								        (u('IX \xE0'),             '$scram$6400$0BojBCBE6P2/N4bQ$'
							 | 
						||
| 
								 | 
							
								                                   'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
							 | 
						||
| 
								 | 
							
								        (u('\u2168\u3000a\u0300'), '$scram$6400$0BojBCBE6P2/N4bQ$'
							 | 
						||
| 
								 | 
							
								                                   'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
							 | 
						||
| 
								 | 
							
								        (u('\u00ADIX \xE0'),       '$scram$6400$0BojBCBE6P2/N4bQ$'
							 | 
						||
| 
								 | 
							
								                                   'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    known_malformed_hashes = [
							 | 
						||
| 
								 | 
							
								        # zero-padding in rounds
							 | 
						||
| 
								 | 
							
								        '$scram$04096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # non-digit in rounds
							 | 
						||
| 
								 | 
							
								        '$scram$409A$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # bad char in salt       ---\/
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf9-$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # bad char in digest                                       ---\/
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX3-',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # missing sections
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92',
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # too many sections
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30$',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # missing separator
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'
							 | 
						||
| 
								 | 
							
								                   'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # too many chars in alg name
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								                                 'shaxxx-190=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # missing sha-1 alg
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha-256=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # non-iana name
							 | 
						||
| 
								 | 
							
								        '$scram$4096$QSXCR.Q6sek8bf92$sha1=HZbuOlKbWl.eR8AfIposuKbhX30',
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def setUp(self):
							 | 
						||
| 
								 | 
							
								        super(scram_test, self).setUp()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # some platforms lack stringprep (e.g. Jython, IronPython)
							 | 
						||
| 
								 | 
							
								        self.require_stringprep()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # silence norm_hash_name() warning
							 | 
						||
| 
								 | 
							
								        warnings.filterwarnings("ignore", r"norm_hash_name\(\): unknown hash")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_90_algs(self):
							 | 
						||
| 
								 | 
							
								        """test parsing of 'algs' setting"""
							 | 
						||
| 
								 | 
							
								        defaults = dict(salt=b'A'*10, rounds=1000)
							 | 
						||
| 
								 | 
							
								        def parse(algs, **kwds):
							 | 
						||
| 
								 | 
							
								            for k in defaults:
							 | 
						||
| 
								 | 
							
								                kwds.setdefault(k, defaults[k])
							 | 
						||
| 
								 | 
							
								            return self.handler(algs=algs, **kwds).algs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # None -> default list
							 | 
						||
| 
								 | 
							
								        self.assertEqual(parse(None, use_defaults=True), hash.scram.default_algs)
							 | 
						||
| 
								 | 
							
								        self.assertRaises(TypeError, parse, None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # strings should be parsed
							 | 
						||
| 
								 | 
							
								        self.assertEqual(parse("sha1"), ["sha-1"])
							 | 
						||
| 
								 | 
							
								        self.assertEqual(parse("sha1, sha256, md5"), ["md5","sha-1","sha-256"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # lists should be normalized
							 | 
						||
| 
								 | 
							
								        self.assertEqual(parse(["sha-1","sha256"]), ["sha-1","sha-256"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # sha-1 required
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, parse, ["sha-256"])
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, parse, algs=[], use_defaults=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # alg names must be < 10 chars
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, parse, ["sha-1","shaxxx-190"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # alg & checksum mutually exclusive.
							 | 
						||
| 
								 | 
							
								        self.assertRaises(RuntimeError, parse, ['sha-1'],
							 | 
						||
| 
								 | 
							
								                          checksum={"sha-1": b"\x00"*20})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_90_checksums(self):
							 | 
						||
| 
								 | 
							
								        """test internal parsing of 'checksum' keyword"""
							 | 
						||
| 
								 | 
							
								        # check non-bytes checksum values are rejected
							 | 
						||
| 
								 | 
							
								        self.assertRaises(TypeError, self.handler, use_defaults=True,
							 | 
						||
| 
								 | 
							
								                          checksum={'sha-1':  u('X')*20})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # check sha-1 is required
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, self.handler, use_defaults=True,
							 | 
						||
| 
								 | 
							
								                          checksum={'sha-256':  b'X'*32})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # XXX: anything else that's not tested by the other code already?
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_91_extract_digest_info(self):
							 | 
						||
| 
								 | 
							
								        """test scram.extract_digest_info()"""
							 | 
						||
| 
								 | 
							
								        edi = self.handler.extract_digest_info
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # return appropriate value or throw KeyError
							 | 
						||
| 
								 | 
							
								        h = "$scram$10$AAAAAA$sha-1=AQ,bbb=Ag,ccc=Aw"
							 | 
						||
| 
								 | 
							
								        s = b'\x00'*4
							 | 
						||
| 
								 | 
							
								        self.assertEqual(edi(h,"SHA1"), (s,10, b'\x01'))
							 | 
						||
| 
								 | 
							
								        self.assertEqual(edi(h,"bbb"), (s,10, b'\x02'))
							 | 
						||
| 
								 | 
							
								        self.assertEqual(edi(h,"ccc"), (s,10, b'\x03'))
							 | 
						||
| 
								 | 
							
								        self.assertRaises(KeyError, edi, h, "ddd")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # config strings should cause value error.
							 | 
						||
| 
								 | 
							
								        c = "$scram$10$....$sha-1,bbb,ccc"
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, edi, c, "sha-1")
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, edi, c, "bbb")
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, edi, c, "ddd")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_92_extract_digest_algs(self):
							 | 
						||
| 
								 | 
							
								        """test scram.extract_digest_algs()"""
							 | 
						||
| 
								 | 
							
								        eda = self.handler.extract_digest_algs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								                   'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'), ["sha-1"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								                   'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', format="hashlib"),
							 | 
						||
| 
								 | 
							
								                         ["sha1"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								                   'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								                   'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
							 | 
						||
| 
								 | 
							
								                   'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
							 | 
						||
| 
								 | 
							
								                       'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'),
							 | 
						||
| 
								 | 
							
								                          ["sha-1","sha-256","sha-512"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_93_derive_digest(self):
							 | 
						||
| 
								 | 
							
								        """test scram.derive_digest()"""
							 | 
						||
| 
								 | 
							
								        # NOTE: this just does a light test, since derive_digest
							 | 
						||
| 
								 | 
							
								        # is used by hash / verify, and is tested pretty well via those.
							 | 
						||
| 
								 | 
							
								        hash = self.handler.derive_digest
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # check various encodings of password work.
							 | 
						||
| 
								 | 
							
								        s1 = b'\x01\x02\x03'
							 | 
						||
| 
								 | 
							
								        d1 = b'\xb2\xfb\xab\x82[tNuPnI\x8aZZ\x19\x87\xcen\xe9\xd3'
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash(u("\u2168"), s1, 1000, 'sha-1'), d1)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash(b"\xe2\x85\xa8", s1, 1000, 'SHA-1'), d1)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash(u("IX"), s1, 1000, 'sha1'), d1)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash(b"IX", s1, 1000, 'SHA1'), d1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # check algs
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash("IX", s1, 1000, 'md5'),
							 | 
						||
| 
								 | 
							
								                         b'3\x19\x18\xc0\x1c/\xa8\xbf\xe4\xa3\xc2\x8eM\xe8od')
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, hash, "IX", s1, 1000, 'sha-666')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # check rounds
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, hash, "IX", s1, 0, 'sha-1')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # unicode salts accepted as of passlib 1.7 (previous caused TypeError)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(hash(u("IX"), s1.decode("latin-1"), 1000, 'sha1'), d1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_94_saslprep(self):
							 | 
						||
| 
								 | 
							
								        """test hash/verify use saslprep"""
							 | 
						||
| 
								 | 
							
								        # NOTE: this just does a light test that saslprep() is being
							 | 
						||
| 
								 | 
							
								        # called in various places, relying in saslpreps()'s tests
							 | 
						||
| 
								 | 
							
								        # to verify full normalization behavior.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # hash unnormalized
							 | 
						||
| 
								 | 
							
								        h = self.do_encrypt(u("I\u00ADX"))
							 | 
						||
| 
								 | 
							
								        self.assertTrue(self.do_verify(u("IX"), h))
							 | 
						||
| 
								 | 
							
								        self.assertTrue(self.do_verify(u("\u2168"), h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # hash normalized
							 | 
						||
| 
								 | 
							
								        h = self.do_encrypt(u("\xF3"))
							 | 
						||
| 
								 | 
							
								        self.assertTrue(self.do_verify(u("o\u0301"), h))
							 | 
						||
| 
								 | 
							
								        self.assertTrue(self.do_verify(u("\u200Do\u0301"), h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # throws error if forbidden char provided
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, self.do_encrypt, u("\uFDD0"))
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, self.do_verify, u("\uFDD0"), h)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_94_using_w_default_algs(self, param="default_algs"):
							 | 
						||
| 
								 | 
							
								        """using() -- 'default_algs' parameter"""
							 | 
						||
| 
								 | 
							
								        # create subclass
							 | 
						||
| 
								 | 
							
								        handler = self.handler
							 | 
						||
| 
								 | 
							
								        orig = list(handler.default_algs) # in case it's modified in place
							 | 
						||
| 
								 | 
							
								        subcls = handler.using(**{param: "sha1,md5"})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # shouldn't have changed handler
							 | 
						||
| 
								 | 
							
								        self.assertEqual(handler.default_algs, orig)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # should have own set
							 | 
						||
| 
								 | 
							
								        self.assertEqual(subcls.default_algs, ["md5", "sha-1"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # test hash output
							 | 
						||
| 
								 | 
							
								        h1 = subcls.hash("dummy")
							 | 
						||
| 
								 | 
							
								        self.assertEqual(handler.extract_digest_algs(h1), ["md5", "sha-1"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_94_using_w_algs(self):
							 | 
						||
| 
								 | 
							
								        """using() -- 'algs' parameter"""
							 | 
						||
| 
								 | 
							
								        self.test_94_using_w_default_algs(param="algs")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_94_needs_update_algs(self):
							 | 
						||
| 
								 | 
							
								        """needs_update() -- algs setting"""
							 | 
						||
| 
								 | 
							
								        handler1 = self.handler.using(algs="sha1,md5")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # shouldn't need update, has same algs
							 | 
						||
| 
								 | 
							
								        h1 = handler1.hash("dummy")
							 | 
						||
| 
								 | 
							
								        self.assertFalse(handler1.needs_update(h1))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # *currently* shouldn't need update, has superset of algs required by handler2
							 | 
						||
| 
								 | 
							
								        # (may change this policy)
							 | 
						||
| 
								 | 
							
								        handler2 = handler1.using(algs="sha1")
							 | 
						||
| 
								 | 
							
								        self.assertFalse(handler2.needs_update(h1))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # should need update, doesn't have all algs required by handler3
							 | 
						||
| 
								 | 
							
								        handler3 = handler1.using(algs="sha1,sha256")
							 | 
						||
| 
								 | 
							
								        self.assertTrue(handler3.needs_update(h1))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_95_context_algs(self):
							 | 
						||
| 
								 | 
							
								        """test handling of 'algs' in context object"""
							 | 
						||
| 
								 | 
							
								        handler = self.handler
							 | 
						||
| 
								 | 
							
								        from passlib.context import CryptContext
							 | 
						||
| 
								 | 
							
								        c1 = CryptContext(["scram"], scram__algs="sha1,md5")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        h = c1.hash("dummy")
							 | 
						||
| 
								 | 
							
								        self.assertEqual(handler.extract_digest_algs(h), ["md5", "sha-1"])
							 | 
						||
| 
								 | 
							
								        self.assertFalse(c1.needs_update(h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        c2 = c1.copy(scram__algs="sha1")
							 | 
						||
| 
								 | 
							
								        self.assertFalse(c2.needs_update(h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        c2 = c1.copy(scram__algs="sha1,sha256")
							 | 
						||
| 
								 | 
							
								        self.assertTrue(c2.needs_update(h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_96_full_verify(self):
							 | 
						||
| 
								 | 
							
								        """test verify(full=True) flag"""
							 | 
						||
| 
								 | 
							
								        def vpart(s, h):
							 | 
						||
| 
								 | 
							
								            return self.handler.verify(s, h)
							 | 
						||
| 
								 | 
							
								        def vfull(s, h):
							 | 
						||
| 
								 | 
							
								            return self.handler.verify(s, h, full=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # reference
							 | 
						||
| 
								 | 
							
								        h = ('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								             'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								             'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,'
							 | 
						||
| 
								 | 
							
								             'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
							 | 
						||
| 
								 | 
							
								                'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
							 | 
						||
| 
								 | 
							
								        self.assertTrue(vfull('pencil', h))
							 | 
						||
| 
								 | 
							
								        self.assertFalse(vfull('tape', h))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # catch truncated digests.
							 | 
						||
| 
								 | 
							
								        h = ('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								             'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								             'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhV,' # -1 char
							 | 
						||
| 
								 | 
							
								             'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
							 | 
						||
| 
								 | 
							
								                'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, vfull, 'pencil', h)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # catch padded digests.
							 | 
						||
| 
								 | 
							
								        h = ('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								             'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,'
							 | 
						||
| 
								 | 
							
								             'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVYa,' # +1 char
							 | 
						||
| 
								 | 
							
								             'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/'
							 | 
						||
| 
								 | 
							
								                'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, vfull, 'pencil', h)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # catch hash containing digests belonging to diff passwords.
							 | 
						||
| 
								 | 
							
								        # proper behavior for quick-verify (the default) is undefined,
							 | 
						||
| 
								 | 
							
								        # but full-verify should throw error.
							 | 
						||
| 
								 | 
							
								        h = ('$scram$4096$QSXCR.Q6sek8bf92$'
							 | 
						||
| 
								 | 
							
								             'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' # 'pencil'
							 | 
						||
| 
								 | 
							
								             'sha-256=R7RJDWIbeKRTFwhE9oxh04kab0CllrQ3kCcpZUcligc,' # 'tape'
							 | 
						||
| 
								 | 
							
								             'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' # 'pencil'
							 | 
						||
| 
								 | 
							
								                'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ')
							 | 
						||
| 
								 | 
							
								        self.assertTrue(vpart('tape', h))
							 | 
						||
| 
								 | 
							
								        self.assertFalse(vpart('pencil', h))
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, vfull, 'pencil', h)
							 | 
						||
| 
								 | 
							
								        self.assertRaises(ValueError, vfull, 'tape', h)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# eof
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 |