move nearly everything into /src to make git.io/gam cleaner w/o a readme tree

This commit is contained in:
Jay Lee
2015-09-30 09:14:32 -04:00
parent 8b19040e45
commit c1225178d6
225 changed files with 2015 additions and 2015 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,168 @@
"""passlib.utils._blowfish - pure-python eks-blowfish implementation for bcrypt
This is a pure-python implementation of the EKS-Blowfish algorithm described by
Provos and Mazieres in `A Future-Adaptable Password Scheme
<http://www.openbsd.org/papers/bcrypt-paper.ps>`_.
This package contains two submodules:
* ``_blowfish/base.py`` contains a class implementing the eks-blowfish algorithm
using easy-to-examine code.
* ``_blowfish/unrolled.py`` contains a subclass which replaces some methods
of the original class with sped-up versions, mainly using unrolled loops
and local variables. this is the class which is actually used by
Passlib to perform BCrypt in pure python.
This module is auto-generated by a script, ``_blowfish/_gen_files.py``.
Status
------
This implementation is usable, but is an order of magnitude too slow to be
usable with real security. For "ok" security, BCrypt hashes should have at
least 2**11 rounds (as of 2011). Assuming a desired response time <= 100ms,
this means a BCrypt implementation should get at least 20 rounds/ms in order
to be both usable *and* secure. On a 2 ghz cpu, this implementation gets
roughly 0.09 rounds/ms under CPython (220x too slow), and 1.9 rounds/ms
under PyPy (10x too slow).
History
-------
While subsequently modified considerly for Passlib, this code was originally
based on `jBcrypt 0.2 <http://www.mindrot.org/projects/jBCrypt/>`_, which was
released under the BSD license::
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
#=============================================================================
# imports
#=============================================================================
# core
from itertools import chain
import struct
# pkg
from passlib.utils import bcrypt64, getrandbytes, rng
from passlib.utils.compat import b, bytes, BytesIO, unicode, u, native_string_types
from passlib.utils._blowfish.unrolled import BlowfishEngine
# local
__all__ = [
'BlowfishEngine',
'raw_bcrypt',
]
#=============================================================================
# bcrypt constants
#=============================================================================
# bcrypt constant data "OrpheanBeholderScryDoubt" as 6 integers
BCRYPT_CDATA = [
0x4f727068, 0x65616e42, 0x65686f6c,
0x64657253, 0x63727944, 0x6f756274
]
# struct used to encode ciphertext as digest (last output byte discarded)
digest_struct = struct.Struct(">6I")
#=============================================================================
# base bcrypt helper
#
# interface designed only for use by passlib.handlers.bcrypt:BCrypt
# probably not suitable for other purposes
#=============================================================================
BNULL = b('\x00')
def raw_bcrypt(password, ident, salt, log_rounds):
"""perform central password hashing step in bcrypt scheme.
:param password: the password to hash
:param ident: identifier w/ minor version (e.g. 2, 2a)
:param salt: the binary salt to use (encoded in bcrypt-base64)
:param rounds: the log2 of the number of rounds (as int)
:returns: bcrypt-base64 encoded checksum
"""
#===================================================================
# parse inputs
#===================================================================
# parse ident
assert isinstance(ident, native_string_types)
add_null_padding = True
if ident == u('2a') or ident == u('2y') or ident == u('2b'):
pass
elif ident == u('2'):
add_null_padding = False
elif ident == u('2x'):
raise ValueError("crypt_blowfish's buggy '2x' hashes are not "
"currently supported")
else:
raise ValueError("unknown ident: %r" % (ident,))
# decode & validate salt
assert isinstance(salt, bytes)
salt = bcrypt64.decode_bytes(salt)
if len(salt) < 16:
raise ValueError("Missing salt bytes")
elif len(salt) > 16:
salt = salt[:16]
# prepare password
assert isinstance(password, bytes)
if add_null_padding:
password += BNULL
# validate rounds
if log_rounds < 4 or log_rounds > 31:
raise ValueError("Bad number of rounds")
#===================================================================
#
# run EKS-Blowfish algorithm
#
# This uses the "enhanced key schedule" step described by
# Provos and Mazieres in "A Future-Adaptable Password Scheme"
# http://www.openbsd.org/papers/bcrypt-paper.ps
#
#===================================================================
engine = BlowfishEngine()
# convert password & salt into list of 18 32-bit integers (72 bytes total).
pass_words = engine.key_to_words(password)
salt_words = engine.key_to_words(salt)
# truncate salt_words to original 16 byte salt, or loop won't wrap
# correctly when passed to .eks_salted_expand()
salt_words16 = salt_words[:4]
# do EKS key schedule setup
engine.eks_salted_expand(pass_words, salt_words16)
# apply password & salt keys to key schedule a bunch more times.
rounds = 1<<log_rounds
engine.eks_repeated_expand(pass_words, salt_words, rounds)
# encipher constant data, and encode to bytes as digest.
data = list(BCRYPT_CDATA)
i = 0
while i < 6:
data[i], data[i+1] = engine.repeat_encipher(data[i], data[i+1], 64)
i += 2
raw = digest_struct.pack(*data)[:-1]
return bcrypt64.encode_bytes(raw)
#=============================================================================
# eof
#=============================================================================

View File

@@ -0,0 +1,204 @@
"""passlib.utils._blowfish._gen_files - meta script that generates unrolled.py"""
#=============================================================================
# imports
#=============================================================================
# core
import os
import textwrap
# pkg
from passlib.utils.compat import irange
# local
#=============================================================================
# helpers
#=============================================================================
def varlist(name, count):
return ", ".join(name + str(x) for x in irange(count))
def indent_block(block, padding):
"""ident block of text"""
lines = block.split("\n")
return "\n".join(
padding + line if line else ""
for line in lines
)
BFSTR = """\
((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff)
""".strip()
def render_encipher(write, indent=0):
for i in irange(0, 15, 2):
write(indent, """\
# Feistel substitution on left word (round %(i)d)
r ^= %(left)s ^ p%(i1)d
# Feistel substitution on right word (round %(i1)d)
l ^= %(right)s ^ p%(i2)d
""", i=i, i1=i+1, i2=i+2,
left=BFSTR, right=BFSTR.replace("l","r"),
)
def write_encipher_function(write, indent=0):
write(indent, """\
def encipher(self, l, r):
\"""blowfish encipher a single 64-bit block encoded as two 32-bit ints\"""
(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9,
p10, p11, p12, p13, p14, p15, p16, p17) = self.P
S0, S1, S2, S3 = self.S
l ^= p0
""")
render_encipher(write, indent+1)
write(indent+1, """\
return r ^ p17, l
""")
def write_expand_function(write, indent=0):
write(indent, """\
def expand(self, key_words):
\"""unrolled version of blowfish key expansion\"""
##assert len(key_words) >= 18, "size of key_words must be >= 18"
P, S = self.P, self.S
S0, S1, S2, S3 = S
#=============================================================
# integrate key
#=============================================================
""")
for i in irange(18):
write(indent+1, """\
p%(i)d = P[%(i)d] ^ key_words[%(i)d]
""", i=i)
write(indent+1, """\
#=============================================================
# update P
#=============================================================
#------------------------------------------------
# update P[0] and P[1]
#------------------------------------------------
l, r = p0, 0
""")
render_encipher(write, indent+1)
write(indent+1, """\
p0, p1 = l, r = r ^ p17, l
""")
for i in irange(2, 18, 2):
write(indent+1, """\
#------------------------------------------------
# update P[%(i)d] and P[%(i1)d]
#------------------------------------------------
l ^= p0
""", i=i, i1=i+1)
render_encipher(write, indent+1)
write(indent+1, """\
p%(i)d, p%(i1)d = l, r = r ^ p17, l
""", i=i, i1=i+1)
write(indent+1, """\
#------------------------------------------------
# save changes to original P array
#------------------------------------------------
P[:] = (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9,
p10, p11, p12, p13, p14, p15, p16, p17)
#=============================================================
# update S
#=============================================================
for box in S:
j = 0
while j < 256:
l ^= p0
""")
render_encipher(write, indent+3)
write(indent+3, """\
box[j], box[j+1] = l, r = r ^ p17, l
j += 2
""")
#=============================================================================
# main
#=============================================================================
def main():
target = os.path.join(os.path.dirname(__file__), "unrolled.py")
fh = file(target, "w")
def write(indent, msg, **kwds):
literal = kwds.pop("literal", False)
if kwds:
msg %= kwds
if not literal:
msg = textwrap.dedent(msg.rstrip(" "))
if indent:
msg = indent_block(msg, " " * (indent*4))
fh.write(msg)
write(0, """\
\"""passlib.utils._blowfish.unrolled - unrolled loop implementation of bcrypt,
autogenerated by _gen_files.py
currently this override the encipher() and expand() methods
with optimized versions, and leaves the other base.py methods alone.
\"""
#=================================================================
# imports
#=================================================================
# pkg
from passlib.utils._blowfish.base import BlowfishEngine as _BlowfishEngine
# local
__all__ = [
"BlowfishEngine",
]
#=================================================================
#
#=================================================================
class BlowfishEngine(_BlowfishEngine):
""")
write_encipher_function(write, indent=1)
write_expand_function(write, indent=1)
write(0, """\
#=================================================================
# eoc
#=================================================================
#=================================================================
# eof
#=================================================================
""")
if __name__ == "__main__":
main()
#=============================================================================
# eof
#=============================================================================

View File

@@ -0,0 +1,442 @@
"""passlib.utils._blowfish.base - unoptimized pure-python blowfish engine"""
#=============================================================================
# imports
#=============================================================================
# core
import struct
# pkg
from passlib.utils.compat import bytes
from passlib.utils import repeat_string
# local
__all__ = [
"BlowfishEngine",
]
#=============================================================================
# blowfish constants
#=============================================================================
BLOWFISH_P = BLOWFISH_S = None
def _init_constants():
global BLOWFISH_P, BLOWFISH_S
# NOTE: blowfish's spec states these numbers are the hex representation
# of the fractional portion of PI, in order.
# Initial contents of key schedule - 18 integers
BLOWFISH_P = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b,
]
# all 4 blowfish S boxes in one array - 256 integers per S box
BLOWFISH_S = [
# sbox 1
[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
],
# sbox 2
[
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
],
# sbox 3
[
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
],
# sbox 4
[
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
]
]
#=============================================================================
# engine
#=============================================================================
class BlowfishEngine(object):
def __init__(self):
if BLOWFISH_P is None:
_init_constants()
self.P = list(BLOWFISH_P)
self.S = [ list(box) for box in BLOWFISH_S ]
#===================================================================
# common helpers
#===================================================================
@staticmethod
def key_to_words(data, size=18):
"""convert data to tuple of <size> 4-byte integers, repeating or
truncating data as needed to reach specified size"""
assert isinstance(data, bytes)
dlen = len(data)
if not dlen:
# return all zeros - original C code would just read the NUL after
# the password, so mimicing that behavior for this edge case.
return [0]*size
# repeat data until it fills up 4*size bytes
data = repeat_string(data, size<<2)
# unpack
return struct.unpack(">%dI" % (size,), data)
#===================================================================
# blowfish routines
#===================================================================
def encipher(self, l, r):
"""loop version of blowfish encipher routine"""
P, S = self.P, self.S
l ^= P[0]
i = 1
while i < 17:
# Feistel substitution on left word
r = ((((S[0][l >> 24] + S[1][(l >> 16) & 0xff]) ^ S[2][(l >> 8) & 0xff]) +
S[3][l & 0xff]) & 0xffffffff) ^ P[i] ^ r
# swap vars so even rounds do Feistel substition on right word
l, r = r, l
i += 1
return r ^ P[17], l
# NOTE: decipher is same as above, just with reversed(P) instead.
def expand(self, key_words):
"""perform stock Blowfish keyschedule setup"""
assert len(key_words) >= 18, "key_words must be at least as large as P"
P, S, encipher = self.P, self.S, self.encipher
i = 0
while i < 18:
P[i] ^= key_words[i]
i += 1
i = l = r = 0
while i < 18:
P[i], P[i+1] = l,r = encipher(l,r)
i += 2
for box in S:
i = 0
while i < 256:
box[i], box[i+1] = l,r = encipher(l,r)
i += 2
#===================================================================
# eks-blowfish routines
#===================================================================
def eks_salted_expand(self, key_words, salt_words):
"""perform EKS' salted version of Blowfish keyschedule setup"""
# NOTE: this is the same as expand(), except for the addition
# of the operations involving *salt_words*.
assert len(key_words) >= 18, "key_words must be at least as large as P"
salt_size = len(salt_words)
assert salt_size, "salt_words must not be empty"
assert not salt_size & 1, "salt_words must have even length"
P, S, encipher = self.P, self.S, self.encipher
i = 0
while i < 18:
P[i] ^= key_words[i]
i += 1
s = i = l = r = 0
while i < 18:
l ^= salt_words[s]
r ^= salt_words[s+1]
s += 2
if s == salt_size:
s = 0
P[i], P[i+1] = l,r = encipher(l,r) # next()
i += 2
for box in S:
i = 0
while i < 256:
l ^= salt_words[s]
r ^= salt_words[s+1]
s += 2
if s == salt_size:
s = 0
box[i], box[i+1] = l,r = encipher(l,r) # next()
i += 2
def eks_repeated_expand(self, key_words, salt_words, rounds):
"""perform rounds stage of EKS keyschedule setup"""
expand = self.expand
n = 0
while n < rounds:
expand(key_words)
expand(salt_words)
n += 1
def repeat_encipher(self, l, r, count):
"""repeatedly apply encipher operation to a block"""
encipher = self.encipher
n = 0
while n < count:
l, r = encipher(l, r)
n += 1
return l, r
#===================================================================
# eoc
#===================================================================
#=============================================================================
# eof
#=============================================================================

View File

@@ -0,0 +1,771 @@
"""passlib.utils._blowfish.unrolled - unrolled loop implementation of bcrypt,
autogenerated by _gen_files.py
currently this override the encipher() and expand() methods
with optimized versions, and leaves the other base.py methods alone.
"""
#=============================================================================
# imports
#=============================================================================
# pkg
from passlib.utils._blowfish.base import BlowfishEngine as _BlowfishEngine
# local
__all__ = [
"BlowfishEngine",
]
#=============================================================================
#
#=============================================================================
class BlowfishEngine(_BlowfishEngine):
def encipher(self, l, r):
"""blowfish encipher a single 64-bit block encoded as two 32-bit ints"""
(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9,
p10, p11, p12, p13, p14, p15, p16, p17) = self.P
S0, S1, S2, S3 = self.S
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
return r ^ p17, l
def expand(self, key_words):
"""unrolled version of blowfish key expansion"""
##assert len(key_words) >= 18, "size of key_words must be >= 18"
P, S = self.P, self.S
S0, S1, S2, S3 = S
#=============================================================
# integrate key
#=============================================================
p0 = P[0] ^ key_words[0]
p1 = P[1] ^ key_words[1]
p2 = P[2] ^ key_words[2]
p3 = P[3] ^ key_words[3]
p4 = P[4] ^ key_words[4]
p5 = P[5] ^ key_words[5]
p6 = P[6] ^ key_words[6]
p7 = P[7] ^ key_words[7]
p8 = P[8] ^ key_words[8]
p9 = P[9] ^ key_words[9]
p10 = P[10] ^ key_words[10]
p11 = P[11] ^ key_words[11]
p12 = P[12] ^ key_words[12]
p13 = P[13] ^ key_words[13]
p14 = P[14] ^ key_words[14]
p15 = P[15] ^ key_words[15]
p16 = P[16] ^ key_words[16]
p17 = P[17] ^ key_words[17]
#=============================================================
# update P
#=============================================================
#------------------------------------------------
# update P[0] and P[1]
#------------------------------------------------
l, r = p0, 0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p0, p1 = l, r = r ^ p17, l
#------------------------------------------------
# update P[2] and P[3]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p2, p3 = l, r = r ^ p17, l
#------------------------------------------------
# update P[4] and P[5]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p4, p5 = l, r = r ^ p17, l
#------------------------------------------------
# update P[6] and P[7]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p6, p7 = l, r = r ^ p17, l
#------------------------------------------------
# update P[8] and P[9]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p8, p9 = l, r = r ^ p17, l
#------------------------------------------------
# update P[10] and P[11]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p10, p11 = l, r = r ^ p17, l
#------------------------------------------------
# update P[12] and P[13]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p12, p13 = l, r = r ^ p17, l
#------------------------------------------------
# update P[14] and P[15]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p14, p15 = l, r = r ^ p17, l
#------------------------------------------------
# update P[16] and P[17]
#------------------------------------------------
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
p16, p17 = l, r = r ^ p17, l
#------------------------------------------------
# save changes to original P array
#------------------------------------------------
P[:] = (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9,
p10, p11, p12, p13, p14, p15, p16, p17)
#=============================================================
# update S
#=============================================================
for box in S:
j = 0
while j < 256:
l ^= p0
# Feistel substitution on left word (round 0)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p1
# Feistel substitution on right word (round 1)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p2
# Feistel substitution on left word (round 2)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p3
# Feistel substitution on right word (round 3)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p4
# Feistel substitution on left word (round 4)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p5
# Feistel substitution on right word (round 5)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p6
# Feistel substitution on left word (round 6)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p7
# Feistel substitution on right word (round 7)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p8
# Feistel substitution on left word (round 8)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p9
# Feistel substitution on right word (round 9)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p10
# Feistel substitution on left word (round 10)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p11
# Feistel substitution on right word (round 11)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p12
# Feistel substitution on left word (round 12)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p13
# Feistel substitution on right word (round 13)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p14
# Feistel substitution on left word (round 14)
r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) +
S3[l & 0xff]) & 0xffffffff) ^ p15
# Feistel substitution on right word (round 15)
l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) +
S3[r & 0xff]) & 0xffffffff) ^ p16
box[j], box[j+1] = l, r = r ^ p17, l
j += 2
#===================================================================
# eoc
#===================================================================
#=============================================================================
# eof
#=============================================================================

438
src/passlib/utils/compat.py Normal file
View File

@@ -0,0 +1,438 @@
"""passlib.utils.compat - python 2/3 compatibility helpers"""
#=============================================================================
# figure out what we're running
#=============================================================================
#------------------------------------------------------------------------
# python version
#------------------------------------------------------------------------
import sys
PY2 = sys.version_info < (3,0)
PY3 = sys.version_info >= (3,0)
PY_MAX_25 = sys.version_info < (2,6) # py 2.5 or earlier
PY27 = sys.version_info[:2] == (2,7) # supports last 2.x release
PY_MIN_32 = sys.version_info >= (3,2) # py 3.2 or later
#------------------------------------------------------------------------
# python implementation
#------------------------------------------------------------------------
PYPY = hasattr(sys, "pypy_version_info")
JYTHON = sys.platform.startswith('java')
#------------------------------------------------------------------------
# capabilities
#------------------------------------------------------------------------
# __dir__() added in py2.6
SUPPORTS_DIR_METHOD = not PY_MAX_25 and not (PYPY and sys.pypy_version_info < (1,6))
#=============================================================================
# common imports
#=============================================================================
import logging; log = logging.getLogger(__name__)
if PY3:
import builtins
else:
import __builtin__ as builtins
def add_doc(obj, doc):
"""add docstring to an object"""
obj.__doc__ = doc
#=============================================================================
# the default exported vars
#=============================================================================
__all__ = [
# python versions
'PY2', 'PY3', 'PY_MAX_25', 'PY27', 'PY_MIN_32',
# io
'BytesIO', 'StringIO', 'NativeStringIO', 'SafeConfigParser',
'print_',
# type detection
## 'is_mapping',
'callable',
'int_types',
'num_types',
'base_string_types',
# unicode/bytes types & helpers
'u', 'b',
'unicode', 'bytes',
'uascii_to_str', 'bascii_to_str',
'str_to_uascii', 'str_to_bascii',
'join_unicode', 'join_bytes',
'join_byte_values', 'join_byte_elems',
'byte_elem_value',
'iter_byte_values',
# iteration helpers
'irange', #'lrange',
'imap', 'lmap',
'iteritems', 'itervalues',
'next',
# introspection
'exc_err', 'get_method_function', 'add_doc',
]
# begin accumulating mapping of lazy-loaded attrs,
# 'merged' into module at bottom
_lazy_attrs = dict()
#=============================================================================
# unicode & bytes types
#=============================================================================
if PY3:
unicode = str
bytes = builtins.bytes
def u(s):
assert isinstance(s, str)
return s
def b(s):
assert isinstance(s, str)
return s.encode("latin-1")
base_string_types = (unicode, bytes)
native_string_types = (unicode,)
else:
unicode = builtins.unicode
bytes = str if PY_MAX_25 else builtins.bytes
def u(s):
assert isinstance(s, str)
return s.decode("unicode_escape")
def b(s):
assert isinstance(s, str)
return s
base_string_types = basestring
native_string_types = (basestring,)
#=============================================================================
# unicode & bytes helpers
#=============================================================================
# function to join list of unicode strings
join_unicode = u('').join
# function to join list of byte strings
join_bytes = b('').join
if PY3:
def uascii_to_str(s):
assert isinstance(s, unicode)
return s
def bascii_to_str(s):
assert isinstance(s, bytes)
return s.decode("ascii")
def str_to_uascii(s):
assert isinstance(s, str)
return s
def str_to_bascii(s):
assert isinstance(s, str)
return s.encode("ascii")
join_byte_values = join_byte_elems = bytes
def byte_elem_value(elem):
assert isinstance(elem, int)
return elem
def iter_byte_values(s):
assert isinstance(s, bytes)
return s
def iter_byte_chars(s):
assert isinstance(s, bytes)
# FIXME: there has to be a better way to do this
return (bytes([c]) for c in s)
else:
def uascii_to_str(s):
assert isinstance(s, unicode)
return s.encode("ascii")
def bascii_to_str(s):
assert isinstance(s, bytes)
return s
def str_to_uascii(s):
assert isinstance(s, str)
return s.decode("ascii")
def str_to_bascii(s):
assert isinstance(s, str)
return s
def join_byte_values(values):
return join_bytes(chr(v) for v in values)
join_byte_elems = join_bytes
byte_elem_value = ord
def iter_byte_values(s):
assert isinstance(s, bytes)
return (ord(c) for c in s)
def iter_byte_chars(s):
assert isinstance(s, bytes)
return s
add_doc(uascii_to_str, "helper to convert ascii unicode -> native str")
add_doc(bascii_to_str, "helper to convert ascii bytes -> native str")
add_doc(str_to_uascii, "helper to convert ascii native str -> unicode")
add_doc(str_to_bascii, "helper to convert ascii native str -> bytes")
# join_byte_values -- function to convert list of ordinal integers to byte string.
# join_byte_elems -- function to convert list of byte elements to byte string;
# i.e. what's returned by ``b('a')[0]``...
# this is b('a') under PY2, but 97 under PY3.
# byte_elem_value -- function to convert byte element to integer -- a noop under PY3
add_doc(iter_byte_values, "iterate over byte string as sequence of ints 0-255")
add_doc(iter_byte_chars, "iterate over byte string as sequence of 1-byte strings")
#=============================================================================
# numeric
#=============================================================================
if PY3:
int_types = (int,)
num_types = (int, float)
else:
int_types = (int, long)
num_types = (int, long, float)
#=============================================================================
# iteration helpers
#
# irange - range iterable / view (xrange under py2, range under py3)
# lrange - range list (range under py2, list(range()) under py3)
#
# imap - map to iterator
# lmap - map to list
#=============================================================================
if PY3:
irange = range
##def lrange(*a,**k):
## return list(range(*a,**k))
def lmap(*a, **k):
return list(map(*a,**k))
imap = map
def iteritems(d):
return d.items()
def itervalues(d):
return d.values()
next_method_attr = "__next__"
else:
irange = xrange
##lrange = range
lmap = map
from itertools import imap
def iteritems(d):
return d.iteritems()
def itervalues(d):
return d.itervalues()
next_method_attr = "next"
if PY_MAX_25:
_undef = object()
def next(itr, default=_undef):
"""compat wrapper for next()"""
if default is _undef:
return itr.next()
try:
return itr.next()
except StopIteration:
return default
else:
next = builtins.next
#=============================================================================
# typing
#=============================================================================
##def is_mapping(obj):
## # non-exhaustive check, enough to distinguish from lists, etc
## return hasattr(obj, "items")
if (3,0) <= sys.version_info < (3,2):
# callable isn't dead, it's just resting
from collections import Callable
def callable(obj):
return isinstance(obj, Callable)
else:
callable = builtins.callable
#=============================================================================
# introspection
#=============================================================================
def exc_err():
"""return current error object (to avoid try/except syntax change)"""
return sys.exc_info()[1]
if PY3:
method_function_attr = "__func__"
else:
method_function_attr = "im_func"
def get_method_function(func):
"""given (potential) method, return underlying function"""
return getattr(func, method_function_attr, func)
#=============================================================================
# input/output
#=============================================================================
if PY3:
_lazy_attrs = dict(
BytesIO="io.BytesIO",
UnicodeIO="io.StringIO",
NativeStringIO="io.StringIO",
SafeConfigParser="configparser.SafeConfigParser",
)
if sys.version_info >= (3,2):
# py32 renamed this, removing old ConfigParser
_lazy_attrs["SafeConfigParser"] = "configparser.ConfigParser"
print_ = getattr(builtins, "print")
else:
_lazy_attrs = dict(
BytesIO="cStringIO.StringIO",
UnicodeIO="StringIO.StringIO",
NativeStringIO="cStringIO.StringIO",
SafeConfigParser="ConfigParser.SafeConfigParser",
)
def print_(*args, **kwds):
"""The new-style print function."""
# extract kwd args
fp = kwds.pop("file", sys.stdout)
sep = kwds.pop("sep", None)
end = kwds.pop("end", None)
if kwds:
raise TypeError("invalid keyword arguments")
# short-circuit if no target
if fp is None:
return
# use unicode or bytes ?
want_unicode = isinstance(sep, unicode) or isinstance(end, unicode) or \
any(isinstance(arg, unicode) for arg in args)
# pick default end sequence
if end is None:
end = u("\n") if want_unicode else "\n"
elif not isinstance(end, base_string_types):
raise TypeError("end must be None or a string")
# pick default separator
if sep is None:
sep = u(" ") if want_unicode else " "
elif not isinstance(sep, base_string_types):
raise TypeError("sep must be None or a string")
# write to buffer
first = True
write = fp.write
for arg in args:
if first:
first = False
else:
write(sep)
if not isinstance(arg, basestring):
arg = str(arg)
write(arg)
write(end)
#=============================================================================
# lazy overlay module
#=============================================================================
from types import ModuleType
def _import_object(source):
"""helper to import object from module; accept format `path.to.object`"""
modname, modattr = source.rsplit(".",1)
mod = __import__(modname, fromlist=[modattr], level=0)
return getattr(mod, modattr)
class _LazyOverlayModule(ModuleType):
"""proxy module which overlays original module,
and lazily imports specified attributes.
this is mainly used to prevent importing of resources
that are only needed by certain password hashes,
yet allow them to be imported from a single location.
used by :mod:`passlib.utils`, :mod:`passlib.utils.crypto`,
and :mod:`passlib.utils.compat`.
"""
@classmethod
def replace_module(cls, name, attrmap):
orig = sys.modules[name]
self = cls(name, attrmap, orig)
sys.modules[name] = self
return self
def __init__(self, name, attrmap, proxy=None):
ModuleType.__init__(self, name)
self.__attrmap = attrmap
self.__proxy = proxy
self.__log = logging.getLogger(name)
def __getattr__(self, attr):
proxy = self.__proxy
if proxy and hasattr(proxy, attr):
return getattr(proxy, attr)
attrmap = self.__attrmap
if attr in attrmap:
source = attrmap[attr]
if callable(source):
value = source()
else:
value = _import_object(source)
setattr(self, attr, value)
self.__log.debug("loaded lazy attr %r: %r", attr, value)
return value
raise AttributeError("'module' object has no attribute '%s'" % (attr,))
def __repr__(self):
proxy = self.__proxy
if proxy:
return repr(proxy)
else:
return ModuleType.__repr__(self)
def __dir__(self):
attrs = set(dir(self.__class__))
attrs.update(self.__dict__)
attrs.update(self.__attrmap)
proxy = self.__proxy
if proxy is not None:
attrs.update(dir(proxy))
return list(attrs)
# replace this module with overlay that will lazily import attributes.
_LazyOverlayModule.replace_module(__name__, _lazy_attrs)
#=============================================================================
# eof
#=============================================================================

859
src/passlib/utils/des.py Normal file
View File

@@ -0,0 +1,859 @@
"""passlib.utils.des -- DES block encryption routines
History
=======
These routines (which have since been drastically modified for python)
are based on a Java implementation of the des-crypt algorithm,
found at `<http://www.dynamic.net.au/christos/crypt/UnixCrypt2.txt>`_.
The copyright & license for that source is as follows::
UnixCrypt.java 0.9 96/11/25
Copyright (c) 1996 Aki Yoshida. All rights reserved.
Permission to use, copy, modify and distribute this software
for non-commercial or commercial purposes and without fee is
hereby granted provided that this copyright notice appears in
all copies.
---
Unix crypt(3C) utility
@version 0.9, 11/25/96
@author Aki Yoshida
---
modified April 2001
by Iris Van den Broeke, Daniel Deville
---
Unix Crypt.
Implements the one way cryptography used by Unix systems for
simple password protection.
@version $Id: UnixCrypt2.txt,v 1.1.1.1 2005/09/13 22:20:13 christos Exp $
@author Greg Wilkins (gregw)
The netbsd des-crypt implementation has some nice notes on how this all works -
http://fxr.googlebit.com/source/lib/libcrypt/crypt.c?v=NETBSD-CURRENT
"""
# TODO: could use an accelerated C version of this module to speed up lmhash,
# des-crypt, and ext-des-crypt
#=============================================================================
# imports
#=============================================================================
# core
import struct
# pkg
from passlib import exc
from passlib.utils.compat import bytes, join_byte_values, byte_elem_value, \
b, irange, irange, int_types
from passlib.utils import deprecated_function
# local
__all__ = [
"expand_des_key",
"des_encrypt_block",
"mdes_encrypt_int_block",
]
#=============================================================================
# constants
#=============================================================================
# masks/upper limits for various integer sizes
INT_24_MASK = 0xffffff
INT_56_MASK = 0xffffffffffffff
INT_64_MASK = 0xffffffffffffffff
# mask to clear parity bits from 64-bit key
_KDATA_MASK = 0xfefefefefefefefe
_KPARITY_MASK = 0x0101010101010101
# mask used to setup key schedule
_KS_MASK = 0xfcfcfcfcffffffff
#=============================================================================
# static DES tables
#=============================================================================
# placeholders filled in by _load_tables()
PCXROT = IE3264 = SPE = CF6464 = None
def _load_tables():
"""delay loading tables until they are actually needed"""
global PCXROT, IE3264, SPE, CF6464
#---------------------------------------------------------------
# Initial key schedule permutation
# PC1ROT - bit reverse, then PC1, then Rotate, then PC2
#---------------------------------------------------------------
# NOTE: this was reordered from original table to make perm3264 logic simpler
PC1ROT=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000002000, 0x0000000000002000,
0x0000000000000020, 0x0000000000000020, 0x0000000000002020, 0x0000000000002020,
0x0000000000000400, 0x0000000000000400, 0x0000000000002400, 0x0000000000002400,
0x0000000000000420, 0x0000000000000420, 0x0000000000002420, 0x0000000000002420, ),
( 0x0000000000000000, 0x2000000000000000, 0x0000000400000000, 0x2000000400000000,
0x0000800000000000, 0x2000800000000000, 0x0000800400000000, 0x2000800400000000,
0x0008000000000000, 0x2008000000000000, 0x0008000400000000, 0x2008000400000000,
0x0008800000000000, 0x2008800000000000, 0x0008800400000000, 0x2008800400000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000040, 0x0000000000000040,
0x0000000020000000, 0x0000000020000000, 0x0000000020000040, 0x0000000020000040,
0x0000000000200000, 0x0000000000200000, 0x0000000000200040, 0x0000000000200040,
0x0000000020200000, 0x0000000020200000, 0x0000000020200040, 0x0000000020200040, ),
( 0x0000000000000000, 0x0002000000000000, 0x0800000000000000, 0x0802000000000000,
0x0100000000000000, 0x0102000000000000, 0x0900000000000000, 0x0902000000000000,
0x4000000000000000, 0x4002000000000000, 0x4800000000000000, 0x4802000000000000,
0x4100000000000000, 0x4102000000000000, 0x4900000000000000, 0x4902000000000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000040000, 0x0000000000040000,
0x0000020000000000, 0x0000020000000000, 0x0000020000040000, 0x0000020000040000,
0x0000000000000004, 0x0000000000000004, 0x0000000000040004, 0x0000000000040004,
0x0000020000000004, 0x0000020000000004, 0x0000020000040004, 0x0000020000040004, ),
( 0x0000000000000000, 0x0000400000000000, 0x0200000000000000, 0x0200400000000000,
0x0080000000000000, 0x0080400000000000, 0x0280000000000000, 0x0280400000000000,
0x0000008000000000, 0x0000408000000000, 0x0200008000000000, 0x0200408000000000,
0x0080008000000000, 0x0080408000000000, 0x0280008000000000, 0x0280408000000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000010000000, 0x0000000010000000,
0x0000000000001000, 0x0000000000001000, 0x0000000010001000, 0x0000000010001000,
0x0000000040000000, 0x0000000040000000, 0x0000000050000000, 0x0000000050000000,
0x0000000040001000, 0x0000000040001000, 0x0000000050001000, 0x0000000050001000, ),
( 0x0000000000000000, 0x0000001000000000, 0x0000080000000000, 0x0000081000000000,
0x1000000000000000, 0x1000001000000000, 0x1000080000000000, 0x1000081000000000,
0x0004000000000000, 0x0004001000000000, 0x0004080000000000, 0x0004081000000000,
0x1004000000000000, 0x1004001000000000, 0x1004080000000000, 0x1004081000000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000080, 0x0000000000000080,
0x0000000000080000, 0x0000000000080000, 0x0000000000080080, 0x0000000000080080,
0x0000000000800000, 0x0000000000800000, 0x0000000000800080, 0x0000000000800080,
0x0000000000880000, 0x0000000000880000, 0x0000000000880080, 0x0000000000880080, ),
( 0x0000000000000000, 0x0000000008000000, 0x0000002000000000, 0x0000002008000000,
0x0000100000000000, 0x0000100008000000, 0x0000102000000000, 0x0000102008000000,
0x0000200000000000, 0x0000200008000000, 0x0000202000000000, 0x0000202008000000,
0x0000300000000000, 0x0000300008000000, 0x0000302000000000, 0x0000302008000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000400000, 0x0000000000400000,
0x0000000004000000, 0x0000000004000000, 0x0000000004400000, 0x0000000004400000,
0x0000000000000800, 0x0000000000000800, 0x0000000000400800, 0x0000000000400800,
0x0000000004000800, 0x0000000004000800, 0x0000000004400800, 0x0000000004400800, ),
( 0x0000000000000000, 0x0000000000008000, 0x0040000000000000, 0x0040000000008000,
0x0000004000000000, 0x0000004000008000, 0x0040004000000000, 0x0040004000008000,
0x8000000000000000, 0x8000000000008000, 0x8040000000000000, 0x8040000000008000,
0x8000004000000000, 0x8000004000008000, 0x8040004000000000, 0x8040004000008000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000004000, 0x0000000000004000,
0x0000000000000008, 0x0000000000000008, 0x0000000000004008, 0x0000000000004008,
0x0000000000000010, 0x0000000000000010, 0x0000000000004010, 0x0000000000004010,
0x0000000000000018, 0x0000000000000018, 0x0000000000004018, 0x0000000000004018, ),
( 0x0000000000000000, 0x0000000200000000, 0x0001000000000000, 0x0001000200000000,
0x0400000000000000, 0x0400000200000000, 0x0401000000000000, 0x0401000200000000,
0x0020000000000000, 0x0020000200000000, 0x0021000000000000, 0x0021000200000000,
0x0420000000000000, 0x0420000200000000, 0x0421000000000000, 0x0421000200000000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000010000000000, 0x0000010000000000,
0x0000000100000000, 0x0000000100000000, 0x0000010100000000, 0x0000010100000000,
0x0000000000100000, 0x0000000000100000, 0x0000010000100000, 0x0000010000100000,
0x0000000100100000, 0x0000000100100000, 0x0000010100100000, 0x0000010100100000, ),
( 0x0000000000000000, 0x0000000080000000, 0x0000040000000000, 0x0000040080000000,
0x0010000000000000, 0x0010000080000000, 0x0010040000000000, 0x0010040080000000,
0x0000000800000000, 0x0000000880000000, 0x0000040800000000, 0x0000040880000000,
0x0010000800000000, 0x0010000880000000, 0x0010040800000000, 0x0010040880000000, ),
)
#---------------------------------------------------------------
# Subsequent key schedule rotation permutations
# PC2ROT - PC2 inverse, then Rotate, then PC2
#---------------------------------------------------------------
# NOTE: this was reordered from original table to make perm3264 logic simpler
PC2ROTA=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000200000, 0x0000000000200000, 0x0000000000200000, 0x0000000000200000,
0x0000000004000000, 0x0000000004000000, 0x0000000004000000, 0x0000000004000000,
0x0000000004200000, 0x0000000004200000, 0x0000000004200000, 0x0000000004200000, ),
( 0x0000000000000000, 0x0000000000000800, 0x0000010000000000, 0x0000010000000800,
0x0000000000002000, 0x0000000000002800, 0x0000010000002000, 0x0000010000002800,
0x0000000010000000, 0x0000000010000800, 0x0000010010000000, 0x0000010010000800,
0x0000000010002000, 0x0000000010002800, 0x0000010010002000, 0x0000010010002800, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000100000000, 0x0000000100000000, 0x0000000100000000, 0x0000000100000000,
0x0000000000800000, 0x0000000000800000, 0x0000000000800000, 0x0000000000800000,
0x0000000100800000, 0x0000000100800000, 0x0000000100800000, 0x0000000100800000, ),
( 0x0000000000000000, 0x0000020000000000, 0x0000000080000000, 0x0000020080000000,
0x0000000000400000, 0x0000020000400000, 0x0000000080400000, 0x0000020080400000,
0x0000000008000000, 0x0000020008000000, 0x0000000088000000, 0x0000020088000000,
0x0000000008400000, 0x0000020008400000, 0x0000000088400000, 0x0000020088400000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000040, 0x0000000000000040, 0x0000000000000040, 0x0000000000000040,
0x0000000000001000, 0x0000000000001000, 0x0000000000001000, 0x0000000000001000,
0x0000000000001040, 0x0000000000001040, 0x0000000000001040, 0x0000000000001040, ),
( 0x0000000000000000, 0x0000000000000010, 0x0000000000000400, 0x0000000000000410,
0x0000000000000080, 0x0000000000000090, 0x0000000000000480, 0x0000000000000490,
0x0000000040000000, 0x0000000040000010, 0x0000000040000400, 0x0000000040000410,
0x0000000040000080, 0x0000000040000090, 0x0000000040000480, 0x0000000040000490, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000080000, 0x0000000000080000, 0x0000000000080000, 0x0000000000080000,
0x0000000000100000, 0x0000000000100000, 0x0000000000100000, 0x0000000000100000,
0x0000000000180000, 0x0000000000180000, 0x0000000000180000, 0x0000000000180000, ),
( 0x0000000000000000, 0x0000000000040000, 0x0000000000000020, 0x0000000000040020,
0x0000000000000004, 0x0000000000040004, 0x0000000000000024, 0x0000000000040024,
0x0000000200000000, 0x0000000200040000, 0x0000000200000020, 0x0000000200040020,
0x0000000200000004, 0x0000000200040004, 0x0000000200000024, 0x0000000200040024, ),
( 0x0000000000000000, 0x0000000000000008, 0x0000000000008000, 0x0000000000008008,
0x0010000000000000, 0x0010000000000008, 0x0010000000008000, 0x0010000000008008,
0x0020000000000000, 0x0020000000000008, 0x0020000000008000, 0x0020000000008008,
0x0030000000000000, 0x0030000000000008, 0x0030000000008000, 0x0030000000008008, ),
( 0x0000000000000000, 0x0000400000000000, 0x0000080000000000, 0x0000480000000000,
0x0000100000000000, 0x0000500000000000, 0x0000180000000000, 0x0000580000000000,
0x4000000000000000, 0x4000400000000000, 0x4000080000000000, 0x4000480000000000,
0x4000100000000000, 0x4000500000000000, 0x4000180000000000, 0x4000580000000000, ),
( 0x0000000000000000, 0x0000000000004000, 0x0000000020000000, 0x0000000020004000,
0x0001000000000000, 0x0001000000004000, 0x0001000020000000, 0x0001000020004000,
0x0200000000000000, 0x0200000000004000, 0x0200000020000000, 0x0200000020004000,
0x0201000000000000, 0x0201000000004000, 0x0201000020000000, 0x0201000020004000, ),
( 0x0000000000000000, 0x1000000000000000, 0x0004000000000000, 0x1004000000000000,
0x0002000000000000, 0x1002000000000000, 0x0006000000000000, 0x1006000000000000,
0x0000000800000000, 0x1000000800000000, 0x0004000800000000, 0x1004000800000000,
0x0002000800000000, 0x1002000800000000, 0x0006000800000000, 0x1006000800000000, ),
( 0x0000000000000000, 0x0040000000000000, 0x2000000000000000, 0x2040000000000000,
0x0000008000000000, 0x0040008000000000, 0x2000008000000000, 0x2040008000000000,
0x0000001000000000, 0x0040001000000000, 0x2000001000000000, 0x2040001000000000,
0x0000009000000000, 0x0040009000000000, 0x2000009000000000, 0x2040009000000000, ),
( 0x0000000000000000, 0x0400000000000000, 0x8000000000000000, 0x8400000000000000,
0x0000002000000000, 0x0400002000000000, 0x8000002000000000, 0x8400002000000000,
0x0100000000000000, 0x0500000000000000, 0x8100000000000000, 0x8500000000000000,
0x0100002000000000, 0x0500002000000000, 0x8100002000000000, 0x8500002000000000, ),
( 0x0000000000000000, 0x0000800000000000, 0x0800000000000000, 0x0800800000000000,
0x0000004000000000, 0x0000804000000000, 0x0800004000000000, 0x0800804000000000,
0x0000000400000000, 0x0000800400000000, 0x0800000400000000, 0x0800800400000000,
0x0000004400000000, 0x0000804400000000, 0x0800004400000000, 0x0800804400000000, ),
( 0x0000000000000000, 0x0080000000000000, 0x0000040000000000, 0x0080040000000000,
0x0008000000000000, 0x0088000000000000, 0x0008040000000000, 0x0088040000000000,
0x0000200000000000, 0x0080200000000000, 0x0000240000000000, 0x0080240000000000,
0x0008200000000000, 0x0088200000000000, 0x0008240000000000, 0x0088240000000000, ),
)
# NOTE: this was reordered from original table to make perm3264 logic simpler
PC2ROTB=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000400, 0x0000000000000400, 0x0000000000000400, 0x0000000000000400,
0x0000000000080000, 0x0000000000080000, 0x0000000000080000, 0x0000000000080000,
0x0000000000080400, 0x0000000000080400, 0x0000000000080400, 0x0000000000080400, ),
( 0x0000000000000000, 0x0000000000800000, 0x0000000000004000, 0x0000000000804000,
0x0000000080000000, 0x0000000080800000, 0x0000000080004000, 0x0000000080804000,
0x0000000000040000, 0x0000000000840000, 0x0000000000044000, 0x0000000000844000,
0x0000000080040000, 0x0000000080840000, 0x0000000080044000, 0x0000000080844000, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000008, 0x0000000000000008, 0x0000000000000008, 0x0000000000000008,
0x0000000040000000, 0x0000000040000000, 0x0000000040000000, 0x0000000040000000,
0x0000000040000008, 0x0000000040000008, 0x0000000040000008, 0x0000000040000008, ),
( 0x0000000000000000, 0x0000000020000000, 0x0000000200000000, 0x0000000220000000,
0x0000000000000080, 0x0000000020000080, 0x0000000200000080, 0x0000000220000080,
0x0000000000100000, 0x0000000020100000, 0x0000000200100000, 0x0000000220100000,
0x0000000000100080, 0x0000000020100080, 0x0000000200100080, 0x0000000220100080, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000002000, 0x0000000000002000, 0x0000000000002000, 0x0000000000002000,
0x0000020000000000, 0x0000020000000000, 0x0000020000000000, 0x0000020000000000,
0x0000020000002000, 0x0000020000002000, 0x0000020000002000, 0x0000020000002000, ),
( 0x0000000000000000, 0x0000000000000800, 0x0000000100000000, 0x0000000100000800,
0x0000000010000000, 0x0000000010000800, 0x0000000110000000, 0x0000000110000800,
0x0000000000000004, 0x0000000000000804, 0x0000000100000004, 0x0000000100000804,
0x0000000010000004, 0x0000000010000804, 0x0000000110000004, 0x0000000110000804, ),
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000001000, 0x0000000000001000, 0x0000000000001000, 0x0000000000001000,
0x0000000000000010, 0x0000000000000010, 0x0000000000000010, 0x0000000000000010,
0x0000000000001010, 0x0000000000001010, 0x0000000000001010, 0x0000000000001010, ),
( 0x0000000000000000, 0x0000000000000040, 0x0000010000000000, 0x0000010000000040,
0x0000000000200000, 0x0000000000200040, 0x0000010000200000, 0x0000010000200040,
0x0000000000008000, 0x0000000000008040, 0x0000010000008000, 0x0000010000008040,
0x0000000000208000, 0x0000000000208040, 0x0000010000208000, 0x0000010000208040, ),
( 0x0000000000000000, 0x0000000004000000, 0x0000000008000000, 0x000000000c000000,
0x0400000000000000, 0x0400000004000000, 0x0400000008000000, 0x040000000c000000,
0x8000000000000000, 0x8000000004000000, 0x8000000008000000, 0x800000000c000000,
0x8400000000000000, 0x8400000004000000, 0x8400000008000000, 0x840000000c000000, ),
( 0x0000000000000000, 0x0002000000000000, 0x0200000000000000, 0x0202000000000000,
0x1000000000000000, 0x1002000000000000, 0x1200000000000000, 0x1202000000000000,
0x0008000000000000, 0x000a000000000000, 0x0208000000000000, 0x020a000000000000,
0x1008000000000000, 0x100a000000000000, 0x1208000000000000, 0x120a000000000000, ),
( 0x0000000000000000, 0x0000000000400000, 0x0000000000000020, 0x0000000000400020,
0x0040000000000000, 0x0040000000400000, 0x0040000000000020, 0x0040000000400020,
0x0800000000000000, 0x0800000000400000, 0x0800000000000020, 0x0800000000400020,
0x0840000000000000, 0x0840000000400000, 0x0840000000000020, 0x0840000000400020, ),
( 0x0000000000000000, 0x0080000000000000, 0x0000008000000000, 0x0080008000000000,
0x2000000000000000, 0x2080000000000000, 0x2000008000000000, 0x2080008000000000,
0x0020000000000000, 0x00a0000000000000, 0x0020008000000000, 0x00a0008000000000,
0x2020000000000000, 0x20a0000000000000, 0x2020008000000000, 0x20a0008000000000, ),
( 0x0000000000000000, 0x0000002000000000, 0x0000040000000000, 0x0000042000000000,
0x4000000000000000, 0x4000002000000000, 0x4000040000000000, 0x4000042000000000,
0x0000400000000000, 0x0000402000000000, 0x0000440000000000, 0x0000442000000000,
0x4000400000000000, 0x4000402000000000, 0x4000440000000000, 0x4000442000000000, ),
( 0x0000000000000000, 0x0000004000000000, 0x0000200000000000, 0x0000204000000000,
0x0000080000000000, 0x0000084000000000, 0x0000280000000000, 0x0000284000000000,
0x0000800000000000, 0x0000804000000000, 0x0000a00000000000, 0x0000a04000000000,
0x0000880000000000, 0x0000884000000000, 0x0000a80000000000, 0x0000a84000000000, ),
( 0x0000000000000000, 0x0000000800000000, 0x0000000400000000, 0x0000000c00000000,
0x0000100000000000, 0x0000100800000000, 0x0000100400000000, 0x0000100c00000000,
0x0010000000000000, 0x0010000800000000, 0x0010000400000000, 0x0010000c00000000,
0x0010100000000000, 0x0010100800000000, 0x0010100400000000, 0x0010100c00000000, ),
( 0x0000000000000000, 0x0100000000000000, 0x0001000000000000, 0x0101000000000000,
0x0000001000000000, 0x0100001000000000, 0x0001001000000000, 0x0101001000000000,
0x0004000000000000, 0x0104000000000000, 0x0005000000000000, 0x0105000000000000,
0x0004001000000000, 0x0104001000000000, 0x0005001000000000, 0x0105001000000000, ),
)
#---------------------------------------------------------------
# PCXROT - PC1ROT, PC2ROTA, PC2ROTB listed in order
# of the PC1 rotation schedule, as used by des_setkey
#---------------------------------------------------------------
##ROTATES = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1)
##PCXROT = (
## PC1ROT, PC2ROTA, PC2ROTB, PC2ROTB,
## PC2ROTB, PC2ROTB, PC2ROTB, PC2ROTB,
## PC2ROTA, PC2ROTB, PC2ROTB, PC2ROTB,
## PC2ROTB, PC2ROTB, PC2ROTB, PC2ROTA,
## )
# NOTE: modified PCXROT to contain entrys broken into pairs,
# to help generate them in format best used by encoder.
PCXROT = (
(PC1ROT, PC2ROTA), (PC2ROTB, PC2ROTB),
(PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTB),
(PC2ROTA, PC2ROTB), (PC2ROTB, PC2ROTB),
(PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTA),
)
#---------------------------------------------------------------
# Bit reverse, intial permupation, expantion
# Initial permutation/expansion table
#---------------------------------------------------------------
# NOTE: this was reordered from original table to make perm3264 logic simpler
IE3264=(
( 0x0000000000000000, 0x0000000000800800, 0x0000000000008008, 0x0000000000808808,
0x0000008008000000, 0x0000008008800800, 0x0000008008008008, 0x0000008008808808,
0x0000000080080000, 0x0000000080880800, 0x0000000080088008, 0x0000000080888808,
0x0000008088080000, 0x0000008088880800, 0x0000008088088008, 0x0000008088888808, ),
( 0x0000000000000000, 0x0080080000000000, 0x0000800800000000, 0x0080880800000000,
0x0800000000000080, 0x0880080000000080, 0x0800800800000080, 0x0880880800000080,
0x8008000000000000, 0x8088080000000000, 0x8008800800000000, 0x8088880800000000,
0x8808000000000080, 0x8888080000000080, 0x8808800800000080, 0x8888880800000080, ),
( 0x0000000000000000, 0x0000000000001000, 0x0000000000000010, 0x0000000000001010,
0x0000000010000000, 0x0000000010001000, 0x0000000010000010, 0x0000000010001010,
0x0000000000100000, 0x0000000000101000, 0x0000000000100010, 0x0000000000101010,
0x0000000010100000, 0x0000000010101000, 0x0000000010100010, 0x0000000010101010, ),
( 0x0000000000000000, 0x0000100000000000, 0x0000001000000000, 0x0000101000000000,
0x1000000000000000, 0x1000100000000000, 0x1000001000000000, 0x1000101000000000,
0x0010000000000000, 0x0010100000000000, 0x0010001000000000, 0x0010101000000000,
0x1010000000000000, 0x1010100000000000, 0x1010001000000000, 0x1010101000000000, ),
( 0x0000000000000000, 0x0000000000002000, 0x0000000000000020, 0x0000000000002020,
0x0000000020000000, 0x0000000020002000, 0x0000000020000020, 0x0000000020002020,
0x0000000000200000, 0x0000000000202000, 0x0000000000200020, 0x0000000000202020,
0x0000000020200000, 0x0000000020202000, 0x0000000020200020, 0x0000000020202020, ),
( 0x0000000000000000, 0x0000200000000000, 0x0000002000000000, 0x0000202000000000,
0x2000000000000000, 0x2000200000000000, 0x2000002000000000, 0x2000202000000000,
0x0020000000000000, 0x0020200000000000, 0x0020002000000000, 0x0020202000000000,
0x2020000000000000, 0x2020200000000000, 0x2020002000000000, 0x2020202000000000, ),
( 0x0000000000000000, 0x0000000000004004, 0x0400000000000040, 0x0400000000004044,
0x0000000040040000, 0x0000000040044004, 0x0400000040040040, 0x0400000040044044,
0x0000000000400400, 0x0000000000404404, 0x0400000000400440, 0x0400000000404444,
0x0000000040440400, 0x0000000040444404, 0x0400000040440440, 0x0400000040444444, ),
( 0x0000000000000000, 0x0000400400000000, 0x0000004004000000, 0x0000404404000000,
0x4004000000000000, 0x4004400400000000, 0x4004004004000000, 0x4004404404000000,
0x0040040000000000, 0x0040440400000000, 0x0040044004000000, 0x0040444404000000,
0x4044040000000000, 0x4044440400000000, 0x4044044004000000, 0x4044444404000000, ),
)
#---------------------------------------------------------------
# Table that combines the S, P, and E operations.
#---------------------------------------------------------------
SPE=(
( 0x0080088008200000, 0x0000008008000000, 0x0000000000200020, 0x0080088008200020,
0x0000000000200000, 0x0080088008000020, 0x0000008008000020, 0x0000000000200020,
0x0080088008000020, 0x0080088008200000, 0x0000008008200000, 0x0080080000000020,
0x0080080000200020, 0x0000000000200000, 0x0000000000000000, 0x0000008008000020,
0x0000008008000000, 0x0000000000000020, 0x0080080000200000, 0x0080088008000000,
0x0080088008200020, 0x0000008008200000, 0x0080080000000020, 0x0080080000200000,
0x0000000000000020, 0x0080080000000000, 0x0080088008000000, 0x0000008008200020,
0x0080080000000000, 0x0080080000200020, 0x0000008008200020, 0x0000000000000000,
0x0000000000000000, 0x0080088008200020, 0x0080080000200000, 0x0000008008000020,
0x0080088008200000, 0x0000008008000000, 0x0080080000000020, 0x0080080000200000,
0x0000008008200020, 0x0080080000000000, 0x0080088008000000, 0x0000000000200020,
0x0080088008000020, 0x0000000000000020, 0x0000000000200020, 0x0000008008200000,
0x0080088008200020, 0x0080088008000000, 0x0000008008200000, 0x0080080000200020,
0x0000000000200000, 0x0080080000000020, 0x0000008008000020, 0x0000000000000000,
0x0000008008000000, 0x0000000000200000, 0x0080080000200020, 0x0080088008200000,
0x0000000000000020, 0x0000008008200020, 0x0080080000000000, 0x0080088008000020, ),
( 0x1000800810004004, 0x0000000000000000, 0x0000800810000000, 0x0000000010004004,
0x1000000000004004, 0x1000800800000000, 0x0000800800004004, 0x0000800810000000,
0x0000800800000000, 0x1000000010004004, 0x1000000000000000, 0x0000800800004004,
0x1000000010000000, 0x0000800810004004, 0x0000000010004004, 0x1000000000000000,
0x0000000010000000, 0x1000800800004004, 0x1000000010004004, 0x0000800800000000,
0x1000800810000000, 0x0000000000004004, 0x0000000000000000, 0x1000000010000000,
0x1000800800004004, 0x1000800810000000, 0x0000800810004004, 0x1000000000004004,
0x0000000000004004, 0x0000000010000000, 0x1000800800000000, 0x1000800810004004,
0x1000000010000000, 0x0000800810004004, 0x0000800800004004, 0x1000800810000000,
0x1000800810004004, 0x1000000010000000, 0x1000000000004004, 0x0000000000000000,
0x0000000000004004, 0x1000800800000000, 0x0000000010000000, 0x1000000010004004,
0x0000800800000000, 0x0000000000004004, 0x1000800810000000, 0x1000800800004004,
0x0000800810004004, 0x0000800800000000, 0x0000000000000000, 0x1000000000004004,
0x1000000000000000, 0x1000800810004004, 0x0000800810000000, 0x0000000010004004,
0x1000000010004004, 0x0000000010000000, 0x1000800800000000, 0x0000800800004004,
0x1000800800004004, 0x1000000000000000, 0x0000000010004004, 0x0000800810000000, ),
( 0x0000000000400410, 0x0010004004400400, 0x0010000000000000, 0x0010000000400410,
0x0000004004000010, 0x0000000000400400, 0x0010000000400410, 0x0010004004000000,
0x0010000000400400, 0x0000004004000000, 0x0000004004400400, 0x0000000000000010,
0x0010004004400410, 0x0010000000000010, 0x0000000000000010, 0x0000004004400410,
0x0000000000000000, 0x0000004004000010, 0x0010004004400400, 0x0010000000000000,
0x0010000000000010, 0x0010004004400410, 0x0000004004000000, 0x0000000000400410,
0x0000004004400410, 0x0010000000400400, 0x0010004004000010, 0x0000004004400400,
0x0010004004000000, 0x0000000000000000, 0x0000000000400400, 0x0010004004000010,
0x0010004004400400, 0x0010000000000000, 0x0000000000000010, 0x0000004004000000,
0x0010000000000010, 0x0000004004000010, 0x0000004004400400, 0x0010000000400410,
0x0000000000000000, 0x0010004004400400, 0x0010004004000000, 0x0000004004400410,
0x0000004004000010, 0x0000000000400400, 0x0010004004400410, 0x0000000000000010,
0x0010004004000010, 0x0000000000400410, 0x0000000000400400, 0x0010004004400410,
0x0000004004000000, 0x0010000000400400, 0x0010000000400410, 0x0010004004000000,
0x0010000000400400, 0x0000000000000000, 0x0000004004400410, 0x0010000000000010,
0x0000000000400410, 0x0010004004000010, 0x0010000000000000, 0x0000004004400400, ),
( 0x0800100040040080, 0x0000100000001000, 0x0800000000000080, 0x0800100040041080,
0x0000000000000000, 0x0000000040041000, 0x0800100000001080, 0x0800000040040080,
0x0000100040041000, 0x0800000000001080, 0x0000000000001000, 0x0800100000000080,
0x0800000000001080, 0x0800100040040080, 0x0000000040040000, 0x0000000000001000,
0x0800000040041080, 0x0000100040040000, 0x0000100000000000, 0x0800000000000080,
0x0000100040040000, 0x0800100000001080, 0x0000000040041000, 0x0000100000000000,
0x0800100000000080, 0x0000000000000000, 0x0800000040040080, 0x0000100040041000,
0x0000100000001000, 0x0800000040041080, 0x0800100040041080, 0x0000000040040000,
0x0800000040041080, 0x0800100000000080, 0x0000000040040000, 0x0800000000001080,
0x0000100040040000, 0x0000100000001000, 0x0800000000000080, 0x0000000040041000,
0x0800100000001080, 0x0000000000000000, 0x0000100000000000, 0x0800000040040080,
0x0000000000000000, 0x0800000040041080, 0x0000100040041000, 0x0000100000000000,
0x0000000000001000, 0x0800100040041080, 0x0800100040040080, 0x0000000040040000,
0x0800100040041080, 0x0800000000000080, 0x0000100000001000, 0x0800100040040080,
0x0800000040040080, 0x0000100040040000, 0x0000000040041000, 0x0800100000001080,
0x0800100000000080, 0x0000000000001000, 0x0800000000001080, 0x0000100040041000, ),
( 0x0000000000800800, 0x0000001000000000, 0x0040040000000000, 0x2040041000800800,
0x2000001000800800, 0x0040040000800800, 0x2040041000000000, 0x0000001000800800,
0x0000001000000000, 0x2000000000000000, 0x2000000000800800, 0x0040041000000000,
0x2040040000800800, 0x2000001000800800, 0x0040041000800800, 0x0000000000000000,
0x0040041000000000, 0x0000000000800800, 0x2000001000000000, 0x2040040000000000,
0x0040040000800800, 0x2040041000000000, 0x0000000000000000, 0x2000000000800800,
0x2000000000000000, 0x2040040000800800, 0x2040041000800800, 0x2000001000000000,
0x0000001000800800, 0x0040040000000000, 0x2040040000000000, 0x0040041000800800,
0x0040041000800800, 0x2040040000800800, 0x2000001000000000, 0x0000001000800800,
0x0000001000000000, 0x2000000000000000, 0x2000000000800800, 0x0040040000800800,
0x0000000000800800, 0x0040041000000000, 0x2040041000800800, 0x0000000000000000,
0x2040041000000000, 0x0000000000800800, 0x0040040000000000, 0x2000001000000000,
0x2040040000800800, 0x0040040000000000, 0x0000000000000000, 0x2040041000800800,
0x2000001000800800, 0x0040041000800800, 0x2040040000000000, 0x0000001000000000,
0x0040041000000000, 0x2000001000800800, 0x0040040000800800, 0x2040040000000000,
0x2000000000000000, 0x2040041000000000, 0x0000001000800800, 0x2000000000800800, ),
( 0x4004000000008008, 0x4004000020000000, 0x0000000000000000, 0x0000200020008008,
0x4004000020000000, 0x0000200000000000, 0x4004200000008008, 0x0000000020000000,
0x4004200000000000, 0x4004200020008008, 0x0000200020000000, 0x0000000000008008,
0x0000200000008008, 0x4004000000008008, 0x0000000020008008, 0x4004200020000000,
0x0000000020000000, 0x4004200000008008, 0x4004000020008008, 0x0000000000000000,
0x0000200000000000, 0x4004000000000000, 0x0000200020008008, 0x4004000020008008,
0x4004200020008008, 0x0000000020008008, 0x0000000000008008, 0x4004200000000000,
0x4004000000000000, 0x0000200020000000, 0x4004200020000000, 0x0000200000008008,
0x4004200000000000, 0x0000000000008008, 0x0000200000008008, 0x4004200020000000,
0x0000200020008008, 0x4004000020000000, 0x0000000000000000, 0x0000200000008008,
0x0000000000008008, 0x0000200000000000, 0x4004000020008008, 0x0000000020000000,
0x4004000020000000, 0x4004200020008008, 0x0000200020000000, 0x4004000000000000,
0x4004200020008008, 0x0000200020000000, 0x0000000020000000, 0x4004200000008008,
0x4004000000008008, 0x0000000020008008, 0x4004200020000000, 0x0000000000000000,
0x0000200000000000, 0x4004000000008008, 0x4004200000008008, 0x0000200020008008,
0x0000000020008008, 0x4004200000000000, 0x4004000000000000, 0x4004000020008008, ),
( 0x0000400400000000, 0x0020000000000000, 0x0020000000100000, 0x0400000000100040,
0x0420400400100040, 0x0400400400000040, 0x0020400400000000, 0x0000000000000000,
0x0000000000100000, 0x0420000000100040, 0x0420000000000040, 0x0000400400100000,
0x0400000000000040, 0x0020400400100000, 0x0000400400100000, 0x0420000000000040,
0x0420000000100040, 0x0000400400000000, 0x0400400400000040, 0x0420400400100040,
0x0000000000000000, 0x0020000000100000, 0x0400000000100040, 0x0020400400000000,
0x0400400400100040, 0x0420400400000040, 0x0020400400100000, 0x0400000000000040,
0x0420400400000040, 0x0400400400100040, 0x0020000000000000, 0x0000000000100000,
0x0420400400000040, 0x0000400400100000, 0x0400400400100040, 0x0420000000000040,
0x0000400400000000, 0x0020000000000000, 0x0000000000100000, 0x0400400400100040,
0x0420000000100040, 0x0420400400000040, 0x0020400400000000, 0x0000000000000000,
0x0020000000000000, 0x0400000000100040, 0x0400000000000040, 0x0020000000100000,
0x0000000000000000, 0x0420000000100040, 0x0020000000100000, 0x0020400400000000,
0x0420000000000040, 0x0000400400000000, 0x0420400400100040, 0x0000000000100000,
0x0020400400100000, 0x0400000000000040, 0x0400400400000040, 0x0420400400100040,
0x0400000000100040, 0x0020400400100000, 0x0000400400100000, 0x0400400400000040, ),
( 0x8008000080082000, 0x0000002080082000, 0x8008002000000000, 0x0000000000000000,
0x0000002000002000, 0x8008000080080000, 0x0000000080082000, 0x8008002080082000,
0x8008000000000000, 0x0000000000002000, 0x0000002080080000, 0x8008002000000000,
0x8008002080080000, 0x8008002000002000, 0x8008000000002000, 0x0000000080082000,
0x0000002000000000, 0x8008002080080000, 0x8008000080080000, 0x0000002000002000,
0x8008002080082000, 0x8008000000002000, 0x0000000000000000, 0x0000002080080000,
0x0000000000002000, 0x0000000080080000, 0x8008002000002000, 0x8008000080082000,
0x0000000080080000, 0x0000002000000000, 0x0000002080082000, 0x8008000000000000,
0x0000000080080000, 0x0000002000000000, 0x8008000000002000, 0x8008002080082000,
0x8008002000000000, 0x0000000000002000, 0x0000000000000000, 0x0000002080080000,
0x8008000080082000, 0x8008002000002000, 0x0000002000002000, 0x8008000080080000,
0x0000002080082000, 0x8008000000000000, 0x8008000080080000, 0x0000002000002000,
0x8008002080082000, 0x0000000080080000, 0x0000000080082000, 0x8008000000002000,
0x0000002080080000, 0x8008002000000000, 0x8008002000002000, 0x0000000080082000,
0x8008000000000000, 0x0000002080082000, 0x8008002080080000, 0x0000000000000000,
0x0000000000002000, 0x8008000080082000, 0x0000002000000000, 0x8008002080080000, ),
)
#---------------------------------------------------------------
# compressed/interleaved => final permutation table
# Compression, final permutation, bit reverse
#---------------------------------------------------------------
# NOTE: this was reordered from original table to make perm6464 logic simpler
CF6464=(
( 0x0000000000000000, 0x0000002000000000, 0x0000200000000000, 0x0000202000000000,
0x0020000000000000, 0x0020002000000000, 0x0020200000000000, 0x0020202000000000,
0x2000000000000000, 0x2000002000000000, 0x2000200000000000, 0x2000202000000000,
0x2020000000000000, 0x2020002000000000, 0x2020200000000000, 0x2020202000000000, ),
( 0x0000000000000000, 0x0000000200000000, 0x0000020000000000, 0x0000020200000000,
0x0002000000000000, 0x0002000200000000, 0x0002020000000000, 0x0002020200000000,
0x0200000000000000, 0x0200000200000000, 0x0200020000000000, 0x0200020200000000,
0x0202000000000000, 0x0202000200000000, 0x0202020000000000, 0x0202020200000000, ),
( 0x0000000000000000, 0x0000000000000020, 0x0000000000002000, 0x0000000000002020,
0x0000000000200000, 0x0000000000200020, 0x0000000000202000, 0x0000000000202020,
0x0000000020000000, 0x0000000020000020, 0x0000000020002000, 0x0000000020002020,
0x0000000020200000, 0x0000000020200020, 0x0000000020202000, 0x0000000020202020, ),
( 0x0000000000000000, 0x0000000000000002, 0x0000000000000200, 0x0000000000000202,
0x0000000000020000, 0x0000000000020002, 0x0000000000020200, 0x0000000000020202,
0x0000000002000000, 0x0000000002000002, 0x0000000002000200, 0x0000000002000202,
0x0000000002020000, 0x0000000002020002, 0x0000000002020200, 0x0000000002020202, ),
( 0x0000000000000000, 0x0000008000000000, 0x0000800000000000, 0x0000808000000000,
0x0080000000000000, 0x0080008000000000, 0x0080800000000000, 0x0080808000000000,
0x8000000000000000, 0x8000008000000000, 0x8000800000000000, 0x8000808000000000,
0x8080000000000000, 0x8080008000000000, 0x8080800000000000, 0x8080808000000000, ),
( 0x0000000000000000, 0x0000000800000000, 0x0000080000000000, 0x0000080800000000,
0x0008000000000000, 0x0008000800000000, 0x0008080000000000, 0x0008080800000000,
0x0800000000000000, 0x0800000800000000, 0x0800080000000000, 0x0800080800000000,
0x0808000000000000, 0x0808000800000000, 0x0808080000000000, 0x0808080800000000, ),
( 0x0000000000000000, 0x0000000000000080, 0x0000000000008000, 0x0000000000008080,
0x0000000000800000, 0x0000000000800080, 0x0000000000808000, 0x0000000000808080,
0x0000000080000000, 0x0000000080000080, 0x0000000080008000, 0x0000000080008080,
0x0000000080800000, 0x0000000080800080, 0x0000000080808000, 0x0000000080808080, ),
( 0x0000000000000000, 0x0000000000000008, 0x0000000000000800, 0x0000000000000808,
0x0000000000080000, 0x0000000000080008, 0x0000000000080800, 0x0000000000080808,
0x0000000008000000, 0x0000000008000008, 0x0000000008000800, 0x0000000008000808,
0x0000000008080000, 0x0000000008080008, 0x0000000008080800, 0x0000000008080808, ),
( 0x0000000000000000, 0x0000001000000000, 0x0000100000000000, 0x0000101000000000,
0x0010000000000000, 0x0010001000000000, 0x0010100000000000, 0x0010101000000000,
0x1000000000000000, 0x1000001000000000, 0x1000100000000000, 0x1000101000000000,
0x1010000000000000, 0x1010001000000000, 0x1010100000000000, 0x1010101000000000, ),
( 0x0000000000000000, 0x0000000100000000, 0x0000010000000000, 0x0000010100000000,
0x0001000000000000, 0x0001000100000000, 0x0001010000000000, 0x0001010100000000,
0x0100000000000000, 0x0100000100000000, 0x0100010000000000, 0x0100010100000000,
0x0101000000000000, 0x0101000100000000, 0x0101010000000000, 0x0101010100000000, ),
( 0x0000000000000000, 0x0000000000000010, 0x0000000000001000, 0x0000000000001010,
0x0000000000100000, 0x0000000000100010, 0x0000000000101000, 0x0000000000101010,
0x0000000010000000, 0x0000000010000010, 0x0000000010001000, 0x0000000010001010,
0x0000000010100000, 0x0000000010100010, 0x0000000010101000, 0x0000000010101010, ),
( 0x0000000000000000, 0x0000000000000001, 0x0000000000000100, 0x0000000000000101,
0x0000000000010000, 0x0000000000010001, 0x0000000000010100, 0x0000000000010101,
0x0000000001000000, 0x0000000001000001, 0x0000000001000100, 0x0000000001000101,
0x0000000001010000, 0x0000000001010001, 0x0000000001010100, 0x0000000001010101, ),
( 0x0000000000000000, 0x0000004000000000, 0x0000400000000000, 0x0000404000000000,
0x0040000000000000, 0x0040004000000000, 0x0040400000000000, 0x0040404000000000,
0x4000000000000000, 0x4000004000000000, 0x4000400000000000, 0x4000404000000000,
0x4040000000000000, 0x4040004000000000, 0x4040400000000000, 0x4040404000000000, ),
( 0x0000000000000000, 0x0000000400000000, 0x0000040000000000, 0x0000040400000000,
0x0004000000000000, 0x0004000400000000, 0x0004040000000000, 0x0004040400000000,
0x0400000000000000, 0x0400000400000000, 0x0400040000000000, 0x0400040400000000,
0x0404000000000000, 0x0404000400000000, 0x0404040000000000, 0x0404040400000000, ),
( 0x0000000000000000, 0x0000000000000040, 0x0000000000004000, 0x0000000000004040,
0x0000000000400000, 0x0000000000400040, 0x0000000000404000, 0x0000000000404040,
0x0000000040000000, 0x0000000040000040, 0x0000000040004000, 0x0000000040004040,
0x0000000040400000, 0x0000000040400040, 0x0000000040404000, 0x0000000040404040, ),
( 0x0000000000000000, 0x0000000000000004, 0x0000000000000400, 0x0000000000000404,
0x0000000000040000, 0x0000000000040004, 0x0000000000040400, 0x0000000000040404,
0x0000000004000000, 0x0000000004000004, 0x0000000004000400, 0x0000000004000404,
0x0000000004040000, 0x0000000004040004, 0x0000000004040400, 0x0000000004040404, ),
)
#===================================================================
# eof _load_tables()
#===================================================================
#=============================================================================
# support
#=============================================================================
def _permute(c, p):
"""Returns the permutation of the given 32-bit or 64-bit code with
the specified permutation table."""
# NOTE: only difference between 32 & 64 bit permutations
# is that len(p)==8 for 32 bit, and len(p)==16 for 64 bit.
out = 0
for r in p:
out |= r[c&0xf]
c >>= 4
return out
#=============================================================================
# packing & unpacking
#=============================================================================
_uint64_struct = struct.Struct(">Q")
_BNULL = b('\x00')
def _pack64(value):
return _uint64_struct.pack(value)
def _unpack64(value):
return _uint64_struct.unpack(value)[0]
def _pack56(value):
return _uint64_struct.pack(value)[1:]
def _unpack56(value):
return _uint64_struct.unpack(_BNULL+value)[0]
#=============================================================================
# 56->64 key manipulation
#=============================================================================
##def expand_7bit(value):
## "expand 7-bit integer => 7-bits + 1 odd-parity bit"
## # parity calc adapted from 32-bit even parity alg found at
## # http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
## assert 0 <= value < 0x80, "value out of range"
## return (value<<1) | (0x9669 >> ((value ^ (value >> 4)) & 0xf)) & 1
_EXPAND_ITER = irange(49,-7,-7)
def expand_des_key(key):
"""convert DES from 7 bytes to 8 bytes (by inserting empty parity bits)"""
if isinstance(key, bytes):
if len(key) != 7:
raise ValueError("key must be 7 bytes in size")
elif isinstance(key, int_types):
if key < 0 or key > INT_56_MASK:
raise ValueError("key must be 56-bit non-negative integer")
return _unpack64(expand_des_key(_pack56(key)))
else:
raise exc.ExpectedTypeError(key, "bytes or int", "key")
key = _unpack56(key)
# NOTE: the following would insert correctly-valued parity bits in each key,
# but the parity bit would just be ignored in des_encrypt_block(),
# so not bothering to use it.
##return join_byte_values(expand_7bit((key >> shift) & 0x7f)
## for shift in _EXPAND_ITER)
return join_byte_values(((key>>shift) & 0x7f)<<1 for shift in _EXPAND_ITER)
def shrink_des_key(key):
"""convert DES key from 8 bytes to 7 bytes (by discarding the parity bits)"""
if isinstance(key, bytes):
if len(key) != 8:
raise ValueError("key must be 8 bytes in size")
return _pack56(shrink_des_key(_unpack64(key)))
elif isinstance(key, int_types):
if key < 0 or key > INT_64_MASK:
raise ValueError("key must be 64-bit non-negative integer")
else:
raise exc.ExpectedTypeError(key, "bytes or int", "key")
key >>= 1
result = 0
offset = 0
while offset < 56:
result |= (key & 0x7f)<<offset
key >>= 8
offset += 7
assert not (result & ~INT_64_MASK)
return result
#=============================================================================
# des encryption
#=============================================================================
def des_encrypt_block(key, input, salt=0, rounds=1):
"""encrypt single block of data using DES, operates on 8-byte strings.
:arg key:
DES key as 7 byte string, or 8 byte string with parity bits
(parity bit values are ignored).
:arg input:
plaintext block to encrypt, as 8 byte string.
:arg salt:
Optional 24-bit integer used to mutate the base DES algorithm in a
manner specific to :class:`~passlib.hash.des_crypt` and its variants.
The default value ``0`` provides the normal (unsalted) DES behavior.
The salt functions as follows:
if the ``i``'th bit of ``salt`` is set,
bits ``i`` and ``i+24`` are swapped in the DES E-box output.
:arg rounds:
Optional number of rounds of to apply the DES key schedule.
the default (``rounds=1``) provides the normal DES behavior,
but :class:`~passlib.hash.des_crypt` and its variants use
alternate rounds values.
:raises TypeError: if any of the provided args are of the wrong type.
:raises ValueError:
if any of the input blocks are the wrong size,
or the salt/rounds values are out of range.
:returns:
resulting 8-byte ciphertext block.
"""
# validate & unpack key
if isinstance(key, bytes):
if len(key) == 7:
key = expand_des_key(key)
elif len(key) != 8:
raise ValueError("key must be 7 or 8 bytes")
key = _unpack64(key)
else:
raise exc.ExpectedTypeError(key, "bytes", "key")
# validate & unpack input
if isinstance(input, bytes):
if len(input) != 8:
raise ValueError("input block must be 8 bytes")
input = _unpack64(input)
else:
raise exc.ExpectedTypeError(input, "bytes", "input")
# hand things off to other func
result = des_encrypt_int_block(key, input, salt, rounds)
# repack result
return _pack64(result)
def des_encrypt_int_block(key, input, salt=0, rounds=1):
"""encrypt single block of data using DES, operates on 64-bit integers.
this function is essentially the same as :func:`des_encrypt_block`,
except that it operates on integers, and will NOT automatically
expand 56-bit keys if provided (since there's no way to detect them).
:arg key:
DES key as 64-bit integer (the parity bits are ignored).
:arg input:
input block as 64-bit integer
:arg salt:
optional 24-bit integer used to mutate the base DES algorithm.
defaults to ``0`` (no mutation applied).
:arg rounds:
optional number of rounds of to apply the DES key schedule.
defaults to ``1``.
:raises TypeError: if any of the provided args are of the wrong type.
:raises ValueError:
if any of the input blocks are the wrong size,
or the salt/rounds values are out of range.
:returns:
resulting ciphertext as 64-bit integer.
"""
#---------------------------------------------------------------
# input validation
#---------------------------------------------------------------
# validate salt, rounds
if rounds < 1:
raise ValueError("rounds must be positive integer")
if salt < 0 or salt > INT_24_MASK:
raise ValueError("salt must be 24-bit non-negative integer")
# validate & unpack key
if not isinstance(key, int_types):
raise exc.ExpectedTypeError(key, "int", "key")
elif key < 0 or key > INT_64_MASK:
raise ValueError("key must be 64-bit non-negative integer")
# validate & unpack input
if not isinstance(input, int_types):
raise exc.ExpectedTypeError(input, "int", "input")
elif input < 0 or input > INT_64_MASK:
raise ValueError("input must be 64-bit non-negative integer")
#---------------------------------------------------------------
# DES setup
#---------------------------------------------------------------
# load tables if not already done
global SPE, PCXROT, IE3264, CF6464
if PCXROT is None:
_load_tables()
# load SPE into local vars to speed things up and remove an array access call
SPE0, SPE1, SPE2, SPE3, SPE4, SPE5, SPE6, SPE7 = SPE
# NOTE: parity bits are ignored completely
# (UTs do fuzz testing to ensure this)
# generate key schedule
# NOTE: generation was modified to output two elements at a time,
# so that per-round loop could do two passes at once.
def _iter_key_schedule(ks_odd):
"""given 64-bit key, iterates over the 8 (even,odd) key schedule pairs"""
for p_even, p_odd in PCXROT:
ks_even = _permute(ks_odd, p_even)
ks_odd = _permute(ks_even, p_odd)
yield ks_even & _KS_MASK, ks_odd & _KS_MASK
ks_list = list(_iter_key_schedule(key))
# expand 24 bit salt -> 32 bit per des_crypt & bsdi_crypt
salt = (
((salt & 0x00003f) << 26) |
((salt & 0x000fc0) << 12) |
((salt & 0x03f000) >> 2) |
((salt & 0xfc0000) >> 16)
)
# init L & R
if input == 0:
L = R = 0
else:
L = ((input >> 31) & 0xaaaaaaaa) | (input & 0x55555555)
L = _permute(L, IE3264)
R = ((input >> 32) & 0xaaaaaaaa) | ((input >> 1) & 0x55555555)
R = _permute(R, IE3264)
#---------------------------------------------------------------
# main DES loop - run for specified number of rounds
#---------------------------------------------------------------
while rounds:
rounds -= 1
# run over each part of the schedule, 2 parts at a time
for ks_even, ks_odd in ks_list:
k = ((R>>32) ^ R) & salt # use the salt to flip specific bits
B = (k<<32) ^ k ^ R ^ ks_even
L ^= (SPE0[(B>>58)&0x3f] ^ SPE1[(B>>50)&0x3f] ^
SPE2[(B>>42)&0x3f] ^ SPE3[(B>>34)&0x3f] ^
SPE4[(B>>26)&0x3f] ^ SPE5[(B>>18)&0x3f] ^
SPE6[(B>>10)&0x3f] ^ SPE7[(B>>2)&0x3f])
k = ((L>>32) ^ L) & salt # use the salt to flip specific bits
B = (k<<32) ^ k ^ L ^ ks_odd
R ^= (SPE0[(B>>58)&0x3f] ^ SPE1[(B>>50)&0x3f] ^
SPE2[(B>>42)&0x3f] ^ SPE3[(B>>34)&0x3f] ^
SPE4[(B>>26)&0x3f] ^ SPE5[(B>>18)&0x3f] ^
SPE6[(B>>10)&0x3f] ^ SPE7[(B>>2)&0x3f])
# swap L and R
L, R = R, L
#---------------------------------------------------------------
# return final result
#---------------------------------------------------------------
C = (
((L>>3) & 0x0f0f0f0f00000000)
|
((L<<33) & 0xf0f0f0f000000000)
|
((R>>35) & 0x000000000f0f0f0f)
|
((R<<1) & 0x00000000f0f0f0f0)
)
return _permute(C, CF6464)
@deprecated_function(deprecated="1.6", removed="1.8",
replacement="des_encrypt_int_block()")
def mdes_encrypt_int_block(key, input, salt=0, rounds=1): # pragma: no cover -- deprecated & unused
if isinstance(key, bytes):
if len(key) == 7:
key = expand_des_key(key)
key = _unpack64(key)
return des_encrypt_int_block(key, input, salt, rounds)
#=============================================================================
# eof
#=============================================================================

File diff suppressed because it is too large Load Diff

266
src/passlib/utils/md4.py Normal file
View File

@@ -0,0 +1,266 @@
"""
helper implementing insecure and obsolete md4 algorithm.
used for NTHASH format, which is also insecure and broken,
since it's just md4(password)
implementated based on rfc at http://www.faqs.org/rfcs/rfc1320.html
"""
#=============================================================================
# imports
#=============================================================================
# core
from binascii import hexlify
import struct
from warnings import warn
# site
from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY3
# local
__all__ = [ "md4" ]
#=============================================================================
# utils
#=============================================================================
def F(x,y,z):
return (x&y) | ((~x) & z)
def G(x,y,z):
return (x&y) | (x&z) | (y&z)
##def H(x,y,z):
## return x ^ y ^ z
MASK_32 = 2**32-1
#=============================================================================
# main class
#=============================================================================
class md4(object):
"""pep-247 compatible implementation of MD4 hash algorithm
.. attribute:: digest_size
size of md4 digest in bytes (16 bytes)
.. method:: update
update digest by appending additional content
.. method:: copy
create clone of digest object, including current state
.. method:: digest
return bytes representing md4 digest of current content
.. method:: hexdigest
return hexadecimal version of digest
"""
# FIXME: make this follow hash object PEP better.
# FIXME: this isn't threadsafe
# XXX: should we monkeypatch ourselves into hashlib for general use? probably wouldn't be nice.
name = "md4"
digest_size = digestsize = 16
_count = 0 # number of 64-byte blocks processed so far (not including _buf)
_state = None # list of [a,b,c,d] 32 bit ints used as internal register
_buf = None # data processed in 64 byte blocks, this holds leftover from last update
def __init__(self, content=None):
self._count = 0
self._state = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
self._buf = b('')
if content:
self.update(content)
# round 1 table - [abcd k s]
_round1 = [
[0,1,2,3, 0,3],
[3,0,1,2, 1,7],
[2,3,0,1, 2,11],
[1,2,3,0, 3,19],
[0,1,2,3, 4,3],
[3,0,1,2, 5,7],
[2,3,0,1, 6,11],
[1,2,3,0, 7,19],
[0,1,2,3, 8,3],
[3,0,1,2, 9,7],
[2,3,0,1, 10,11],
[1,2,3,0, 11,19],
[0,1,2,3, 12,3],
[3,0,1,2, 13,7],
[2,3,0,1, 14,11],
[1,2,3,0, 15,19],
]
# round 2 table - [abcd k s]
_round2 = [
[0,1,2,3, 0,3],
[3,0,1,2, 4,5],
[2,3,0,1, 8,9],
[1,2,3,0, 12,13],
[0,1,2,3, 1,3],
[3,0,1,2, 5,5],
[2,3,0,1, 9,9],
[1,2,3,0, 13,13],
[0,1,2,3, 2,3],
[3,0,1,2, 6,5],
[2,3,0,1, 10,9],
[1,2,3,0, 14,13],
[0,1,2,3, 3,3],
[3,0,1,2, 7,5],
[2,3,0,1, 11,9],
[1,2,3,0, 15,13],
]
# round 3 table - [abcd k s]
_round3 = [
[0,1,2,3, 0,3],
[3,0,1,2, 8,9],
[2,3,0,1, 4,11],
[1,2,3,0, 12,15],
[0,1,2,3, 2,3],
[3,0,1,2, 10,9],
[2,3,0,1, 6,11],
[1,2,3,0, 14,15],
[0,1,2,3, 1,3],
[3,0,1,2, 9,9],
[2,3,0,1, 5,11],
[1,2,3,0, 13,15],
[0,1,2,3, 3,3],
[3,0,1,2, 11,9],
[2,3,0,1, 7,11],
[1,2,3,0, 15,15],
]
def _process(self, block):
"""process 64 byte block"""
# unpack block into 16 32-bit ints
X = struct.unpack("<16I", block)
# clone state
orig = self._state
state = list(orig)
# round 1 - F function - (x&y)|(~x & z)
for a,b,c,d,k,s in self._round1:
t = (state[a] + F(state[b],state[c],state[d]) + X[k]) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
# round 2 - G function
for a,b,c,d,k,s in self._round2:
t = (state[a] + G(state[b],state[c],state[d]) + X[k] + 0x5a827999) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
# round 3 - H function - x ^ y ^ z
for a,b,c,d,k,s in self._round3:
t = (state[a] + (state[b] ^ state[c] ^ state[d]) + X[k] + 0x6ed9eba1) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
# add back into original state
for i in irange(4):
orig[i] = (orig[i]+state[i]) & MASK_32
def update(self, content):
if not isinstance(content, bytes):
raise TypeError("expected bytes")
buf = self._buf
if buf:
content = buf + content
idx = 0
end = len(content)
while True:
next = idx + 64
if next <= end:
self._process(content[idx:next])
self._count += 1
idx = next
else:
self._buf = content[idx:]
return
def copy(self):
other = _builtin_md4()
other._count = self._count
other._state = list(self._state)
other._buf = self._buf
return other
def digest(self):
# NOTE: backing up state so we can restore it after _process is called,
# in case object is updated again (this is only attr altered by this method)
orig = list(self._state)
# final block: buf + 0x80,
# then 0x00 padding until congruent w/ 56 mod 64 bytes
# then last 8 bytes = msg length in bits
buf = self._buf
msglen = self._count*512 + len(buf)*8
block = buf + b('\x80') + b('\x00') * ((119-len(buf)) % 64) + \
struct.pack("<2I", msglen & MASK_32, (msglen>>32) & MASK_32)
if len(block) == 128:
self._process(block[:64])
self._process(block[64:])
else:
assert len(block) == 64
self._process(block)
# render digest & restore un-finalized state
out = struct.pack("<4I", *self._state)
self._state = orig
return out
def hexdigest(self):
return bascii_to_str(hexlify(self.digest()))
#===================================================================
# eoc
#===================================================================
# keep ref around for unittest, 'md4' usually replaced by ssl wrapper, below.
_builtin_md4 = md4
#=============================================================================
# check if hashlib provides accelarated md4
#=============================================================================
import hashlib
from passlib.utils import PYPY
def _has_native_md4(): # pragma: no cover -- runtime detection
try:
h = hashlib.new("md4")
except ValueError:
# not supported - ssl probably missing (e.g. ironpython)
return False
result = h.hexdigest()
if result == '31d6cfe0d16ae931b73c59d7e0c089c0':
return True
if PYPY and result == '':
# workaround for https://bugs.pypy.org/issue957, fixed in PyPy 1.8
return False
# anything else and we should alert user
from passlib.exc import PasslibRuntimeWarning
warn("native md4 support disabled, sanity check failed!", PasslibRuntimeWarning)
return False
if _has_native_md4():
# overwrite md4 class w/ hashlib wrapper
def md4(content=None):
"""wrapper for hashlib.new('md4')"""
return hashlib.new('md4', content or b(''))
#=============================================================================
# eof
#=============================================================================

415
src/passlib/utils/pbkdf2.py Normal file
View File

@@ -0,0 +1,415 @@
"""passlib.pbkdf2 - PBKDF2 support
this module is getting increasingly poorly named.
maybe rename to "kdf" since it's getting more key derivation functions added.
"""
#=============================================================================
# imports
#=============================================================================
# core
import hashlib
import logging; log = logging.getLogger(__name__)
import re
from struct import pack
from warnings import warn
# site
try:
from M2Crypto import EVP as _EVP
except ImportError:
_EVP = None
# pkg
from passlib.exc import PasslibRuntimeWarning, ExpectedTypeError
from passlib.utils import join_bytes, to_native_str, bytes_to_int, int_to_bytes, join_byte_values
from passlib.utils.compat import b, bytes, BytesIO, irange, callable, int_types
# local
__all__ = [
"get_prf",
"pbkdf1",
"pbkdf2",
]
#=============================================================================
# hash helpers
#=============================================================================
# known hash names
_nhn_formats = dict(hashlib=0, iana=1)
_nhn_hash_names = [
# (hashlib/ssl name, iana name or standin, ... other known aliases)
# hashes with official IANA-assigned names
# (as of 2012-03 - http://www.iana.org/assignments/hash-function-text-names)
("md2", "md2"),
("md5", "md5"),
("sha1", "sha-1"),
("sha224", "sha-224", "sha2-224"),
("sha256", "sha-256", "sha2-256"),
("sha384", "sha-384", "sha2-384"),
("sha512", "sha-512", "sha2-512"),
# hashlib/ssl-supported hashes without official IANA names,
# hopefully compatible stand-ins have been chosen.
("md4", "md4"),
("sha", "sha-0", "sha0"),
("ripemd", "ripemd"),
("ripemd160", "ripemd-160"),
]
# cache for norm_hash_name()
_nhn_cache = {}
def norm_hash_name(name, format="hashlib"):
"""Normalize hash function name
:arg name:
Original hash function name.
This name can be a Python :mod:`~hashlib` digest name,
a SCRAM mechanism name, IANA assigned hash name, etc.
Case is ignored, and underscores are converted to hyphens.
:param format:
Naming convention to normalize to.
Possible values are:
* ``"hashlib"`` (the default) - normalizes name to be compatible
with Python's :mod:`!hashlib`.
* ``"iana"`` - normalizes name to IANA-assigned hash function name.
for hashes which IANA hasn't assigned a name for, issues a warning,
and then uses a heuristic to give a "best guess".
:returns:
Hash name, returned as native :class:`!str`.
"""
# check cache
try:
idx = _nhn_formats[format]
except KeyError:
raise ValueError("unknown format: %r" % (format,))
try:
return _nhn_cache[name][idx]
except KeyError:
pass
orig = name
# normalize input
if not isinstance(name, str):
name = to_native_str(name, 'utf-8', 'hash name')
name = re.sub("[_ /]", "-", name.strip().lower())
if name.startswith("scram-"):
name = name[6:]
if name.endswith("-plus"):
name = name[:-5]
# look through standard names and known aliases
def check_table(name):
for row in _nhn_hash_names:
if name in row:
_nhn_cache[orig] = row
return row[idx]
result = check_table(name)
if result:
return result
# try to clean name up, and recheck table
m = re.match("^(?P<name>[a-z]+)-?(?P<rev>\d)?-?(?P<size>\d{3,4})?$", name)
if m:
name, rev, size = m.group("name", "rev", "size")
if rev:
name += rev
if size:
name += "-" + size
result = check_table(name)
if result:
return result
# else we've done what we can
warn("norm_hash_name(): unknown hash: %r" % (orig,), PasslibRuntimeWarning)
name2 = name.replace("-", "")
row = _nhn_cache[orig] = (name2, name)
return row[idx]
# TODO: get_hash() func which wraps norm_hash_name(), hashlib.<attr>, and hashlib.new
#=============================================================================
# general prf lookup
#=============================================================================
_BNULL = b('\x00')
_XY_DIGEST = b(',\x1cb\xe0H\xa5\x82M\xfb>\xd6\x98\xef\x8e\xf9oQ\x85\xa3i')
_trans_5C = join_byte_values((x ^ 0x5C) for x in irange(256))
_trans_36 = join_byte_values((x ^ 0x36) for x in irange(256))
def _get_hmac_prf(digest):
"""helper to return HMAC prf for specific digest"""
def tag_wrapper(prf):
prf.__name__ = "hmac_" + digest
prf.__doc__ = ("hmac_%s(key, msg) -> digest;"
" generated by passlib.utils.pbkdf2.get_prf()" %
digest)
if _EVP and digest == "sha1":
# use m2crypto function directly for sha1, since that's its default digest
try:
result = _EVP.hmac(b('x'),b('y'))
except ValueError: # pragma: no cover
pass
else:
if result == _XY_DIGEST:
return _EVP.hmac, 20
# don't expect to ever get here, but will fall back to pure-python if we do.
warn("M2Crypto.EVP.HMAC() returned unexpected result " # pragma: no cover -- sanity check
"during Passlib self-test!", PasslibRuntimeWarning)
elif _EVP:
# use m2crypto if it's present and supports requested digest
try:
result = _EVP.hmac(b('x'), b('y'), digest)
except ValueError:
pass
else:
# it does. so use M2Crypto's hmac & digest code
hmac_const = _EVP.hmac
def prf(key, msg):
return hmac_const(key, msg, digest)
digest_size = len(result)
tag_wrapper(prf)
return prf, digest_size
# fall back to hashlib-based implementation
digest_const = getattr(hashlib, digest, None)
if not digest_const:
raise ValueError("unknown hash algorithm: %r" % (digest,))
tmp = digest_const()
block_size = tmp.block_size
assert block_size >= 16, "unacceptably low block size"
digest_size = tmp.digest_size
del tmp
def prf(key, msg):
# simplified version of stdlib's hmac module
if len(key) > block_size:
key = digest_const(key).digest()
key += _BNULL * (block_size - len(key))
tmp = digest_const(key.translate(_trans_36) + msg).digest()
return digest_const(key.translate(_trans_5C) + tmp).digest()
tag_wrapper(prf)
return prf, digest_size
# cache mapping prf name/func -> (func, digest_size)
_prf_cache = {}
def _clear_prf_cache():
"""helper for unit tests"""
_prf_cache.clear()
def get_prf(name):
"""lookup pseudo-random family (prf) by name.
:arg name:
this must be the name of a recognized prf.
currently this only recognizes names with the format
:samp:`hmac-{digest}`, where :samp:`{digest}`
is the name of a hash function such as
``md5``, ``sha256``, etc.
this can also be a callable with the signature
``prf(secret, message) -> digest``,
in which case it will be returned unchanged.
:raises ValueError: if the name is not known
:raises TypeError: if the name is not a callable or string
:returns:
a tuple of :samp:`({func}, {digest_size})`.
* :samp:`{func}` is a function implementing
the specified prf, and has the signature
``func(secret, message) -> digest``.
* :samp:`{digest_size}` is an integer indicating
the number of bytes the function returns.
usage example::
>>> from passlib.utils.pbkdf2 import get_prf
>>> hmac_sha256, dsize = get_prf("hmac-sha256")
>>> hmac_sha256
<function hmac_sha256 at 0x1e37c80>
>>> dsize
32
>>> digest = hmac_sha256('password', 'message')
this function will attempt to return the fastest implementation
it can find; if M2Crypto is present, and supports the specified prf,
:func:`M2Crypto.EVP.hmac` will be used behind the scenes.
"""
global _prf_cache
if name in _prf_cache:
return _prf_cache[name]
if isinstance(name, str):
if name.startswith("hmac-") or name.startswith("hmac_"):
retval = _get_hmac_prf(name[5:])
else:
raise ValueError("unknown prf algorithm: %r" % (name,))
elif callable(name):
# assume it's a callable, use it directly
digest_size = len(name(b('x'),b('y')))
retval = (name, digest_size)
else:
raise ExpectedTypeError(name, "str or callable", "prf name")
_prf_cache[name] = retval
return retval
#=============================================================================
# pbkdf1 support
#=============================================================================
def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
"""pkcs#5 password-based key derivation v1.5
:arg secret: passphrase to use to generate key
:arg salt: salt string to use when generating key
:param rounds: number of rounds to use to generate key
:arg keylen: number of bytes to generate (if ``None``, uses digest's native size)
:param hash:
hash function to use. must be name of a hash recognized by hashlib.
:returns:
raw bytes of generated key
.. note::
This algorithm has been deprecated, new code should use PBKDF2.
Among other limitations, ``keylen`` cannot be larger
than the digest size of the specified hash.
"""
# validate secret & salt
if not isinstance(secret, bytes):
raise ExpectedTypeError(secret, "bytes", "secret")
if not isinstance(salt, bytes):
raise ExpectedTypeError(salt, "bytes", "salt")
# validate rounds
if not isinstance(rounds, int_types):
raise ExpectedTypeError(rounds, "int", "rounds")
if rounds < 1:
raise ValueError("rounds must be at least 1")
# resolve hash
try:
hash_const = getattr(hashlib, hash)
except AttributeError:
# check for ssl hash
# NOTE: if hash unknown, new() will throw ValueError, which we'd just
# reraise anyways; so instead of checking, we just let it get
# thrown during first use, below
# TODO: use builtin md4 class if hashlib doesn't have it.
def hash_const(msg):
return hashlib.new(hash, msg)
# prime pbkdf1 loop, get block size
block = hash_const(secret + salt).digest()
# validate keylen
if keylen is None:
keylen = len(block)
elif not isinstance(keylen, int_types):
raise ExpectedTypeError(keylen, "int or None", "keylen")
elif keylen < 0:
raise ValueError("keylen must be at least 0")
elif keylen > len(block):
raise ValueError("keylength too large for digest: %r > %r" %
(keylen, len(block)))
# main pbkdf1 loop
for _ in irange(rounds-1):
block = hash_const(block).digest()
return block[:keylen]
#=============================================================================
# pbkdf2
#=============================================================================
MAX_BLOCKS = 0xffffffff # 2**32-1
MAX_HMAC_SHA1_KEYLEN = MAX_BLOCKS*20
# NOTE: the pbkdf2 spec does not specify a maximum number of rounds.
# however, many of the hashes in passlib are currently clamped
# at the 32-bit limit, just for sanity. once realistic pbkdf2 rounds
# start approaching 24 bits, this limit will be raised.
def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
"""pkcs#5 password-based key derivation v2.0
:arg secret: passphrase to use to generate key
:arg salt: salt string to use when generating key
:param rounds: number of rounds to use to generate key
:arg keylen:
number of bytes to generate.
if set to ``None``, will use digest size of selected prf.
:param prf:
psuedo-random family to use for key strengthening.
this can be any string or callable accepted by :func:`get_prf`.
this defaults to ``"hmac-sha1"`` (the only prf explicitly listed in
the PBKDF2 specification)
:returns:
raw bytes of generated key
"""
# validate secret & salt
if not isinstance(secret, bytes):
raise ExpectedTypeError(secret, "bytes", "secret")
if not isinstance(salt, bytes):
raise ExpectedTypeError(salt, "bytes", "salt")
# validate rounds
if not isinstance(rounds, int_types):
raise ExpectedTypeError(rounds, "int", "rounds")
if rounds < 1:
raise ValueError("rounds must be at least 1")
# validate keylen
if keylen is not None:
if not isinstance(keylen, int_types):
raise ExpectedTypeError(keylen, "int or None", "keylen")
elif keylen < 0:
raise ValueError("keylen must be at least 0")
# special case for m2crypto + hmac-sha1
if prf == "hmac-sha1" and _EVP:
if keylen is None:
keylen = 20
# NOTE: doing check here, because M2crypto won't take 'long' instances
# (which this is when running under 32bit)
if keylen > MAX_HMAC_SHA1_KEYLEN:
raise ValueError("key length too long for digest")
# NOTE: as of 2012-4-4, m2crypto has buffer overflow issue
# which may cause segfaults if keylen > 32 (EVP_MAX_KEY_LENGTH).
# therefore we're avoiding m2crypto for large keys until that's fixed.
# see https://bugzilla.osafoundation.org/show_bug.cgi?id=13052
if keylen < 32:
return _EVP.pbkdf2(secret, salt, rounds, keylen)
# resolve prf
prf_func, digest_size = get_prf(prf)
if keylen is None:
keylen = digest_size
# figure out how many blocks we'll need
block_count = (keylen+digest_size-1)//digest_size
if block_count >= MAX_BLOCKS:
raise ValueError("key length too long for digest")
# build up result from blocks
def gen():
for i in irange(block_count):
digest = prf_func(secret, salt + pack(">L", i+1))
accum = bytes_to_int(digest)
for _ in irange(rounds-1):
digest = prf_func(secret, digest)
accum ^= bytes_to_int(digest)
yield int_to_bytes(accum, digest_size)
return join_bytes(gen())[:keylen]
#=============================================================================
# eof
#=============================================================================