這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在項目開發過程中,當我們利用資料庫儲存一些關於使用者的隱私資訊,諸如密碼、帳戶密鑰等資料時,需要加密後才向資料庫寫入。這時,我們需要一些高效地、簡單易用的密碼編譯演算法,當我們向資料庫寫資料時加密資料,然後把加密後的資料存入資料庫;當需要讀取資料時,從資料庫把加密後的資料取出來,再通過演算法解密。
常用的密碼編譯演算法有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!
參考
- Golang中的DES加密ECB模式
- AES五種加密模式(CBC、ECB、CTR、OCF、CFB)