code: def apache_md5crypt(password, salt, magic='$apr1$'):
      
      password = password.encode('utf-8')
      salt = salt.encode('utf-8')
      magic = magic.encode('utf-8')
  
      m = md5()
      m.update(password + magic + salt)
  
      mixin = md5(password + salt + password).digest()
      for i in range(0, len(password)):
          m.update(mixin[i % 16])
  
      i = len(password)
      while i:
          if i & 1:
              m.update('\x00')
          else:
              m.update(password[0])
          i >>= 1
  
      final = m.digest()
  
      for i in range(1000):
          m2 = md5()
          if i & 1:
              m2.update(password)
          else:
              m2.update(final)
  
          if i % 3:
              m2.update(salt)
  
          if i % 7:
              m2.update(password)
  
          if i & 1:
              m2.update(final)
          else:
              m2.update(password)
  
          final = m2.digest()
  
      itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  
      rearranged = ''
      seq = ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5))
      for a, b, c in seq:
          v = ord(final[a]) << 16 | ord(final[b]) << 8 | ord(final[c])
          for i in range(4):
              rearranged += itoa64[v & 0x3f]
              v >>= 6
  
      v = ord(final[11])
      for i in range(2):
          rearranged += itoa64[v & 0x3f]
          v >>= 6
  
      return magic + salt + '$' + rearranged
docs: Calculates the Apache-style MD5 hash of a password