东台市文章资讯

微信小程序中Crypto.js加密解密详细示例代码

2026-04-04 22:16:01 浏览次数:0
详细信息

1. 安装 Crypto.js

由于小程序环境限制,需要下载特定版本的 Crypto.js:

// 方法一:使用 npm(需在 project.config.json 中开启 npm 支持)
npm install crypto-js

// 方法二:手动引入
// 1. 下载 crypto-js:https://github.com/brix/crypto-js
// 2. 将所需文件复制到小程序项目中,如 utils/crypto-js/

2. 基础加密解密示例

AES 加密解密

// utils/cryptoUtil.js
const CryptoJS = require('./crypto-js/crypto-js.js');

class CryptoUtil {
  /**
   * AES 加密
   * @param {string} data 待加密数据
   * @param {string} key 密钥
   * @param {string} iv 向量(可选)
   * @returns {string} 加密后的 Base64 字符串
   */
  static aesEncrypt(data, key, iv = '') {
    try {
      // 处理密钥和向量
      const keyUtf8 = CryptoJS.enc.Utf8.parse(this._handleKey(key));
      const ivUtf8 = iv ? CryptoJS.enc.Utf8.parse(this._handleKey(iv)) : null;

      // 加密配置
      const cfg = {
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      };

      // 如果有向量,添加到配置中
      if (ivUtf8) {
        cfg.iv = ivUtf8;
      }

      // 执行加密
      const encrypted = CryptoJS.AES.encrypt(
        CryptoJS.enc.Utf8.parse(data),
        keyUtf8,
        cfg
      );

      // 返回 Base64 字符串
      return encrypted.toString();
    } catch (error) {
      console.error('AES 加密失败:', error);
      return null;
    }
  }

  /**
   * AES 解密
   * @param {string} data 待解密数据(Base64)
   * @param {string} key 密钥
   * @param {string} iv 向量(可选)
   * @returns {string} 解密后的字符串
   */
  static aesDecrypt(data, key, iv = '') {
    try {
      // 处理密钥和向量
      const keyUtf8 = CryptoJS.enc.Utf8.parse(this._handleKey(key));
      const ivUtf8 = iv ? CryptoJS.enc.Utf8.parse(this._handleKey(iv)) : null;

      // 解密配置
      const cfg = {
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      };

      // 如果有向量,添加到配置中
      if (ivUtf8) {
        cfg.iv = ivUtf8;
      }

      // 执行解密
      const decrypted = CryptoJS.AES.decrypt(data, keyUtf8, cfg);

      // 返回 UTF-8 字符串
      return decrypted.toString(CryptoJS.enc.Utf8);
    } catch (error) {
      console.error('AES 解密失败:', error);
      return null;
    }
  }

  /**
   * 处理密钥长度
   * @private
   */
  static _handleKey(key) {
    // AES 密钥长度:16/24/32 字节(对应 128/192/256 位)
    const keyLength = [16, 24, 32];
    const keyUtf8 = CryptoJS.enc.Utf8.parse(key);

    // 如果密钥长度符合要求,直接返回
    for (let len of keyLength) {
      if (keyUtf8.sigBytes === len) {
        return key;
      }
    }

    // 密钥长度不符合,进行补全或截取
    let newKey = key;
    if (keyUtf8.sigBytes < 16) {
      // 补全到 16 位
      while (newKey.length < 16) {
        newKey += '0';
      }
      newKey = newKey.substring(0, 16);
    } else if (keyUtf8.sigBytes > 32) {
      // 截取到 32 位
      newKey = newKey.substring(0, 32);
    }

    return newKey;
  }
}

module.exports = CryptoUtil;

DES 加密解密

// 在 CryptoUtil 类中添加 DES 方法
class CryptoUtil {
  // ... 之前的 AES 方法 ...

  /**
   * DES 加密
   * @param {string} data 待加密数据
   * @param {string} key 密钥(8字节)
   * @param {string} iv 向量(8字节)
   * @returns {string} 加密后的 Base64 字符串
   */
  static desEncrypt(data, key, iv = '') {
    try {
      const keyUtf8 = CryptoJS.enc.Utf8.parse(key.substring(0, 8));
      const ivUtf8 = iv ? CryptoJS.enc.Utf8.parse(iv.substring(0, 8)) : null;

      const cfg = {
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
        iv: ivUtf8
      };

      const encrypted = CryptoJS.DES.encrypt(
        CryptoJS.enc.Utf8.parse(data),
        keyUtf8,
        cfg
      );

      return encrypted.toString();
    } catch (error) {
      console.error('DES 加密失败:', error);
      return null;
    }
  }

  /**
   * DES 解密
   * @param {string} data 待解密数据
   * @param {string} key 密钥(8字节)
   * @param {string} iv 向量(8字节)
   * @returns {string} 解密后的字符串
   */
  static desDecrypt(data, key, iv = '') {
    try {
      const keyUtf8 = CryptoJS.enc.Utf8.parse(key.substring(0, 8));
      const ivUtf8 = iv ? CryptoJS.enc.Utf8.parse(iv.substring(0, 8)) : null;

      const cfg = {
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
        iv: ivUtf8
      };

      const decrypted = CryptoJS.DES.decrypt(data, keyUtf8, cfg);
      return decrypted.toString(CryptoJS.enc.Utf8);
    } catch (error) {
      console.error('DES 解密失败:', error);
      return null;
    }
  }
}

3. 哈希函数示例

// 在 CryptoUtil 类中添加哈希方法
class CryptoUtil {
  // ... 之前的加解密方法 ...

  /**
   * MD5 哈希
   * @param {string} data 待哈希数据
   * @returns {string} 哈希结果(十六进制)
   */
  static md5(data) {
    return CryptoJS.MD5(data).toString();
  }

  /**
   * SHA1 哈希
   * @param {string} data 待哈希数据
   * @returns {string} 哈希结果(十六进制)
   */
  static sha1(data) {
    return CryptoJS.SHA1(data).toString();
  }

  /**
   * SHA256 哈希
   * @param {string} data 待哈希数据
   * @returns {string} 哈希结果(十六进制)
   */
  static sha256(data) {
    return CryptoJS.SHA256(data).toString();
  }

  /**
   * HMAC-SHA256 签名
   * @param {string} data 待签名数据
   * @param {string} key 密钥
   * @returns {string} 签名结果(十六进制)
   */
  static hmacSha256(data, key) {
    return CryptoJS.HmacSHA256(data, key).toString();
  }

  /**
   * Base64 编码
   * @param {string} data 待编码数据
   * @returns {string} Base64 编码结果
   */
  static base64Encode(data) {
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data));
  }

  /**
   * Base64 解码
   * @param {string} data Base64 数据
   * @returns {string} 解码后的字符串
   */
  static base64Decode(data) {
    return CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8);
  }
}

4. 使用示例

页面中使用

// pages/index/index.js
const CryptoUtil = require('../../utils/cryptoUtil.js');

Page({
  data: {
    originalText: 'Hello, 微信小程序!',
    encryptedText: '',
    decryptedText: '',
    hashResult: ''
  },

  onLoad() {
    this.testEncryption();
  },

  testEncryption() {
    // 测试数据
    const text = this.data.originalText;
    const key = '0123456789abcdef';  // 16字节密钥
    const iv = 'fedcba9876543210';   // 16字节向量

    // 1. AES 加密解密
    const encrypted = CryptoUtil.aesEncrypt(text, key, iv);
    const decrypted = CryptoUtil.aesDecrypt(encrypted, key, iv);

    console.log('AES 加密结果:', encrypted);
    console.log('AES 解密结果:', decrypted);

    // 2. MD5 哈希
    const md5Hash = CryptoUtil.md5(text);
    console.log('MD5 哈希:', md5Hash);

    // 3. SHA256 哈希
    const sha256Hash = CryptoUtil.sha256(text);
    console.log('SHA256 哈希:', sha256Hash);

    // 4. Base64 编解码
    const base64Encoded = CryptoUtil.base64Encode(text);
    const base64Decoded = CryptoUtil.base64Decode(base64Encoded);
    console.log('Base64 编码:', base64Encoded);
    console.log('Base64 解码:', base64Decoded);

    this.setData({
      encryptedText: encrypted,
      decryptedText: decrypted,
      hashResult: md5Hash
    });
  },

  // 实际应用:加密用户数据
  encryptUserData() {
    const userData = {
      userId: '12345',
      username: '张三',
      timestamp: Date.now()
    };

    const jsonStr = JSON.stringify(userData);
    const key = 'mySecretKey123456'; // 实际应用中应从安全位置获取
    const iv = 'initialVector123';

    // 加密数据
    const encrypted = CryptoUtil.aesEncrypt(jsonStr, key, iv);

    // 发送到服务器
    wx.request({
      url: 'https://api.example.com/save',
      method: 'POST',
      data: {
        encryptedData: encrypted,
        // 可以同时发送哈希值用于验证
        signature: CryptoUtil.hmacSha256(encrypted, key)
      },
      success(res) {
        console.log('加密数据发送成功');
      }
    });
  }
});

WXML 页面

<!-- pages/index/index.wxml -->
<view class="container">
  <view class="section">
    <text class="title">原始文本:</text>
    <text>{{originalText}}</text>
  </view>

  <view class="section">
    <text class="title">AES 加密结果:</text>
    <text class="encrypted">{{encryptedText}}</text>
  </view>

  <view class="section">
    <text class="title">AES 解密结果:</text>
    <text>{{decryptedText}}</text>
  </view>

  <view class="section">
    <text class="title">MD5 哈希值:</text>
    <text class="hash">{{hashResult}}</text>
  </view>

  <button type="primary" bindtap="encryptUserData">
    加密并发送用户数据
  </button>
</view>

WXSS 样式

/* pages/index/index.wxss */
.container {
  padding: 20rpx;
}

.section {
  margin: 30rpx 0;
  padding: 20rpx;
  background-color: #f5f5f5;
  border-radius: 10rpx;
}

.title {
  font-weight: bold;
  color: #333;
  display: block;
  margin-bottom: 10rpx;
}

.encrypted {
  word-break: break-all;
  font-size: 24rpx;
  color: #e44d26;
}

.hash {
  font-family: monospace;
  word-break: break-all;
  font-size: 24rpx;
  color: #1890ff;
}

5. 注意事项

密钥管理

性能考虑

安全性

小程序限制

6. 优化建议

// 添加缓存机制
class CryptoUtil {
  static cache = new Map();

  static getCachedEncrypt(data, key, iv) {
    const cacheKey = `encrypt_${data}_${key}_${iv}`;
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    const result = this.aesEncrypt(data, key, iv);
    this.cache.set(cacheKey, result);
    return result;
  }

  // 添加错误重试机制
  static safeEncrypt(data, key, iv, retryCount = 3) {
    for (let i = 0; i < retryCount; i++) {
      try {
        return this.aesEncrypt(data, key, iv);
      } catch (error) {
        if (i === retryCount - 1) throw error;
        console.warn(`加密失败,第${i + 1}次重试`);
      }
    }
  }
}

这个示例提供了完整的 Crypto.js 在小程序中的使用方案,包括安装、基础加解密、哈希函数、实际应用和注意事项。

相关推荐