Go 語言常用加密算法

在項目開發過程中,當我們利用數據庫存儲一些關於用戶的隱私信息,諸如密碼、帳戶密鑰等數據時,需要加密後才向數據庫寫入。這時,我們需要一些高效地、簡單易用的加密算法,當我們向數據庫寫數據時加密數據,然後把加密後的數據存入數據庫;當需要讀取數據時,從數據庫把加密後的數據取出來,再通過算法解密。

常用的加密算法有 Base64、MD5、AES 和 DES。

Base64

Base64 是一種任意二進制到文本字符串的編碼方法,常用於在 URL、Cookie、網頁中傳輸少量二進制數據。

首先使用 Base64 編碼需要一個含有 64 個字符的表,這個表由大小寫字母、數字、+ 和 / 組成。採用 Base64 編碼處理數據時,會把每三個字節共 24 位作爲一個處理單元,再分爲四組,每組 6 位,查表後獲得相應的字符即編碼後的字符串。編碼後的字符串長 32 位,這樣,經 Base64 編碼後,原字符串增長 1/3。如果要編碼的數據不是 3 的倍數,最後會剩下一到兩個字節,Base64 編碼中會採用 \ x00 在處理單元后補全,編碼後的字符串最後會加上一到兩個 = 表示補了幾個字節。

Base64 表

    BASE64Table = "IJjkKLMNO567PQX12RVW3YZaDEFGbcdefghiABCHlSTUmnopqrxyz04stuvw89+/"

加密。函數里的第二行的代碼可以把一個輸入的字符串轉換成一個字節數組。

func Encode(data string) string {
    content := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&data))))
    coder := base64.NewEncoding(BASE64Table)
    return coder.EncodeToString(content)
}

解密。函數返回處的代碼可以把一個 字節數組轉換成一個字符串。

func Decode(data string) string {
    coder := base64.NewEncoding(BASE64Table)
    result, _ := coder.DecodeString(data)
    return *(*string)(unsafe.Pointer(&result))
}

測試。

    func main(){
      strTest := "I love this beautiful world!"
      strEncrypt := Encode(strTest)
      strDecrypt := Decode(strEncrypt)
      fmt.Println("Encrypted:",strEncrypt)
      fmt.Println("Decrypted:",strDecrypt)
    }
//Output:
//Encrypted: VVJmGsEBONRlFaPfDCYgcaRSEHYmONcpbCrAO2==
//Decrypted: I love this beautiful world!

MD5

MD5 的全稱是 Message-DigestAlgorithm 5,它可以把一個任意長度的字節數組轉換成一個定長的整數,並且這種轉換是不可逆的。對於任意長度的數據,轉換後的 MD5 值長度是固定的,而且 MD5 的轉換操作很容易,只要原數據有一點點改動,轉換後結果就會有很大的差異。正是由於 MD5 算法的這些特性,它經常用於對於一段信息產生信息摘要,以防止其被篡改。其還廣泛就於操作系統的登錄過程中的安全驗證,比如 Unix 操作系統的密碼就是經過 MD5 加密後存儲到文件系統中,當用戶登錄時輸入密碼後, 對用戶輸入的數據經過 MD5 加密後與原來存儲的密文信息比對,如果相同說明密碼正確,否則輸入的密碼就是錯誤的。

MD5 以 512 位爲一個計算單位對數據進行分組,每一分組又被劃分爲 16 個 32 位的小組,經過一系列處理後,輸出 4 個 32 位的小組,最後組成一個 128 位的哈希值。對處理的數據進行 512 求餘得到 N 和一個餘數,如果餘數不爲 448, 填充 1 和若干個 0 直到 448 位爲止,最後再加上一個 64 位用來保存數據的長度,這樣經過預處理後,數據變成(N+1)x 512 位。

加密。Encode 函數用來加密數據,Check 函數傳入一個未加密的字符串和與加密後的數據,進行對比,如果正確就返回 true。

func Check(content, encrypted string) bool {
    return strings.EqualFold(Encode(content), encrypted)
}
func Encode(data string) string {
    h := md5.New()
    h.Write([]byte(data))
    return hex.EncodeToString(h.Sum(nil))
}

測試。

func main() {
     strTest := "I love this beautiful world!"
    strEncrypted := "98b4fc4538115c4980a8b859ff3d27e1"
    fmt.Println(Check(strTest, strEncrypted))
}
//Output:
//true

DES

DES 是一種對稱加密算法,又稱爲美國數據加密標準。DES 加密時以 64 位分組對數據進行加密,加密和解密都使用的是同一個長度爲 64 位的密鑰,實際上只用到了其中的 56 位,密鑰中的第 8、16...64 位用來作奇偶校驗。DES 有 ECB(電子密碼本)和 CBC(加密塊)等加密模式。

DES 算法的安全性很高,目前除了窮舉搜索破解外, 尚無更好的的辦法來破解。其密鑰長度越長,破解難度就越大。

填充和去填充函數。

func ZeroPadding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padtext := bytes.Repeat([]byte{0}, padding)
    return append(ciphertext, padtext...)
}

func ZeroUnPadding(origData []byte) []byte {
    return bytes.TrimFunc(origData,
        func(r rune) bool {
            return r == rune(0)
        })
}

加密。

func Encrypt(text string, key []byte) (string, error) {
    src := []byte(text)
    block, err := des.NewCipher(key)
    if err != nil {
        return "", err
    }
    bs := block.BlockSize()
    src = ZeroPadding(src, bs)
    if len(src)%bs != 0 {
        return "", errors.New("Need a multiple of the blocksize")
    }
    out := make([]byte, len(src))
    dst := out
    for len(src) > 0 {
        block.Encrypt(dst, src[:bs])
        src = src[bs:]
        dst = dst[bs:]
    }
    return hex.EncodeToString(out), nil
}

解密。

func Decrypt(decrypted string , key []byte) (string, error) {
    src, err := hex.DecodeString(decrypted)
    if err != nil {
        return "", err
    }
    block, err := des.NewCipher(key)
    if err != nil {
        return "", err
    }
    out := make([]byte, len(src))
    dst := out
    bs := block.BlockSize()
    if len(src)%bs != 0 {
        return "", errors.New("crypto/cipher: input not full blocks")
    }
    for len(src) > 0 {
        block.Decrypt(dst, src[:bs])
        src = src[bs:]
        dst = dst[bs:]
    }
    out = ZeroUnPadding(out)
    return string(out), nil
}

測試。在這裏,DES 中使用的密鑰 key 只能爲 8 位。

func main() {
    key := []byte("2fa6c1e9")
    str :="I love this beautiful world!"
    strEncrypted, err := Encrypt(str, key)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Encrypted:", strEncrypted)
    strDecrypted, err := Decrypt(strEncrypted, key)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Decrypted:", strDecrypted)
}
//Output:
//Encrypted: 5d2333b9fbbe5892379e6bcc25ffd1f3a51b6ffe4dc7af62beb28e1270d5daa1
//Decrypted: I love this beautiful world!

AES

AES,即高級加密標準(Advanced Encryption Standard),是一個對稱分組密碼算法,旨在取代 DES 成爲廣泛使用的標準。AES 中常見的有三種解決方案,分別爲 AES-128、AES-192 和 AES-256。

AES 加密過程涉及到 4 種操作:字節替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和輪密鑰加(AddRoundKey)。解密過程分別爲對應的逆操作。由於每一步操作都是可逆的,按照相反的順序進行解密即可恢復明文。加解密中每輪的密鑰分別由初始密鑰擴展得到。算法中 16 字節的明文、密文和輪密鑰都以一個 4x4 的矩陣表示。

AES 有五種加密模式:電碼本模式(Electronic Codebook Book (ECB))、密碼分組鏈接模式(Cipher Block Chaining (CBC))、計算器模式(Counter (CTR))、密碼反饋模式(Cipher FeedBack (CFB))和輸出反饋模式(Output FeedBack (OFB))。下面以 CFB 爲例。

加密。iv 即初始向量,這裏取密鑰的前 16 位作爲初始向量。

func Encrypt(text string, key []byte) (string, error) {
     var iv = key[:aes.BlockSize]
    encrypted := make([]byte, len(text))
    block, err := aes.NewCipher(key)
    if err != nil {
        return "", err
    }
    encrypter := cipher.NewCFBEncrypter(block, iv)
    encrypter.XORKeyStream(encrypted, []byte(text))
    return hex.EncodeToString(encrypted), nil
}

解密。

func Decrypt(encrypted string, key []byte) (string, error) {
    var err error
    defer func() {
        if e := recover(); e != nil {
            err = e.(error)
        }
    }()
    src, err := hex.DecodeString(encrypted)
    if err != nil {
        return "", err
    }
    var iv = key[:aes.BlockSize]
    decrypted := make([]byte, len(src))
    var block cipher.Block
    block, err = aes.NewCipher([]byte(key))
    if err != nil {
        return "", err
    }
    decrypter := cipher.NewCFBDecrypter(block, iv)
    decrypter.XORKeyStream(decrypted, src)
    return string(decrypted), nil
}

測試。密鑰 key 只能爲 16 位、24 位或 32 位,分別對應 AES-128, AES-192 和 AES-256。

func main(){
    str := "I love this beautiful world!"
    key := []byte{0xBA, 0x37, 0x2F, 0x02, 0xC3, 0x92, 0x1F, 0x7D,
        0x7A, 0x3D, 0x5F, 0x06, 0x41, 0x9B, 0x3F, 0x2D,
        0xBA, 0x37, 0x2F, 0x02, 0xC3, 0x92, 0x1F, 0x7D,
        0x7A, 0x3D, 0x5F, 0x06, 0x41, 0x9B, 0x3F, 0x2D,
        }
    strEncrypted,err := Encrypt(str, key)
    if err != nil {
        log.Error("Encrypted err:",err)
    }
    fmt.Println("Encrypted:",strEncrypted)
    strDecrypted,err := Decrypt(strEncrypted, key)
    if err != nil {
        log.Error("Decrypted err:",err)
    }
    fmt.Println("Decrypted:",strDecrypted)
}
//Output:
//Encrypted: f866bfe2a36d5a43186a790b41dc2396234dd51241f8f2d4a08fa5dc
//Decrypted: I love this beautiful world!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Qh_3P3UNGokgrDHMTB0j2Q