package main
import (
"bytes"
"crypto/cipher"
"encoding/base64"
"errors"
"fmt"
"strconv"
"golang.org/x/crypto/blowfish"
)
func main() {
key := "PPpn7ugdcTa4DTUdqSkxSeR7gTsv93Q576ug8QMdeLbVFPte"
price := "29.20"
enc, err := BlowfishECBEncrypt(price, key)
if err != nil {
fmt.Println("-------err: ", err)
}
encodeStr := base64.URLEncoding.EncodeToString(enc)
fmt.Println("encode=", encodeStr)
enc, err = base64.URLEncoding.DecodeString(encodeStr)
if err != nil {
fmt.Println("-------err: ", err)
}
price2, err := BlowfishECBDecrypt(enc, []byte(key))
if err != nil {
fmt.Println("--------err decode=", err)
}
fmt.Println("decode=", string(price2))
price1, err := strconv.ParseFloat(string(price2), 64)
if err != nil {
fmt.Println("parse float is failed, err:", err)
}
fmt.Println("------------price1=", price1)
}
func BlowfishECBEncrypt(src, key string) ([]byte, error) {
block, err := blowfish.NewCipher([]byte(key))
if err != nil {
return nil, err
}
if src == "" {
return nil, errors.New("plain content empty")
}
ecb := NewECBEncrypter(block)
content := []byte(src)
content = PKCS5Padding(content, block.BlockSize())
crypted := make([]byte, len(content))
ecb.CryptBlocks(crypted, content)
return crypted, nil
}
func BlowfishECBDecrypt(crypted, key []byte) ([]byte, error) {
block, err := blowfish.NewCipher([]byte(key))
if err != nil {
return nil, err
}
blockMode := NewECBDecrypter(block)
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}
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:]
}
}
// PKCS5Padding _
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// PKCS5UnPadding _
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}