Go语言的DES加密(CBC模式, ECB模式) ---- 与java加密互通
问题场景:
业务需要对接接口, 采用DES加密方式加密, 于是google一下go的DES加密方式,
go的DES的默认隐藏了ECB模式, 因为go认为ECB不安全, 所以不建议使用,就隐藏了,
然而由于历史遗留问题接口却需要采用ECB模式。
ECB
ECB(电子密本方式)就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
CBC
CBC(密文分组链接方式)有向量的概念, 它的实现机制使加密的各段数据之间有了联系。
每个密文块依赖于所有的信息明文消息中一个改变会影响所有密文块
代码:
//des_ecb_pkcs5padding.go
package main
import (
"bytes"
"crypto/des"
"encoding/base64"
"errors"
)
//明文补码算法
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 := 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)
return append(ciphertext, padtext...)
}
func ZeroUnPadding(origData []byte) []byte {
return bytes.TrimFunc(origData,
func(r rune) bool {
return r == rune(0)
})
}
func DesEncrypt(src, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
bs := block.BlockSize()
//对明文数据进行补码
src = PKCS5Padding(src, bs)
if len(src) % bs != 0 {
return nil, errors.New("Need a multiple of the blocksize")
}
out := make([]byte, len(src))
dst := out
//对明文按照blocksize进行分块加密
//必要时可以使用go关键字进行并行加密
for len(src) > 0 {
block.Encrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
dstBase64 := make([]byte, base64.StdEncoding.EncodedLen(len(out)))
base64.StdEncoding.Encode(dstBase64, out)
return dstBase64, nil
}
func DesDecrypt(src, key []byte) ([]byte, error) {
srcBase64 := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(srcBase64, src)
if err != nil {
return nil, err
}
srcUnBase64 := srcBase64[:n]
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
out := make([]byte, len(srcUnBase64))
dst := out
bs := block.BlockSize()
if len(srcUnBase64) % bs != 0 {
return nil, errors.New("crypto/cipher: input not full blocks")
}
for len(srcUnBase64) > 0 {
block.Decrypt(dst, srcUnBase64[:bs])
srcUnBase64 = srcUnBase64[bs:]
dst = dst[bs:]
}
out = PKCS5UnPadding(out)
return out, nil
}
//main.go 使用DES算法来加密电话号码
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"runtime"
"sync"
)
const (
GPNUM = 1000
//key只能是8位,不能少于8位也不能多于8位.
KEY = "ImDesKey"
)
var (
inputFile, outputFile string
)
type outputWriter struct {
file *os.File
fWriter *bufio.Writer
rwMutex *sync.RWMutex
ch chan []byte
wg *sync.WaitGroup
}
func (ow *outputWriter) Write(row []byte) {
ow.rwMutex.Lock()
ow.fWriter.Write(row)
ow.rwMutex.Unlock()
}
func (ow *outputWriter) Flush() {
ow.rwMutex.Lock()
ow.fWriter.Flush()
ow.rwMutex.Unlock()
}
func (ow *outputWriter) Close() {
ow.file.Close()
}
func NewOutputWriter(dstFile string, gp int) (*outputWriter, error) {
f, err := os.OpenFile(dstFile,os.O_WRONLY|os.O_CREATE|os.O_TRUNC,0644)
if err != nil {
return nil, err
}
w := bufio.NewWriter(f)
ch := make(chan []byte, gp)
return &outputWriter{file:f, fWriter:w, rwMutex:&sync.RWMutex{}, ch:ch, wg:&sync.WaitGroup{}}, nil
}
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
flag.StringVar(&inputFile, "srcfile", "tel.txt", "src file")
flag.StringVar(&outputFile, "dstfile", "tel_en.txt", "dst file")
flag.Parse()
}
func concurrentProcess(gp int, src string) {
//ch := make(chan []byte, gp)
//wg := &sync.WaitGroup{}
fReader, err := os.Open(src)
if err != nil {
fmt.Errorf("Error: %v\n", err)
os.Exit(1)
}
//defer fReader.Close()
reader := bufio.NewReader(fReader)
writer, err := NewOutputWriter(outputFile, gp)
if err != nil {
fmt.Errorf("Error: %v\n", err)
}
//defer writer.Close()
for {
lineBytes, _, err := reader.ReadLine()
if err == io.EOF {
break
}
//tab键的ascii码为9
//lineBytesSlice := bytes.Split(lineBytes, []byte{9})
//telBytes := lineBytesSlice[0]
//provBytes := lineBytesSlice[1]
//cityBytes := lineBytesSlice[2]
writer.wg.Add(1)
go func(ch chan []byte) {
lineWriteBytes := make([]byte,0,45)
telBytes := make([]byte,0,11)
for i:=0;i<=10;i++{
telBytes = append(telBytes, lineBytes[i])
}
//注意:这里不能使用telEnBytes, telEnErr := DesEncrypt(lineBytes[:11], []byte(KEY))来加密电话号码,否则会修改lineBytes[11:]中的内容
telEnBytes, telEnErr := DesEncrypt(telBytes, []byte(KEY))
if telEnErr != nil {
fmt.Errorf("Error: %v\n", telEnErr)
//os.Exit(1)
}
for i:=0;i<=11;i++ {
lineWriteBytes = append(lineWriteBytes,lineBytes[i])
}
for i:=0;i<=23;i++{
lineWriteBytes = append(lineWriteBytes, telEnBytes[i])
}
for i:=11;i<len(lineBytes);i++{
lineWriteBytes = append(lineWriteBytes, lineBytes[i])
}
//换行的ascii码为10lineBytes[:11]
lineWriteBytes = append(lineWriteBytes,10)
//writer.Write(lineWriteBytes)
//writer.Flush()
ch <- lineWriteBytes
defer writer.wg.Done()
}(writer.ch)
writer.wg.Add(1)
go func(ch chan []byte) {
writer.Write(<-ch)
writer.Flush()
defer writer.wg.Done()
}(writer.ch)
}
//writer.Flush()
writer.wg.Wait()
fReader.Close()
writer.Close()
}
func main() {
concurrentProcess(GPNUM, inputFile)
}
//tel.txt 电话号码文件
13615660000 551 0566
13665660000 551 0566
13615580000 551 0566
13615670000 551 0566
13615680000 551 0566
13615510000 551 0566
13615600000 551 0566
13615690000 551 0566
13645640000 551 0566
13665540000 551 0566