背景:某无产者(我就不点名批判一番了)分享了一个压缩包,然而有密码保护,只有密码提示“是xxx的niconico番号”。当然帖子底下有好多伸手党问密码到底是什么,不出意外,没有什么特别的发现。

首先是估算问题的规模,根据niconico在发帖时大概有2千万个视频,基本可以认为这个问题的规模时2千万个候选密码。不算特别大,取个常用对数还在10以下,那还是能搞一搞的。

那么首先是核心代码,这边就会有一点点讲究。直觉上,如果我们想要知道压缩包的密码是否正确,那么我们可以使用密码测试一下压缩包。但是实际上,这么做的速度非常慢:在AMD Ryzen5上速度只有不到48 rps(round per second),但是当我们直接尝试去使用密码直接解压时,速度可以提升到1214 rps。下面是示例代码

def do(guess, filepath):
    from zipfile import ZipFile
    from zlib import error as ZlibError
    fp = ZipFile(filepath)
    for passwd in guess:
        try:
            fp.extractall(pwd=passwd )
            print('password is %s' % passwd)
            break
        except ZlibError:
            pass
        except RuntimeError:
            pass

那么对于CPython的祖传单线程,启用多进程池就行了,示例如下

from multiprocessing.pool import Pool
if __name__ == "__main__":
    pool = Pool()
    for i in [b'some', b'password', b'here']:
        pool.apply_async(do, args=(i, '/path/to/zipfile'))
    pool.close()
    pool.join()

当然根据具体问题适当划分一下问题规模会比较好,这里就不再展开了,毕竟开一个进程是要时间的,传参是要占内存的。

留下评论