python生成shadow中密码(SHA512)

在很久很久以前写过一篇文章讲linux中shadow文件的数据构成(https://blog.csdn.net/cracker_zhou/article/details/50817743)。
当然在文章末尾提到了使用python的crypt模块可以生成或者校验linux密码的有效性。但是crypt模块在windows上并不能使用。同时在文章中提交密码的生成依赖于算法(md5,sha512之类)和盐值(salt),但是并没有说清楚salt是如何使用的。
研究发现,密码的生成比我想象的复杂的多,以$6为例并不是单纯的sha512(pass+salt)或者sha512(salt+passwd),而是经历了一系列复杂的运算而成。
下面python代码参考了node版本: https://github.com/mvo5/sha512crypt-node
同时给出官方的C语言版本: https://www.akkadia.org/drepper/SHA-crypt.txt
Tip: 测试代码在python3.6版本编译通过,其他python版本需要做微调

import hashlib,math

def rstr_sha512(text: bytes) -> bytes:
    sha512 = hashlib.sha512()
    sha512.update(text)
    return sha512.digest()

def _extend(source: bytes, size_ref: int) -> bytes :
    extended = b"";
    for i in range(math.floor(size_ref/64)):
        extended += source;
    extended += source[:size_ref % 64]
    return extended;

def _sha512crypt_intermediate(password: bytes,salt: bytes) -> bytes:
    #digest_a = rstr_sha512(password + salt)
    digest_b = rstr_sha512(password + salt + password)
    digest_b_extended = _extend(digest_b,len(password))
    intermediate_input = password + salt + digest_b_extended
    passwd_len = len(password)
    while passwd_len!=0:
        if passwd_len&1 == 1:
            intermediate_input += digest_b
        else:
            intermediate_input += password
        passwd_len >>= 1
    return rstr_sha512(intermediate_input)

def _sha512crypt(password :bytes,salt :bytes,rounds :int) -> bytes:
    digest_a = _sha512crypt_intermediate(password, salt)
    p = _extend(rstr_sha512(password*len(password)),len(password))
    s = _extend(rstr_sha512(salt*(16+digest_a[0])),len(salt))
    digest = digest_a
    for i in range(rounds):
        c_input = b""
        if i&1 :
            c_input += p
        else:
            c_input += digest
        if i % 3:
            c_input += s
        if i % 7:
            c_input += p
        if i & 1:
            c_input += digest
        else:
            c_input += p
        digest = rstr_sha512(c_input)
    return digest

def sha512crypt(password :bytes,salt :bytes, rounds=5000) -> str:
    salt = salt[:16] # max 16 bytes for salt
    input = _sha512crypt(password, salt, rounds)
    tab = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    order = [ 42, 21, 0,  1,  43, 22, 23, 2,  44, 45, 24, 3,
              4,  46, 25, 26, 5,  47, 48, 27, 6, 7,  49, 28,
              29, 8,  50, 51, 30, 9, 10, 52, 31, 32, 11, 53,
              54, 33, 12, 13, 55, 34, 35, 14, 56, 57, 36, 15,
              16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40,
              41, 20, 62, 63]
    output = ""
    for i in range(0,len(input),3):
        # special case for the end of the input
        if i+1 >= len(order): # i == 63
            char_1 = input[order[i+0]] & 0b00111111
            char_2 = (input[order[i+0]] & 0b11000000) >> 6
            output += tab[char_1] + tab[char_2]
        else:
            char_1 = input[order[i+0]] & 0b00111111
            char_2 = (((input[order[i+0]] & 0b11000000) >> 6) |
                       (input[order[i+1]] & 0b00001111) << 2)
            char_3 = (
                ((input[order[i+1]] & 0b11110000) >> 4) | 
                    (input[order[i+2]] & 0b00000011) << 4)
            char_4 = (input[order[i+2]] & 0b11111100) >> 2
            output += tab[char_1] + tab[char_2] + tab[char_3] + tab[char_4]
    if rounds!=5000:
        return "$6$rounds={}${}${}".format(rounds,salt.decode("utf-8"),output)
    else:
        return "$6${}${}".format(salt.decode("utf-8"),output)

if __name__ == "__main__":
    #  与crypt.crypt("123456","$6$123456") 运算结果一致
    print(sha512crypt(b"123456",b"123456",5000))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容

  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    小迈克阅读 2,858评论 1 3
  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    aimaile阅读 26,292评论 6 428
  • Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def...
    伊森H阅读 2,965评论 0 15
  • 数组 定义数组并赋值 如一维整型数组 int[ ] scores=new scores[ ]{1,2,3,4};二...
    续笙阅读 251评论 0 1
  • 大家好,我是Simin。 这是第三个70天。第一期参加了冥想群,然后自控力lab就陪着我从大四踏实的走向职场啦。 ...
    Simin_阅读 233评论 0 3