加密通信:Vue 3 + Web Crypto API的端到端加密实践

加密通信:Vue 3 + Web Crypto API的端到端加密实践

引言

大家好,欢迎来到今天的讲座!今天我们要聊一聊如何在 Vue 3 项目中使用 Web Crypto API 实现端到端加密。听起来是不是有点高大上?别担心,我会用轻松诙谐的语言,带你一步步实现这个功能。如果你已经熟悉了 Vue 3 和 JavaScript 的基础,那么今天的内容对你来说将会是一次有趣的探索。

什么是端到端加密?

端到端加密(End-to-End Encryption, E2EE)是一种加密技术,确保只有通信的双方能够读取消息内容。即使消息在传输过程中被截获,第三方也无法解密这些消息。E2EE 广泛应用于即时通讯应用、电子邮件和其他需要保护隐私的场景。

简单的例子

想象一下你和朋友通过信鸽传递秘密信息。为了让其他人无法读懂你们的信件,你们决定使用一种只有你们两个人知道的密码。这样,即使信鸽被别人抓住,他们也看不懂信中的内容。这就是端到端加密的基本原理。

Web Crypto API 是什么?

Web Crypto API 是浏览器内置的一组加密工具,允许开发者在客户端进行加密操作。它提供了多种加密算法,包括 AES、RSA、ECDSA 等,可以用于生成密钥、加密、解密、签名和验证等操作。

为什么选择 Web Crypto API?

  1. 安全性:Web Crypto API 是由浏览器厂商维护的,经过严格的安全审查,确保其安全性。
  2. 跨平台:只要你使用的浏览器支持 Web Crypto API,代码就可以在任何设备上运行。
  3. 性能:Web Crypto API 使用底层的硬件加速,因此加密和解密的速度非常快。

准备工作

在开始之前,确保你已经安装了 Vue 3 和 Node.js。我们还将使用一些常见的开发工具,如 npmyarn 来管理依赖。

创建 Vue 3 项目

如果你还没有创建 Vue 3 项目,可以通过以下命令快速创建:

npm init vue@latest

按照提示完成项目初始化后,进入项目目录并启动开发服务器:

cd my-vue-app
npm install
npm run dev

第一步:生成密钥对

在端到端加密中,通常会使用非对称加密算法(如 RSA 或 ECC)。非对称加密使用一对密钥:公钥和私钥。公钥用于加密,私钥用于解密。我们将使用 Web Crypto API 生成一个密钥对。

代码示例:生成 RSA 密钥对

async function generateKeyPair() {
  const keyPair = await crypto.subtle.generateKey(
    {
      name: "RSA-OAEP",
      modulusLength: 2048,
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: "SHA-256"
    },
    true, // 是否可导出密钥
    ["encrypt", "decrypt"] // 密钥用途
  );

  return keyPair;
}

// 调用函数并打印结果
generateKeyPair().then(keyPair => {
  console.log("Public Key:", keyPair.publicKey);
  console.log("Private Key:", keyPair.privateKey);
});

解释

  • crypto.subtle.generateKey():这是 Web Crypto API 中用于生成密钥对的函数。
  • modulusLength:指定 RSA 密钥的长度,2048 位是一个常见的选择。
  • publicExponent:指定 RSA 的公钥指数,通常使用 0x010001(即 65537)。
  • hash:指定用于加密的哈希算法,这里我们使用 SHA-256。
  • true:表示我们可以将生成的密钥导出为 JSON Web Key (JWK) 格式。
  • ["encrypt", "decrypt"]:指定密钥的用途,这里我们需要同时加密和解密。

第二步:导出和导入密钥

生成的密钥对通常是不可直接使用的,因为它们是浏览器内部的对象。为了在不同页面或设备之间共享密钥,我们需要将它们导出为 JWK 格式,并在需要时重新导入。

代码示例:导出和导入密钥

async function exportKey(key) {
  const exportedKey = await crypto.subtle.exportKey("jwk", key);
  return exportedKey;
}

async function importKey(jwk, isPrivate) {
  const importedKey = await crypto.subtle.importKey(
    "jwk",
    jwk,
    {
      name: "RSA-OAEP",
      hash: "SHA-256"
    },
    true, // 是否可导出
    isPrivate ? ["decrypt"] : ["encrypt"]
  );
  return importedKey;
}

// 示例:导出公钥并重新导入
generateKeyPair().then(async keyPair => {
  const exportedPublicKey = await exportKey(keyPair.publicKey);
  console.log("Exported Public Key:", exportedPublicKey);

  const importedPublicKey = await importKey(exportedPublicKey, false);
  console.log("Imported Public Key:", importedPublicKey);
});

解释

  • crypto.subtle.exportKey():将密钥导出为 JWK 格式。
  • crypto.subtle.importKey():将 JWK 格式的密钥重新导入为浏览器可用的密钥对象。
  • isPrivate:根据是否是私钥来设置密钥的用途。

第三步:加密和解密消息

现在我们已经有了密钥对,接下来就是加密和解密消息了。我们将使用 RSA-OAEP 算法进行加密,这是一种基于 RSA 的安全加密算法。

代码示例:加密和解密消息

async function encryptMessage(publicKey, message) {
  const encoder = new TextEncoder();
  const encodedMessage = encoder.encode(message);

  const encryptedMessage = await crypto.subtle.encrypt(
    {
      name: "RSA-OAEP"
    },
    publicKey,
    encodedMessage
  );

  return encryptedMessage;
}

async function decryptMessage(privateKey, encryptedMessage) {
  const decryptedMessage = await crypto.subtle.decrypt(
    {
      name: "RSA-OAEP"
    },
    privateKey,
    encryptedMessage
  );

  const decoder = new TextDecoder();
  return decoder.decode(decryptedMessage);
}

// 示例:加密和解密消息
generateKeyPair().then(async keyPair => {
  const message = "Hello, World!";
  const encrypted = await encryptMessage(keyPair.publicKey, message);
  console.log("Encrypted Message:", encrypted);

  const decrypted = await decryptMessage(keyPair.privateKey, encrypted);
  console.log("Decrypted Message:", decrypted);
});

解释

  • TextEncoderTextDecoder:用于将字符串转换为字节数组,以及将字节数组转换回字符串。
  • crypto.subtle.encrypt():使用公钥加密消息。
  • crypto.subtle.decrypt():使用私钥解密消息。

第四步:在 Vue 3 中集成加密功能

现在我们已经实现了基本的加密和解密功能,接下来将其集成到 Vue 3 项目中。我们将创建一个简单的聊天应用,用户可以在其中发送加密消息。

1. 创建 Vuex Store

为了管理密钥和消息状态,我们将使用 Vuex 作为状态管理库。

// store/index.js
import { createStore } from 'vuex';

export default createStore({
  state: {
    publicKey: null,
    privateKey: null,
    messages: []
  },
  mutations: {
    setKeys(state, { publicKey, privateKey }) {
      state.publicKey = publicKey;
      state.privateKey = privateKey;
    },
    addMessage(state, message) {
      state.messages.push(message);
    }
  },
  actions: {
    async generateKeys({ commit }) {
      const keyPair = await generateKeyPair();
      commit('setKeys', keyPair);
    },
    async sendMessage({ state }, message) {
      const encryptedMessage = await encryptMessage(state.publicKey, message);
      commit('addMessage', { text: message, encrypted: encryptedMessage });
    },
    async decryptMessage({ state }, encryptedMessage) {
      return await decryptMessage(state.privateKey, encryptedMessage);
    }
  }
});

2. 创建聊天组件

接下来,我们创建一个简单的聊天组件,用户可以在其中输入消息并发送加密后的消息。

<template>
  <div class="chat">
    <h1>端到端加密聊天</h1>
    <ul>
      <li v-for="(message, index) in messages" :key="index">
        {{ message.text }}
      </li>
    </ul>
    <input v-model="newMessage" placeholder="输入消息" />
    <button @click="sendMessage">发送</button>
  </div>
</template>

<script>
import { computed } from 'vue';
import { useStore } from 'vuex';

export default {
  setup() {
    const store = useStore();

    const newMessage = ref('');
    const messages = computed(() => store.state.messages);

    const sendMessage = async () => {
      if (newMessage.value.trim()) {
        await store.dispatch('sendMessage', newMessage.value);
        newMessage.value = '';
      }
    };

    return {
      newMessage,
      messages,
      sendMessage
    };
  }
};
</script>

3. 初始化 Vuex Store

最后,在 main.js 中初始化 Vuex Store,并调用 generateKeys 动作生成密钥对。

import { createApp } from 'vue';
import App from './App.vue';
import store from './store';

createApp(App).use(store).mount('#app');

store.dispatch('generateKeys');

结论

通过今天的讲座,我们学习了如何在 Vue 3 项目中使用 Web Crypto API 实现端到端加密。我们从生成密钥对、导出和导入密钥,再到加密和解密消息,最后将这些功能集成到了一个简单的聊天应用中。

虽然今天我们只实现了基本的功能,但在实际应用中,你还可以进一步优化和扩展,例如:

  • 密钥存储:使用浏览器的 IndexedDBLocalStorage 存储用户的密钥对。
  • 身份验证:结合 JWT 或 OAuth2 实现用户身份验证,确保只有授权用户可以访问密钥。
  • 消息签名:使用 ECDSA 算法为每条消息添加数字签名,确保消息的完整性和来源的真实性。

希望今天的讲座对你有所帮助!如果你有任何问题或想法,欢迎在评论区留言。编码愉快! 😊


参考资料:

  • [MDN Web Docs – Web Crypto API](MDN Web Docs)
  • [W3C Web Cryptography API Specification](W3C Web Cryptography API Specification)

感谢大家的聆听,下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注