Angular中使用Crypto/rsa加密并在Golang中解密的实现方法

Angular中使用Crypto/rsa加密并在Golang中解密的实现方法 我有一个应用程序,需要在Angular中使用公钥进行加密,然后在Golang REST API中使用私钥进行解密。

我已经尝试了crypto/rsa加密,它是有效的。

请指导我。

5 回复

很高兴能帮上忙

更多关于Angular中使用Crypto/rsa加密并在Golang中解密的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢。

问题已解决。我在 Angular 端使用了错误的哈希算法。

我想在Angular端使用公钥加密载荷,然后在Golang端使用私钥解密。

我已经尝试过了。但在Golang端无法解密。

你有示例代码吗(包括Angular和Go的)?

你们是如何共享密钥的? 在Angular中你们使用哪种算法,在Go中又使用哪种算法?

在Angular中使用Crypto/rsa加密并在Golang中解密的实现方法

1. Angular端(前端)实现

首先安装必要的依赖:

npm install crypto-js

Angular加密服务示例:

// encryption.service.ts
import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';

@Injectable({
  providedIn: 'root'
})
export class EncryptionService {
  
  // 将PEM格式公钥转换为CryptoKey
  async importPublicKey(pemPublicKey: string): Promise<CryptoKey> {
    // 移除PEM格式的头部和尾部
    const pemHeader = "-----BEGIN PUBLIC KEY-----";
    const pemFooter = "-----END PUBLIC KEY-----";
    const pemContents = pemPublicKey
      .replace(pemHeader, '')
      .replace(pemFooter, '')
      .replace(/\s/g, '');
    
    // 将Base64转换为ArrayBuffer
    const binaryDer = this.base64ToArrayBuffer(pemContents);
    
    return await window.crypto.subtle.importKey(
      'spki',
      binaryDer,
      {
        name: 'RSA-OAEP',
        hash: { name: 'SHA-256' }
      },
      false,
      ['encrypt']
    );
  }

  // 使用RSA-OAEP加密数据
  async encryptWithPublicKey(publicKey: CryptoKey, data: string): Promise<string> {
    const encoder = new TextEncoder();
    const encodedData = encoder.encode(data);
    
    const encryptedData = await window.crypto.subtle.encrypt(
      {
        name: 'RSA-OAEP'
      },
      publicKey,
      encodedData
    );
    
    // 转换为Base64字符串
    return this.arrayBufferToBase64(encryptedData);
  }

  // 辅助方法:Base64转ArrayBuffer
  private base64ToArrayBuffer(base64: string): ArrayBuffer {
    const binaryString = window.atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
  }

  // 辅助方法:ArrayBuffer转Base64
  private arrayBufferToBase64(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (let i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
  }
}

组件中使用示例:

// app.component.ts
import { Component, OnInit } from '@angular/core';
import { EncryptionService } from './encryption.service';

@Component({
  selector: 'app-root',
  template: `
    <button (click)="encryptAndSend()">加密并发送</button>
  `
})
export class AppComponent implements OnInit {
  private publicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzXoQkQvKX7J8wJv6z6Z2
...(您的公钥内容)...
-----END PUBLIC KEY-----`;

  constructor(private encryptionService: EncryptionService) {}

  async encryptAndSend() {
    try {
      // 导入公钥
      const publicKey = await this.encryptionService.importPublicKey(this.publicKeyPem);
      
      // 要加密的数据
      const sensitiveData = JSON.stringify({
        username: 'john_doe',
        password: 'secret123',
        timestamp: new Date().toISOString()
      });
      
      // 加密数据
      const encryptedData = await this.encryptionService.encryptWithPublicKey(
        publicKey, 
        sensitiveData
      );
      
      // 发送到Golang后端
      const response = await fetch('https://your-api.com/decrypt', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ encryptedData })
      });
      
      const result = await response.json();
      console.log('解密结果:', result);
      
    } catch (error) {
      console.error('加密或发送失败:', error);
    }
  }
}

2. Golang端(后端)实现

生成RSA密钥对(一次性操作):

// generate_keys.go
package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "os"
)

func main() {
    // 生成2048位的RSA密钥对
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        panic(err)
    }

    // 保存私钥到文件
    privateKeyFile, err := os.Create("private.pem")
    if err != nil {
        panic(err)
    }
    defer privateKeyFile.Close()

    privateKeyPEM := &pem.Block{
        Type:  "RSA PRIVATE KEY",
        Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
    }
    
    if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil {
        panic(err)
    }

    // 保存公钥到文件
    publicKeyFile, err := os.Create("public.pem")
    if err != nil {
        panic(err)
    }
    defer publicKeyFile.Close()

    publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
    if err != nil {
        panic(err)
    }

    publicKeyPEM := &pem.Block{
        Type:  "PUBLIC KEY",
        Bytes: publicKeyBytes,
    }
    
    if err := pem.Encode(publicKeyFile, publicKeyPEM); err != nil {
        panic(err)
    }

    fmt.Println("密钥对已生成: private.pem, public.pem")
}

Golang REST API解密实现:

// main.go
package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/base64"
    "encoding/json"
    "encoding/pem"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

var privateKey *rsa.PrivateKey

// 初始化加载私钥
func init() {
    // 从文件加载私钥
    keyData, err := ioutil.ReadFile("private.pem")
    if err != nil {
        log.Fatal("无法读取私钥文件:", err)
    }

    block, _ := pem.Decode(keyData)
    if block == nil || block.Type != "RSA PRIVATE KEY" {
        log.Fatal("无效的私钥格式")
    }

    privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        log.Fatal("解析私钥失败:", err)
    }
}

// 请求结构体
type DecryptRequest struct {
    EncryptedData string `json:"encryptedData"`
}

// 响应结构体
type DecryptResponse struct {
    Success bool   `json:"success"`
    Data    string `json:"data,omitempty"`
    Error   string `json:"error,omitempty"`
}

// 解密处理器
func decryptHandler(w http.ResponseWriter, r *http.Request) {
    // 设置CORS头部
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")

    // 只接受POST请求
    if r.Method != "POST" {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }

    var req DecryptRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        sendError(w, "无效的请求格式", http.StatusBadRequest)
        return
    }

    // Base64解码加密数据
    encryptedBytes, err := base64.StdEncoding.DecodeString(req.EncryptedData)
    if err != nil {
        sendError(w, "Base64解码失败", http.StatusBadRequest)
        return
    }

    // 使用RSA-OAEP解密
    decryptedBytes, err := rsa.DecryptOAEP(
        sha256.New(),
        rand.Reader,
        privateKey,
        encryptedBytes,
        nil, // 标签参数
    )
    if err != nil {
        sendError(w, "解密失败", http.StatusBadRequest)
        return
    }

    // 返回解密后的数据
    response := DecryptResponse{
        Success: true,
        Data:    string(decryptedBytes),
    }
    
    json.NewEncoder(w).Encode(response)
}

func sendError(w http.ResponseWriter, message string, statusCode int) {
    response := DecryptResponse{
        Success: false,
        Error:   message,
    }
    w.WriteHeader(statusCode)
    json.NewEncoder(w).Encode(response)
}

func main() {
    http.HandleFunc("/decrypt", decryptHandler)
    
    fmt.Println("服务器启动在 :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

3. 测试示例

创建测试客户端:

// test_client.go
package main

import (
    "bytes"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/base64"
    "encoding/json"
    "encoding/pem"
    "fmt"
    "io/ioutil"
    "net/http"
)

func testEncryption() {
    // 模拟Angular端的加密
    publicKeyPEM := `-----BEGIN PUBLIC KEY-----
...(您的公钥内容)...
-----END PUBLIC KEY-----`

    block, _ := pem.Decode([]byte(publicKeyPEM))
    if block == nil {
        panic("无效的公钥")
    }

    pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        panic(err)
    }

    publicKey := pubInterface.(*rsa.PublicKey)

    // 要加密的数据
    data := `{"username":"test","password":"test123"}`
    
    // 使用RSA-OAEP加密
    encrypted, err := rsa.EncryptOAEP(
        sha256.New(),
        rand.Reader,
        publicKey,
        []byte(data),
        nil,
    )
    if err != nil {
        panic(err)
    }

    // Base64编码
    encryptedBase64 := base64.StdEncoding.EncodeToString(encrypted)

    // 发送到API
    requestBody, _ := json.Marshal(map[string]string{
        "encryptedData": encryptedBase64,
    })

    resp, err := http.Post("http://localhost:8080/decrypt", 
        "application/json", 
        bytes.NewBuffer(requestBody))
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println("API响应:", string(body))
}

func main() {
    testEncryption()
}

4. 注意事项

  1. 密钥管理:私钥必须安全存储,不应暴露给前端
  2. 加密限制:RSA加密有长度限制(对于2048位密钥,最多加密245字节)
  3. 性能考虑:对于大量数据,建议使用对称加密(如AES),用RSA加密对称密钥
  4. 错误处理:在实际应用中需要更完善的错误处理和日志记录
  5. 安全性:确保使用TLS/HTTPS传输加密数据

这个实现方案使用了RSA-OAEP with SHA-256,这是当前推荐的RSA加密方式,提供了良好的安全性和兼容性。

回到顶部