文、專任講師 小州

D018.jpg  

因為教課需要,所以上課時候會簡單提到 linux 系統上密碼的加密方式,裡面會簡單帶到 DES, MD5, SHA-256 與 SHA-512 這類 hash 的密碼加密格式。其中系統預設都會有安裝 openssl 套件,所以有一個 openssl passwd 命令可以產生 DES 與 MD5 hash 格式的密碼。


kendlee@ubuntu:~$ openssl passwd -crypt "passwd"
eS3Et.uzGxtTQ

kendlee@ubuntu:~$ openssl passwd -1 "passwd"
$1$3PjWGBih$24Y7LLSh6UICtTH6f39Lw1


這幾年開始的 linux 系統也開始引入 SHA-256 與 SHA-512,不過查了一下 openssl 該命令似乎一直沒有支援後續的加密演算法格式,所以得求助其他工具來產生所需要的加密內容。在目前的 linux 於 glibc 內其實 crypt() 函數也不再單純只有支援傳統 DES 的加密格式,而是依據傳入不同的 salt 會提供最終 MD5/SHA-256/SHA-512 的密碼的編碼格式。



NOTES
   Glibc Notes
       The glibc2 version of this function supports additional
       encryption algorithms.

 

       If salt is a character string starting with the characters
       "$id$" followed by a string terminated by "$":

              $id$salt$encrypted

       then instead of using the DES machine,id identifies the
       encryption method used and this then determines how the rest of
       the password string is interpreted.  The following values of id
       are supported:

              ID  | Method
              ─────────────────────────────────────────────────────────
              1   | MD5
              2a  | Blowfish (not in mainline glibc; added in some
                  | Linux distributions)
              5   | SHA-256 (since glibc 2.7)
              6   | SHA-512 (since glibc 2.7)

       So   $5$salt$encrypted   is an SHA-256 encoded password and
       $6$salt$encrypted is an SHA-512 encoded one.

       "salt" stands for the up to 16 characters following "$id$" in
       the salt. The encrypted part of the password string is the
       actual computed  password.  The size of this string is fixed:

       MD5     | 22 characters
       SHA-256 | 43 characters
       SHA-512 | 86 characters

       The  characters  in  "salt"  and  "encrypted"  are  drawn  from
       the set [a–zA–Z0–9./]. In the MD5 and SHA implementations the
       entire key is significant (instead of only the first 8 bytes in
       DES).

 


看一下 python library 剛好有提供 crypt 的 module 可以呼叫使用,在 linux 系統環境最後底層最後會呼叫 glibc 的 crypt() 函數,所以就簡單寫了一段 python code 達成該需求。


# *-* coding: utf-8 *-*

 

"""

version: 0.3
author: kenduest - kenduest@gmail.com

"""

import crypt,random

####################################################################

class kenduest_crypt:

    pw_chars_array = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')

    salt_chars_array = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,/')

    crypt_id = { 'DES'     : { "salt_prefix" : ""    , "salt_length" : 2  }  ,
                 'MD5'     : { "salt_prefix" : "$1$" , "salt_length" : 16 }  ,
                 'SHA-256' : { "salt_prefix" : "$5$" , "salt_length" : 16 }  ,
                 'SHA-512' : { "salt_prefix" : "$6$" , "salt_length" : 16 }
                  }

####################################################################

    def genrandompassword(self,length=100):   

        pw_result = []
        pw_result = [ random.choice(self.pw_chars_array) for i in range(0,length) ]
        return "".join(pw_result)

####################################################################

    def hashpw(self, password, crypt_type) :

        return crypt.crypt(password, self.gensalt(crypt_type))

####################################################################

    def get_crypt_method(self):
        #return self.crypt_method
        return [ x for x in sorted(self.crypt_id) ]

####################################################################   

    def gensalt(self, ctype_type) :

        supported_crypt_method = self.get_crypt_method()

        self.xtype = str(ctype_type).upper()

        if self.xtype not in supported_crypt_method :
            raise NotImplementedError

        salt_result = [ random.choice(self.salt_chars_array) for i in range(0,self.crypt_id[self.xtype]["salt_length"]) ]
        result = self.crypt_id[self.xtype]["salt_prefix"] + "".join(salt_result)

        return result

# end of class code

####################################################################

# test code

####################################################################

def test1() :

    if len(sys.argv) != 3 :
        return False

    pw = kenduest_crypt();
    password = sys.argv[1]
    t = sys.argv[2]

    try :
        print(pw.hashpw(password, t))

    except(NotImplementedError) :
        print("Sorry, unspoorted type: %s" % t)

    return True       

####################################################################

def test2() :

    pw = kenduest_crypt();


if len(sys.argv) == 1 :
        password = pw.genrandompassword(10)
    else :
    password = sys.argv[1]

    print("Password is %s" % password)

    try :
        for t in pw.get_crypt_method() :
            print("using %s, result: %s" % (t, pw.hashpw(password, t)))

    except(NotImplementedError) :
        print("Sorry, unspoorted type: %s" % t)
        return False

    return True

####################################################################

# main test code entry

if __name__ == "__main__" :
    import sys    

if not test1() :
    test2()

 


測試一下執行結果...。


 

kendlee@linux:~$ python test2.py
Password is usI3vg8DDv
using DES, result: /rgsM0QlJ/j5s
using MD5, result: $1$1QvD6tSu$zwCGapWJH7Z3YAn4Cmddp1
using SHA-256, result: $5$rCsixkEzHat,HyD3$hdpnwh.LXY1gPyMhfOi5b3LXDZtTWs2R9yLSGnrunu8
using SHA-512, result: $6$tfNEaWcMBtgBhos5$7NoS6amd94Uw35yQkE49PajSfZimYDiQ96daf4SdwGATb6G1kuQMHSa0e5fcgEqy9MzQcYbsDoKe5yv9hufZ1/


 單獨指定密碼與格式執行結果..。


kendlee@linux:~$ python test2.py "123456" "md5"
$1$E1Y1p3s0$s2cc96v94Uwh0vqG3oTY21 


有把產生的結果帶入到 useradd 命令內的 "-p" 參數,有確認可以正常登入成功,所以程式碼大體上應該沒有錯誤....由於 python 本身是要求版面依據要求正常縮排才可以跑的程式語言,所以網頁上顯示剪貼複製容易有錯誤,所以上面的程式碼版本可以在這個網址下載:http://expert.lccnet.com.tw/~kendlee/python/kenduest_crypt.py
這程式碼最大缺點就是還是依賴系統的 glibc 的 crypt() 呼叫,下次預期的目標是改版成為獨立計算雜湊編碼的版本,好相容於其他平台上。另外若是有一篇文章程式碼可以參考,基於 FreeBSD 上 crypt.c 的 source code 寫的 python code 版本
http://code.activestate.com/recipes/325204-passwd-file-compatible-1-md5-crypt/

 2011-10-14-blog.gif  

arrow
arrow

    聯成電腦 發表在 痞客邦 留言(2) 人氣()