vue cbc 加密,go 后端解密

<template>
    <div>
      <textarea v-model="plaintext" placeholder="Enter plaintext"></textarea>
      <textarea v-model="plaintext2" placeholder="Enter plaintext"></textarea>
      <button @click="encrypt">Encrypt</button>
      <button @click="DecryptAES">DecryptAES</button>
      <p>Encrypted: {{ encryptedText }}</p>
      <p>IV: {{ iv }}</p>
    </div>
  </template>

  <script>
  import CryptoJS from 'crypto-js';

  export default {
    data() {
      return {
        plaintext: 'Hello, AES!',
        plaintext2:'',
        encryptedText: '',
        iv: '1234567890123456',
        key: '1234567890123456', // 密钥应该是 16/24/32 个字节
      };
    },
    methods: {
      encrypt() {
        // 生成随机 IV
        console.log("key22===",this.key)
        if (this.key && this.iv) {
          this.key = CryptoJS.enc.Utf8.parse(this.key);
          console.log("key===", this.key)
          this.iv = CryptoJS.enc.Utf8.parse(this.iv);
          console.log("iv===",this.iv)
        }

        let srcs = CryptoJS.enc.Utf8.parse(this.plaintext);
        let encrypted = CryptoJS.AES.encrypt(srcs, this.key, {
          iv: this.iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
        });
        this.encryptedText = encrypted.toString()
                // 转换为16进制
        let encryptedHex = CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
        console.log("Encrypted Hex: ", encryptedHex);
        // 将十六进制字符串转换为字节数组
        let wordArray = CryptoJS.enc.Hex.parse(encryptedHex);

        // 将字节数组转换为二进制字符串
        let binaryString = '';
        for (let i = 0; i < wordArray.sigBytes; i++) {
            let byte = wordArray.words[wordArray.sigBytes - 1 - i] >>> 24 - (i % 4 * 8);
            binaryString += ('00000000' + byte.toString(2)).slice(-8);
        }

        console.log("binaryString Hex: ",binaryString);

        return encrypted.toString();
      },
      DecryptAES() {
        // key 和 iv 使用同一个值
        const decrypted = CryptoJS.AES.decrypt(this.encryptedText, this.key, {
          iv: this.key,
          mode: CryptoJS.mode.CBC, // CBC算法
          padding: CryptoJS.pad.Pkcs7, //使用pkcs7 进行padding 后端需要注意
        });
        console.log("ddddddd",decrypted.toString(CryptoJS.enc.Utf8))

        this.plaintext2 =  decrypted.toString(CryptoJS.enc.Utf8);
      }   
    }
  };
  </script>

后端解密

package main

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

const sKey = "1234567890123456"

//pkcs7Padding 填充
func pkcs7Padding(data []byte, blockSize int) []byte {
    //判断缺少几位长度。最少1,最多 blockSize
    padding := blockSize - len(data)%blockSize
    //补足位数。把切片[]byte{byte(padding)}复制padding个
    padText := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(data, padText...)
}

//pkcs7UnPadding 填充的反向操作
func pkcs7UnPadding(data []byte) ([]byte, error) {
    length := len(data)
    if length == 0 {
        return nil, errors.New("加密字符串错误!")
    }
    //获取填充的个数
    unPadding := int(data[length-1])
    return data[:(length - unPadding)], nil
}

//AesEncrypt 加密
func AesEncrypt(data []byte) ([]byte, error) {
    key := []byte(sKey)
    //创建加密实例
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    //判断加密块的大小
    blockSize := block.BlockSize()
    //填充
    encryptBytes := pkcs7Padding(data, blockSize)
    //初始化加密数据接收切片
    crypted := make([]byte, len(encryptBytes))
    //使用cbc加密模式
    fmt.Printf("31232131===%s\n", key[:blockSize])
    blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
    //执行加密
    blockMode.CryptBlocks(crypted, encryptBytes)
    return crypted, nil
}

//AesDecrypt 解密
func AesDecrypt2(data []byte) ([]byte, error) {
    key := []byte(sKey)
    //创建实例
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    //获取块的大小
    blockSize := block.BlockSize()
    //使用cbc  这里这个 iv = key[:blockSize] 相当前端设置跟 key 一样
    blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
    //初始化解密数据接收切片
    crypted := make([]byte, len(data))
    //执行解密
    blockMode.CryptBlocks(crypted, data)
    //去除填充
    crypted, err = pkcs7UnPadding(crypted)
    if err != nil {
        return nil, err
    }
    return crypted, nil
}

func main() {

    s := []byte("Hello, AES!")
    ss, err := AesEncrypt(s)
    if err != nil {
        fmt.Printf("AesEncrypt: %v\n", err)
    }
    mw := base64.StdEncoding.EncodeToString(ss)
    fmt.Printf("加密后: %s\n", mw)

    mwb, _ := base64.StdEncoding.DecodeString("VowXT9KIzk8031LVI5rs5Q==")
    s, err = AesDecrypt2(mwb)
    if err != nil {
        fmt.Printf("解密后: %v\n", err)
    }
    fmt.Printf("解密后: %s\n", s)
}
// 所以 iv  跟 key 的长度要一致
//  iv: '1234567890123456',  16位
//  key: '1234567890123457', 16位  两个可不同,但长度一样
func NewCBCDecrypter(b Block, iv []byte) BlockMode {
    if len(iv) != b.BlockSize() {
        panic("cipher.NewCBCDecrypter: IV length must equal block size")
    }
    if cbc, ok := b.(cbcDecAble); ok {
        return cbc.NewCBCDecrypter(iv)
    }
    return (*cbcDecrypter)(newCBC(b, iv))


func AesDecrypt(str string) string {
    // 将加密字符串转换为字节数组
    encryptedData, _ := base64.StdEncoding.DecodeString(str)
    // 创建一个新的AES解密器
    key := []byte("1234567890123456")  // 密钥与前端保持一致
    iv := []byte("1234567890123457") // 偏移量与前端保持一致
    block, _ := aes.NewCipher(key)

    // 使用CBC模式解密
    mode := cipher.NewCBCDecrypter(block, iv)

    decryptedData := make([]byte, len(encryptedData))
    mode.CryptBlocks(decryptedData, encryptedData)

    // 移除填充
    fmt.Println("decryptedData===",decryptedData)
    padding := int(decryptedData[len(decryptedData)-1])
    fmt.Println("padding===",padding)
    fmt.Println("len(decryptedData)===",len(decryptedData))
    decryptedData = decryptedData[:len(decryptedData)-padding]

    // 将解密后的字节数组转换为字符串
    decryptedStr := string(decryptedData)
    return decryptedStr
}
}

参考这个链接

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 18

前端加密闻所未闻 :sweat_smile:

1年前 评论
Image chaofu (楼主) 1年前
Image Dash007 (作者) 1年前

你这是生怕别人不知道密钥啊

1年前 评论

这种加密不太安全,应该采用“信封”模式比较好些。

1年前 评论
Image chaofu (楼主) 1年前

发错版块了

1年前 评论

可以用rsa加密密码,后端再解密

1年前 评论

不是这样的流程的。首先前端从后端接口获取RSA公钥,然后使用公钥加密数据,例如密码或者提交的数据都可以,然后后端拿到数据后,中间件或者函数内使用RSA私钥解密,然后进行下一步操作。

1年前 评论
Image chaofu (楼主) 1年前

多此一举,只能防君子

1年前 评论
Image chaofu (楼主) 1年前

客户端存秘钥就不安全

1年前 评论

这样前端是不是泄露 秘钥了

1年前 评论

前端加密,会把加密代码暴漏在外面,你后端能解密,别人也能解密,图个啥

1年前 评论
Image 我们只希望世界和平 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
Image
未填写
文章
78
粉丝
8
喜欢
43
收藏
49
排名:82
访问:10.4 万
私信
所有博文
社区赞助商