def parse_p_bitstring(self, msg): # type: (six.binary_type) -> six.binary_type unused = bord(msg[0]) r = b"".join(BITSTING[bord(c)] for c in msg) if unused: r = r[:-unused] return r
def md5crypt(password, salt=None, magic=b"$1$"): # type: (bytes, Optional[bytes], bytes) -> bytes """ MD5 password hash (Used for RIPE authentication) >>> md5crypt("test", salt="1234") '$1$1234$InX9CGnHSFgHD3OZHTyt3.' >>> md5crypt("test", salt="1234") '$1$1234$InX9CGnHSFgHD3OZHTyt3.' >>> md5crypt("test", salt="1234", magic="$5$") '$5$1234$x29w4cwzSDnesjss/m2O1.' """ password = smart_bytes(password) magic = smart_bytes(magic) salt = smart_bytes(salt) if salt else gen_salt(8) # /* The password first, since that is what is most unknown */ /* Then our magic string */ /* Then the raw salt */ m = hashlib.md5(smart_bytes(password + magic + salt)) # /* Then just as many characters of the MD5(pw,salt,pw) */ mixin = hashlib.md5(smart_bytes(password + salt + password)).digest() for i in range(len(password)): m.update(bchr(mixin[i % 16])) # /* Then something really weird... */ # Also really broken, as far as I can tell. -m i = len(password) while i: if i & 1: m.update(b"\x00") else: m.update(bchr(password[0])) i >>= 1 final = m.digest() # /* and now, just to make sure things don't run too fast */ for i in range(1000): m2 = hashlib.md5() if i & 1: m2.update(smart_bytes(password)) else: m2.update(smart_bytes(final)) if i % 3: m2.update(smart_bytes(salt)) if i % 7: m2.update(smart_bytes(password)) if i & 1: m2.update(smart_bytes(final)) else: m2.update(smart_bytes(password)) final = m2.digest() # This is the bit that uses to64() in the original code. rearranged = [] for a, b, c in REARRANGED_BITS: v = bord(final[a]) << 16 | bord(final[b]) << 8 | bord(final[c]) for i in range(4): rearranged += [ITOA64[v & 0x3F]] v >>= 6 v = bord(final[11]) for i in range(2): rearranged += [ITOA64[v & 0x3F]] v >>= 6 return magic + salt + b"$" + make_bytes(rearranged)
def feed(self, chunk): # type: (six.binary_type) -> six.binary_type """ Feed chunk of data to parser :param chunk: String :return: Parsed data """ if self.iac_seq and chunk: # Restore incomplete IAC context chunk = self.iac_seq + chunk self.iac_seq = b"" r = [] # type: List[six.binary_type] while chunk: left, seq, right = chunk.partition(B_IAC) # Pass clear part r += [left] # Process control sequences if seq: # Process IAC sequence if not right or len(right) == 1: # Incomplete sequence # Collect for next round self.iac_seq = B_IAC + right break ctl = bord(right[0]) if ctl == IAC: # <IAC> <IAC> leads to single <IAC> r += [B_IAC] chunk = right[1:] elif ctl in IGNORED_CMD: # Ignore command chunk = right[1:] elif ctl != SB: # Process IAC <cmd> <opt> self.process_iac(ctl, bord(right[1])) chunk = right[2:] else: # Process IAC SB ... SE sequence # @todo: Use .partition() if B_SE not in right: self.iac_seq = B_IAC + right break i = right.index(B_SE) self.process_iac_sb(right[1:i - 1]) chunk = right[i + 1:] else: # Return leftovers break if self.out_iac_seq: out_seq = b"".join(self.out_iac_seq) self.writer(out_seq) self.out_iac_seq = [] return b"".join(r)
def parse_compressed_oid(self, msg): # type: (bytes) -> six.text_type """ :param msg: :return: """ pos = bord(msg[0]) - 1 parts = self.last_oid.split(".")[:pos] + [ str(bord(d)) for d in msg[1:] ] self.last_oid = ".".join(parts) return smart_text(self.last_oid)
def encode_int(self, data): """ >>> BEREncoder().encode_int(0) '\\x02\\x01\\x00' >>> BEREncoder().encode_int(1) '\\x02\\x01\\x01' >>> BEREncoder().encode_int(127) '\\x02\\x01\\x7f' >>> BEREncoder().encode_int(128) '\\x02\\x02\\x00\\x80' >>> BEREncoder().encode_int(256) '\\x02\\x02\\x01\\x00' >>> BEREncoder().encode_int(-128) '\\x02\\x01\\x80' >>> BEREncoder().encode_int(-129) '\\x02\\x02\\xff\\x7f' """ if data == 0: return b"\x02\x01\x00" if data > 0: return encode_int(data) data = -data r = self.struct_Q.pack(data).lstrip(b"\x00") ln = len(r) comp = 1 << (ln * 8 - 1) if comp < data: comp <<= 8 r = self.struct_Q.pack(comp - data).lstrip(b"\x00") if r: r = self.struct_B.pack(bord(r[0]) | 0x80) + r[1:] else: r = b"\x80" + b"\x00" * (ln - 1) return self.encode_tlv(2, True, r)
def parse_real(self, msg): # type: (bytes) -> float """ """ if not msg: return 0.0 f = bord(msg[0]) if f & 0x80: # Binary encoding, 8.5.6 # @todo: Снести в конец base = {0x00: 2, 0x10: 4, 0x20: 16}[f & 0x30] # 8.5.6.2 n = (f & 0x03) + 1 e = self.parse_int(msg[1:n + 1]) # 8.5.6.4 p = self.parse_int(msg[n + 1:]) # 8.5.6.5 if f & 0x40: p = -p # 8.5.6.1 return p * pow(base, e) elif f & 0xC0 == 0: # Decimal encoding, 8.5.7 try: if f & 0x3F == 0x01: # ISO 6093 NR1 form return float(msg[1:]) # 456 elif f & 0x3F == 0x02: # ISO 6093 NR2 form return float(msg[1:]) # 4.56 elif f & 0x3F == 0x03: # ISO 6093 NR3 form return float(msg[1:]) # 0123e456 except ValueError: raise ValueError("Invalid REAL representation: %s" % msg[1:]) elif f & 0x40: # infinitive, 8.5.8 return float("-inf" if f & 0x01 else "inf") else: raise ValueError("Unknown REAL encoding: %s" % f)
def parse_int(self, msg): # type: (bytes) -> int """ >>> BERDecoder().parse_int('') 0 >>> BERDecoder().parse_int('\\x00') 0 >>> BERDecoder().parse_int('\\x01') 1 >>> BERDecoder().parse_int('\\x7f') 127 >>> BERDecoder().parse_int('\\x00\\x80') 128 >>> BERDecoder().parse_int('\\x01\\x00') 256 >>> BERDecoder().parse_int('\\x80') -128 >>> BERDecoder().parse_int('\\xff\\x7f') -129 :param msg: :return: integer """ if not msg: return 0 # Try to speedup mask = self.INT_MASK.get(len(msg)) if mask: return mask.unpack(msg)[0] # Decode as is v = 0 for c in msg: v = (v << 8) + bord(c) if bord(msg[0]) & 0x80: # Negative number m = 1 << (8 * len(msg)) v -= m return v
def _replace_re_group_binary(expr, group, pattern): # type: (six.binary_type, six.binary_type, six.binary_type) -> six.binary_type """ Replace regular expression group with pattern >>> replace_re_group("nothing","(?P<groupname>","groupvalue") 'nothing' >>> replace_re_group("the (?P<groupname>simple) test","(?P<groupname>","groupvalue") 'the groupvalue test' >>> replace_re_group("the (?P<groupname> nested (test)>)","(?P<groupname>","groupvalue") 'the groupvalue' """ r = [] lg = len(group) while expr: idx = expr.find(group) if idx == -1: break r += [expr[:idx]] expr = expr[idx + lg :] level = 1 # Level of parenthesis nesting while expr: c = bord(expr[0]) expr = expr[1:] if c == 0x5C: # "\\" # Skip quoted character expr = expr[1:] continue elif c == 0x28: # "(" # Increase nesting level level += 1 continue elif c == 0x29: # ")" # Decrease nesting level level -= 1 if level == 0: # Replace with pattern and search for next r += [pattern] break r += [expr] return b"".join(r)
def parse_boolean(self, msg): # type: (bytes) -> bool if not msg: return False return bool(bord(msg[0]))
def parse_a_ipaddress(self, msg): # type: (bytes) -> six.text_type if not msg: raise ValueError("Invalid IP Address: '%s'" % msg.encode("hex")) return "%d.%d.%d.%d" % (bord(msg[0]), bord(msg[1]), bord( msg[2]), bord(msg[3]))
def test_bord(input, expected): assert bord(input[0]) == expected