def test_03_encrypt_bytes(self): """des_encrypt_block()""" from passlib.crypto.des import (des_encrypt_block, shrink_des_key, _pack64, _unpack64) # run through test vectors for key, plaintext, correct in self.des_test_vectors: # convert to bytes key = _pack64(key) plaintext = _pack64(plaintext) correct = _pack64(correct) # test 64-bit key result = des_encrypt_block(key, plaintext) self.assertEqual(result, correct, "key=%r plaintext=%r:" % (key, plaintext)) # test 56-bit version key2 = shrink_des_key(key) result = des_encrypt_block(key2, plaintext) self.assertEqual( result, correct, "key=%r shrink(key)=%r plaintext=%r:" % (key, key2, plaintext)) # test with random parity bits for _ in range(20): key3 = _pack64(self._random_parity(_unpack64(key))) result = des_encrypt_block(key3, plaintext) self.assertEqual( result, correct, "key=%r rndparity(key)=%r plaintext=%r:" % (key, key3, plaintext)) # check invalid keys stub = b'\x00' * 8 self.assertRaises(TypeError, des_encrypt_block, 0, stub) self.assertRaises(ValueError, des_encrypt_block, b'\x00' * 6, stub) # check invalid input self.assertRaises(TypeError, des_encrypt_block, stub, 0) self.assertRaises(ValueError, des_encrypt_block, stub, b'\x00' * 7) # check invalid salts self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=-1) self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=1 << 24) # check invalid rounds self.assertRaises(ValueError, des_encrypt_block, stub, stub, 0, rounds=0)
def raw_lmhash(secret, encoding="ascii", hex=False): """encode password using des-based LMHASH algorithm; returns string of raw bytes, or unicode hex""" # NOTE: various references say LMHASH uses the OEM codepage of the host # for its encoding. until a clear reference is found, # as well as a path for getting the encoding, # letting this default to "ascii" to prevent incorrect hashes # from being made w/o user explicitly choosing an encoding. if isinstance(secret, unicode): secret = secret.encode(encoding) ns = secret.upper()[:14] + b"\x00" * (14 - len(secret)) out = des_encrypt_block(ns[:7], LM_MAGIC) + des_encrypt_block(ns[7:], LM_MAGIC) return hexlify(out).decode("ascii") if hex else out
def des_cbc_encrypt(key, value, iv=b'\x00' * 8, pad=b'\x00'): value += pad * (-len(value) % 8) # null pad to multiple of 8 hash = iv # start things off for offset in xrange(0,len(value),8): chunk = xor_bytes(hash, value[offset:offset+8]) hash = des_encrypt_block(key, chunk) return hash
def test_03_encrypt_bytes(self): """des_encrypt_block()""" from passlib.crypto.des import (des_encrypt_block, shrink_des_key, _pack64, _unpack64) # run through test vectors for key, plaintext, correct in self.des_test_vectors: # convert to bytes key = _pack64(key) plaintext = _pack64(plaintext) correct = _pack64(correct) # test 64-bit key result = des_encrypt_block(key, plaintext) self.assertEqual(result, correct, "key=%r plaintext=%r:" % (key, plaintext)) # test 56-bit version key2 = shrink_des_key(key) result = des_encrypt_block(key2, plaintext) self.assertEqual(result, correct, "key=%r shrink(key)=%r plaintext=%r:" % (key, key2, plaintext)) # test with random parity bits for _ in range(20): key3 = _pack64(self._random_parity(_unpack64(key))) result = des_encrypt_block(key3, plaintext) self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" % (key, key3, plaintext)) # check invalid keys stub = b'\x00' * 8 self.assertRaises(TypeError, des_encrypt_block, 0, stub) self.assertRaises(ValueError, des_encrypt_block, b'\x00'*6, stub) # check invalid input self.assertRaises(TypeError, des_encrypt_block, stub, 0) self.assertRaises(ValueError, des_encrypt_block, stub, b'\x00'*7) # check invalid salts self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=-1) self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=1<<24) # check invalid rounds self.assertRaises(ValueError, des_encrypt_block, stub, stub, 0, rounds=0)
def raw(cls, secret, encoding=None): """encode password using LANMAN hash algorithm. :type secret: unicode or utf-8 encoded bytes :arg secret: secret to hash :type encoding: str :arg encoding: optional encoding to use for unicode inputs. this defaults to ``cp437``, which is the common case for most situations. :returns: returns string of raw bytes """ if not encoding: encoding = cls.default_encoding # some nice empircal data re: different encodings is at... # http://www.openwall.com/lists/john-dev/2011/08/01/2 # http://www.freerainbowtables.com/phpBB3/viewtopic.php?t=387&p=12163 from passlib.crypto.des import des_encrypt_block MAGIC = cls._magic if isinstance(secret, unicode): # perform uppercasing while we're still unicode, # to give a better shot at getting non-ascii chars right. # (though some codepages do NOT upper-case the same as unicode). secret = secret.upper().encode(encoding) elif isinstance(secret, bytes): # FIXME: just trusting ascii upper will work? # and if not, how to do codepage specific case conversion? # we could decode first using <encoding>, # but *that* might not always be right. secret = secret.upper() else: raise TypeError("secret must be unicode or bytes") secret = right_pad_string(secret, 14) return des_encrypt_block(secret[0:7], MAGIC) + des_encrypt_block( secret[7:14], MAGIC)
def raw(cls, secret, encoding=None): """encode password using LANMAN hash algorithm. :type secret: unicode or utf-8 encoded bytes :arg secret: secret to hash :type encoding: str :arg encoding: optional encoding to use for unicode inputs. this defaults to ``cp437``, which is the common case for most situations. :returns: returns string of raw bytes """ if not encoding: encoding = cls.default_encoding # some nice empircal data re: different encodings is at... # http://www.openwall.com/lists/john-dev/2011/08/01/2 # http://www.freerainbowtables.com/phpBB3/viewtopic.php?t=387&p=12163 from passlib.crypto.des import des_encrypt_block MAGIC = cls._magic if isinstance(secret, unicode): # perform uppercasing while we're still unicode, # to give a better shot at getting non-ascii chars right. # (though some codepages do NOT upper-case the same as unicode). secret = secret.upper().encode(encoding) elif isinstance(secret, bytes): # FIXME: just trusting ascii upper will work? # and if not, how to do codepage specific case conversion? # we could decode first using <encoding>, # but *that* might not always be right. secret = secret.upper() else: raise TypeError("secret must be unicode or bytes") secret = right_pad_string(secret, 14) return des_encrypt_block(secret[0:7], MAGIC) + \ des_encrypt_block(secret[7:14], MAGIC)
def des_cbc_encrypt(key, value, iv=b'\x00' * 8, pad=b'\x00'): """performs des-cbc encryption, returns only last block. this performs a specific DES-CBC encryption implementation as needed by the Oracle10 hash. it probably won't be useful for other purposes as-is. input value is null-padded to multiple of 8 bytes. :arg key: des key as bytes :arg value: value to encrypt, as bytes. :param iv: optional IV :param pad: optional pad byte :returns: last block of DES-CBC encryption of all ``value``'s byte blocks. """ value += pad * (-len(value) % 8) # null pad to multiple of 8 hash = iv # start things off for offset in irange(0, len(value), 8): chunk = xor_bytes(hash, value[offset:offset + 8]) hash = des_encrypt_block(key, chunk) return hash
def des_cbc_encrypt(key, value, iv=b'\x00' * 8, pad=b'\x00'): """performs des-cbc encryption, returns only last block. this performs a specific DES-CBC encryption implementation as needed by the Oracle10 hash. it probably won't be useful for other purposes as-is. input value is null-padded to multiple of 8 bytes. :arg key: des key as bytes :arg value: value to encrypt, as bytes. :param iv: optional IV :param pad: optional pad byte :returns: last block of DES-CBC encryption of all ``value``'s byte blocks. """ value += pad * (-len(value) % 8) # null pad to multiple of 8 hash = iv # start things off for offset in irange(0,len(value),8): chunk = xor_bytes(hash, value[offset:offset+8]) hash = des_encrypt_block(key, chunk) return hash