1. 程式人生 > >[加解密]js/python/golang 相容AES(CBC/ECB)加解密(2)--CBC模式

[加解密]js/python/golang 相容AES(CBC/ECB)加解密(2)--CBC模式

CBC模式用起來差別不大,就是多了一個iv

還是先來js的

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>Title</title>  
  
</head>  
<script src="rollups/aes.js"></script>  
<script src="components/pad-zeropadding.js"></script>  
<body>  
<script>  
  
     
  
    var key = CryptoJS.enc.Utf8.parse("beijingtiananmen");  
    var plaintText = 'www.baidu.com'; // 明文  
    //var plaintText = 'www.baidu.com'; // 明文  
    var iv=key;  //16位字串
    var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {  
        iv:  CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,  
        padding: CryptoJS.pad.Pkcs7  
        //padding: CryptoJS.pad.ZeroPadding
    });  
  
    console.log("加密前:"+plaintText);  
    console.log("加密後:"+encryptedData);    //Pkcs7:   WoCzvm6eZiM4/bx5o/CzGw==
                                              //ZeroPadding :   cUYmaJktt7P+dqv+Ijds9g==
  
    encryptedData = encryptedData.ciphertext.toString();  
  
    var encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedData);  
    console.log("解密前hex:"+encryptedHexStr); 
    var encryptedBase64Str = CryptoJS.enc.Base64.stringify(encryptedHexStr);  
    console.log("解密前:"+encryptedBase64Str);  
    var decryptedData = CryptoJS.AES.decrypt(encryptedBase64Str, key, {  
        iv:  CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,  
        padding: CryptoJS.pad.Pkcs7  
    });  
  
    var decryptedStr = decryptedData.toString(CryptoJS.enc.Utf8);  
    console.log("解密後:"+decryptedStr);  
</script>  
</body>  
</html>  

再來go的

package main

import (
	"bytes"
	"crypto/cipher"
	"crypto/aes"
	"encoding/base64"
	"fmt"
)

func main() {
	testAes()
}

func testAes() {
	// AES-128。key長度:16, 24, 32 bytes 對應 AES-128, AES-192, AES-256
	key := []byte("beijingtiananmen")
	result, err := AesEncrypt([]byte("www.baidu.com"), key)
	if err != nil {
		panic(err)
	}
	fmt.Println(base64.StdEncoding.EncodeToString(result))    //zero UR5c4C1iW5mIdxrv5rxo4w==,pkcs jE7BUAKWpdJWb2ulcFWd/g==  和pthon,js相同 
	origData, err := AesDecrypt(result, key)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(origData))
}

func AesEncrypt(origData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	//origData = PKCS5Padding(origData, blockSize)
	 origData = ZeroPadding(origData, block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])  //iv=key
	crypted := make([]byte, len(origData))
	// 根據CryptBlocks方法的說明,如下方式初始化crypted也可以
	// crypted := origData
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

func AesDecrypt(crypted, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
	origData := make([]byte, len(crypted))
	// origData := crypted
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(origData)
	// origData = ZeroUnPadding(origData)
	return origData, nil
}

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 {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

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

func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	// 去掉最後一個位元組 unpadding 次
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

python的

#coding=utf-8
#AES AES/CBC/PKCS5|Zero

import base64
from Crypto.Cipher import AES

def ByteToHex( bins ):
    """
    Convert a byte string to it's hex string representation e.g. for output.
    """
    return ''.join( [ "%02X" % x for x in bins ] ).strip()


'''
採用AES對稱加密演算法
'''
# str不是16的倍數那就補足為16的倍數. ZeroPadding

'''
    在PKCS5Padding中,明確定義Block的大小是8位
    而在PKCS7Padding定義中,對於塊的大小是不確定的,可以在1-255之間

    PKCS #7 填充字串由一個位元組序列組成,每個位元組填充該位元組序列的長度。
    假定塊長度為 8,資料長度為 9,
    資料: FF FF FF FF FF FF FF FF FF
    PKCS7 填充: FF FF FF FF FF FF FF FF FF 01 01 01 01 01 01 01   ?應該是填充01
    
    python3:填充bytes(這個說法不對,AES的引數是字串,不是byte)
    length = 16 - (len(data) % 16)
    data += bytes([length])*length

 
    python2:填充字串
    length = 16 - (len(data) % 16)
    data += chr(length)*length

    
    pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
    unpad = lambda s : s[0:-ord(s[-1])]

'''
def add_to_16(value):
    while len(value) % 16 != 0:
        value += '\0'
    return str.encode(value)  # 返回bytes

    
def ZeroPadding(value,bs):
    while len(value) % bs != 0:
        value += '\0'
    return str.encode(value)  # 返回bytes

#對於python,不需要zerounpadding?  去掉尾部的\0
    
def PKCS7Padding(value,bs):
    pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)#PKS7 
    return str.encode(pad(value)) # 返回bytes
    
def PKCS7UnPadding(value):
    #value = value[:-value[-1]]
    unpad = lambda s : s[0:-ord(s[-1])]  #獲得資料的長度,擷取
    return unpad(value)

#加密方法
def encrypt_oracle():
    # 祕鑰
    #key = '123456'
    key = 'beijingtiananmen'
    # 待加密文字
    #text = 'abc123def456'
    text = 'www.baidu.com'
    iv=add_to_16(key)   #多了個iv
    # 初始化加密器
    aes = AES.new(add_to_16(key), AES.MODE_CBC,iv)
    bs = AES.block_size
    pad2 = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)#PKS7 
    
    #先進行aes加密
    #encrypt_aes = aes.encrypt(add_to_16(text))
    #Zeropadding
    #encrypt_aes = aes.encrypt(add_to_16(text))
    #Pkcs7 padding
    encrypt_aes = aes.encrypt(str.encode(pad2(text)))
    #轉為hex
    print(ByteToHex(encrypt_aes))    #轉為字串 71462668992DB7B3FE76ABFE22376CF6
    #用base64轉成字串形式
    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')  # 執行加密並轉碼返回bytes
    print(encrypted_text)   #zeropadding:   UR5c4C1iW5mIdxrv5rxo4w==     Pkcs7/Pkcs7: jE7BUAKWpdJWb2ulcFWd/g==
    #和js的 結果相同 http://tool.chacuo.net/cryptaes
    return encrypted_text
    
#解密方法
def decrypt_oralce(text):
    # 祕鑰
    #key = '123456'
    key = 'beijingtiananmen'
    # 密文
    #text = 'qR/TQk4INsWeXdMSbCDDdA=='
    #text = 'cUYmaJktt7P+dqv+Ijds9g=='
    # 初始化加密器
    aes = AES.new(add_to_16(key), AES.MODE_CBC,add_to_16(key))
    #優先逆向解密base64成bytes
    base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))
    #
    decrypted_text = str(aes.decrypt(base64_decrypted),encoding='utf-8') # 執行解密密並轉碼返回str
    unpad = lambda s : s[0:-ord(s[-1])]
    #PADDING = '\0'
    #print decrypted_text.rstrip(PADDING)  #zeropadding只見誒去掉結尾\0
    print(unpad(decrypted_text))

if __name__ == '__main__':
    en=encrypt_oracle()
    decrypt_oralce(en)