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

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

  起因是想實現oracle相容的加解密演算法,結果折騰了好幾天也沒有搞定相容的3des演算法.

  副產品是把aes的各種場景驗證了一遍.

  之前沒有密碼學基礎,通過折騰,稍微瞭解了一點.AES是比3des更先進的加密演算法,雖然現在也不可靠了.

  加密的塊處理模式分為ECB和CBC.  ECB因為不安全,已經廢棄.如果不考慮和php相容,那麼可以不用了.

  塊處理就涉及一個填充模式,常見的填充模式,有補0(ZeroPadding)和補位數(PKcs5/PKcs7)

  AES的相容性相對比較好.可以先線上測試一下,獲得比較基準.http://tool.chacuo.net/cryptaes

  下面分別上程式碼(差別不大,但是分開來看得比較清楚)

   先來ECB的,雖然已經淘汰了, 網上搜索的很多反而是這個.

   js的,需要下載CrypoJS庫. 注意解密的是base格式的str.

<!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>  
<script src="components/mode-ecb.js"></script>  

<body>  
<script>  
    var key = CryptoJS.enc.Utf8.parse("abcdefgh12345678");  
 
    var plaintText = 'www.baidu.com'; // 明文  
    //var plaintText = 'www.baidu.com'; // 明文  
  
    var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {  
        mode: CryptoJS.mode.ECB,  
        padding: CryptoJS.pad.Pkcs7  
        //padding: CryptoJS.pad.ZeroPadding
    });  
  
    console.log("加密前:"+plaintText);  
    console.log("加密後:"+encryptedData);   
                                              
  
    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, {  
        mode: CryptoJS.mode.ECB,  
        padding: CryptoJS.pad.Pkcs7  
    });  
  
    var decryptedStr = decryptedData.toString(CryptoJS.enc.Utf8);  
    console.log("解密後:"+decryptedStr);  
    
</script>  
</body>  
</html>  

golang的. 比較囉嗦.封裝層次太低,padding函式也要自己寫.

/*
描述 :  golang  AES/ECB/PKCS5|Zero  加密解密
date : 2016-04-08
*/

package main

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

func main() {
    /*
    *src 要加密的字串
    *key 用來加密的金鑰 金鑰長度可以是128bit、192bit、256bit中的任意一個
    *16位key對應128bit
     */
    src := "www.baidu.com"
    key := "abcdefgh12345678"

    crypted := AesEncrypt(src, key)
    AesDecrypt(crypted, []byte(key))
    
}


func AesDecrypt(crypted, key []byte) []byte {
    block, err := aes.NewCipher(key)
    if err != nil {
        fmt.Println("err is:", err)
    }
    blockMode := NewECBDecrypter(block)
    origData := make([]byte, len(crypted))
    blockMode.CryptBlocks(origData, crypted)
    //origData = PKCS5UnPadding(origData)
    origData = ZeroUnPadding(origData)
    fmt.Println("source is :", origData, string(origData))
    return origData
}

func AesEncrypt(src, key string) []byte {
    block, err := aes.NewCipher([]byte(key))
    if err != nil {
        fmt.Println("key error1", err)
    }
    if src == "" {
        fmt.Println("plain content empty")
    }
    ecb := NewECBEncrypter(block)
    content := []byte(src)
    //content = PKCS5Padding(content, block.BlockSize())
    content = ZeroPadding(content, block.BlockSize())
    crypted := make([]byte, len(content))
    ecb.CryptBlocks(crypted, content)
    
    fmt.Println("base64 result:", base64.StdEncoding.EncodeToString(crypted))
    return crypted
}



func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
        padding := blockSize - len(ciphertext)%blockSize//需要padding的數目
        //只要少於256就能放到一個byte中,預設的blockSize=16(即採用16*8=128, AES-128長的金鑰)
        //最少填充1個byte,如果原文剛好是blocksize的整數倍,則再填充一個blocksize
        padtext := bytes.Repeat([]byte{byte(padding)}, padding)//生成填充的文字
        return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
        length := len(origData)
        unpadding := int(origData[length-1])
        return origData[:(length - unpadding)]
}

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

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


type ecb struct {
    b         cipher.Block
    blockSize int
}

func newECB(b cipher.Block) *ecb {
    return &ecb{
        b:         b,
        blockSize: b.BlockSize(),
    }
}

type ecbEncrypter ecb

// NewECBEncrypter returns a BlockMode which encrypts in electronic code book
// mode, using the given Block.
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
    return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
    if len(src)%x.blockSize != 0 {
        panic("crypto/cipher: input not full blocks")
    }
    if len(dst) < len(src) {
        panic("crypto/cipher: output smaller than input")
    }
    for len(src) > 0 {
        x.b.Encrypt(dst, src[:x.blockSize])
        src = src[x.blockSize:]
        dst = dst[x.blockSize:]
    }
}

type ecbDecrypter ecb

// NewECBDecrypter returns a BlockMode which decrypts in electronic code book
// mode, using the given Block.
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
    return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
    if len(src)%x.blockSize != 0 {
        panic("crypto/cipher: input not full blocks")
    }
    if len(dst) < len(src) {
        panic("crypto/cipher: output smaller than input")
    }
    for len(src) > 0 {
        x.b.Decrypt(dst, src[:x.blockSize])
        src = src[x.blockSize:]
        dst = dst[x.blockSize:]
    }
}


python的. 還行.不過加解密的物件是byte

#coding=utf-8
#AES-demo  AES/ECB/PKCS5|Zero
#ECB不安全.建議CBC

import base64
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex

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
    
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 = 'abcdefgh12345678'
    # 待加密文字
    text = 'www.baidu.com'
    # 初始化加密器
    aes = AES.new(add_to_16(key), AES.MODE_ECB)
    bs = AES.block_size
    pad2 = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)#PKS7 就是pkcs7padding
    
    #先進行aes加密
    #Zeropadding
    #encrypt_aes = aes.encrypt(add_to_16(text))
    #Pkcs7 padding
    encrypt_aes = aes.encrypt(str.encode(pad2(text)))
    #轉為hex
    print(ByteToHex(encrypt_aes))    #轉為字串 
    print(b2a_hex(encrypt_aes))      #b''
    #用base64轉成字串形式
    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')  # 執行加密並轉碼返回bytes
    print(encrypted_text)   
    #和js的 結果相同 http://tool.chacuo.net/cryptaes
    return encrypted_text
    
#解密方法
def decrypt_oralce(text):
    # 祕鑰
    key = 'abcdefgh12345678'
    # 密文

    # 初始化加密器
    aes = AES.new(add_to_16(key), AES.MODE_ECB)
    #優先逆向解密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])]    #pkcs7unpadding比較簡單.
    print(unpad(decrypted_text))

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


相關推薦

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

  起因是想實現oracle相容的加解密演算法,結果折騰了好幾天也沒有搞定相容的3des演算法.  副產品是把aes的各種場景驗證了一遍.  之前沒有密碼學基礎,通過折騰,稍微瞭解了一點.AES是比3des更先進的加密演算法,雖然現在也不可靠了.  加密的塊處理模式分為ECB

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

CBC模式用起來差別不大,就是多了一個iv還是先來js的<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <tit

golang實現aes-cbc-256加密解密過程記錄

generic 返回 hint pie follow strong pri hms 加密解密 我為什麽吃撐了要實現go的aes-cbc-256加密解密功能? 之前的項目是用php實現的,現在準備用go重構,需要用到這個功能,這麽常用的功能上網一搜一大把現成例子,於是基於g

golang使用aes庫實現解密

golang實現加密解密的庫很多, 這裡使用的是aes庫+base64庫來實現. 使用時,需要指定一個私鑰,來進行加解密, 這裡指定是: var aeskey = []byte(“321423u9y

手機號的 AES/CBC/PKCS7Padding 解密

.sh cipher 字節 padding name key inf ret def 前言:接口中上次的手機號碼和密碼是傳入的加密的,模擬自動化的時候也需要先對數據進行加密 代碼操作 # coding=utf-8 import hashlib from Cr

Golang實現AES/CBC/PKCS5Padding演算法

使用golang實現AES演算法很簡單,系統庫中已自帶了CBC、CFB等等許多加密模式,而且可以很方便的設定IVPara,但是前幾日在做AES加密時,發現傳入的key必須是128bit、192bit或256bit,記得當時用Java實現的時候並沒有這個問題。AES中的key的

angularjs ocLazyLoad分步js文件,angularjs ocLazyLoad按需js

path 技術分享 active meta 代碼 效果 function 初始化 reat 用angular有一段時間了,平日裏只顧著寫代碼,沒有註意到性能優化的問題,而今有時間,於是捋了捋,講學習過程記錄於此: 問題描述:由於采用angular做了網頁的單頁面應用,

AES-128-CBC-PKCS5PADDING 解密實現

Copyright © 2018 Joyce_BY, all rights reserved. Contact by email: [email protected] 本文目的及實驗環境 1、實現128-bit的AES加解密過程 2、python3.7.0,windo

aes/cbc/pkcs5padding/128解密

//******aes/cbc/pkcs5padding/128加解密****** private function aesEncrypt($data,$iv=''){ $enc_key = 'KlW';//隨機生成16為由大小寫字元和數字組成的字串

JAVA AES文件解密

輸出 byte stat spa urn code for cat substring AES加解密算法,代碼如下: /** * Created by hua on 2017/6/30. */ import javax.crypto.Cipher; import j

python給html裏的css及js文件鏈接自動添版本號

odin link 鏈接 寫入 dir bsp gulp () pan 傳統的給文件鏈接添加版本號的方法是使用gulp-rev,這裏提出的解決方案是使用python來替代gulp-rev。 import os import re import uuid impor

python AES CBC模式加密

理解 定義 代碼 Coding imp lai encrypted python .net 今天需要用到AES CBC模式加密,搜索了很久,終於加密成功,記錄一下今天的理解。 首先要安裝pycrypto庫,不知道為什麽在windows安裝失敗,在linux可以正常安裝 ht

Python3 學習解密 系列 4 --Cryptodome -Cipher-AES

由於Crypto 安裝 麻煩,選擇了和它一樣專案的Cryptodome包 直接 pip install pycryptodome 就行 先help 發現 有多種加密方式: 看 Cryptodome 原始碼 有很多功能 先看第一個AES: 瞭解下 AES的加密模式:https://

PHP AES cbc模式 pkcs7 128加密解密

今天在對接一個第三方介面的時候,對方需要AES CBC模式下的加密。這裡簡單寫一個demo class Model_Junjingbao extends Model { private static $_partnerKey = '6d70a09e4d0f8095'; //

java實現AES&MD5解密

AES: import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.bin

python AES-16位加密解密功能實現

從網上搜了很多這種python AES相關內容,但是大部分都是需要自己除錯修改半天才能使用,有的甚至埋下很多坑,費時費力,我這邊根據專案需求,也需要弄一套AES-16位加密和解密API 我用的python加密元件是Crypto,很好用,可以從網上下載最新的庫,我用的比較穩

AES CBC加密/解密

簡介 高階加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高

JAVA 實現對稱解密小程式使用者資訊(AES-128-CBC演算法)

需要引入bcprov.jar包 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</ar

JS AES加密與PHP解密

網頁端(在沒有https情況下)給密碼之類的加密傳輸,雖然多此一舉,也好過直接監控軟體就能看到密碼 思路 在傳輸密碼的時候,先向後臺獲取一個隨機碼或者驗證碼,作為祕鑰,網頁端根據這個祕鑰,加密要傳輸的資料,服務端先驗證驗證碼是否正確,如果驗證正確,根據驗

PHP和Java AES 128 ECB 解密(PKCS5Padding)

php 和 java 使用 AES128/ECB/PKCS5Padding對稱加解密,簽名使用 HmacSHA256,附帶 php 和 java 程式碼,均為 DEMO 版本,測試通過,實際使用請根據自己專案修改。 最近做專案涉及到一丟丟的安全問題,需