Browser-Side Crypto in Practice: Web Crypto API and SM2/SM3/SM4

前端安全(Updated May 18, 2026)

Why Encrypt in the Browser?

Traditional flows send data to a server for crypto work—which creates privacy risk:

Traditional: plaintext → network → server encrypts → ciphertext back
Risk: plaintext may be intercepted; server may log data

Browser-side: plaintext → local encrypt → ciphertext
Benefit: plaintext never leaves the device

ToolsKu's 30+ crypto tools run entirely in the browser with zero uploads.


Web Crypto API: Native Browser Crypto

Capabilities

Web Crypto API is a W3C standard supported in all modern browsers:

// Feature detection
if (window.crypto?.subtle) {
  // Web Crypto API available
}
Category Algorithms Key sizes
Symmetric AES-GCM, AES-CBC, AES-CTR 128/192/256
Asymmetric RSA-OAEP, RSA-PSS, ECDSA 2048/4096
Key derivation PBKDF2, HKDF, ECDH -
Hash SHA-1, SHA-256, SHA-384, SHA-512 -
HMAC HMAC (with hashes above) -

AES-256-GCM end-to-end

async function aesGcmEncrypt(plaintext: string, password: string) {
  const enc = new TextEncoder();

  // 1. Derive key from password (PBKDF2)
  const salt = crypto.getRandomValues(new Uint8Array(16));
  const keyMaterial = await crypto.subtle.importKey(
    'raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']
  );
  const key = await crypto.subtle.deriveKey(
    { name: 'PBKDF2', salt, iterations: 600000, hash: 'SHA-256' },
    keyMaterial,
    { name: 'AES-GCM', length: 256 },
    false,
    ['encrypt']
  );

  // 2. Random IV
  const iv = crypto.getRandomValues(new Uint8Array(12));

  // 3. Encrypt
  const ciphertext = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv },
    key,
    enc.encode(plaintext)
  );

  // 4. Concatenate: salt + iv + ciphertext
  return concatBuffers(salt, iv, ciphertext);
}

Security decisions

Decision Choice Rationale
Symmetric mode AES-GCM (not CBC) Authenticated encryption, tamper-resistant
Key derivation PBKDF2 + SHA-256 Standard, widely supported
Iterations 600,000 OWASP 2023 minimum recommendation
IV length 12 bytes (96 bits) Recommended for GCM
Salt 16 random bytes Mitigates rainbow tables

National Algorithms: JS Implementation Challenges

Algorithm map

Algorithm Type International analog ToolsKu
SM2 Asymmetric encrypt/sign ECDSA (P-256) sm-crypto
SM3 Hash SHA-256 sm-crypto
SM4 Symmetric AES-128 sm-crypto

Using sm-crypto

import { sm2, sm3, sm4 } from 'sm-crypto';

// SM2 key pair
const keyPair = sm2.generateKeyPairHex();
// publicKey: keyPair.publicKey (130 hex chars, uncompressed)
// privateKey: keyPair.privateKey (64 hex chars)

// SM2 encrypt (C1C3C4 mode, national standard)
const cipherMode = 1; // 1 = C1C3C4, 0 = C1C2C3
const ciphertext = sm2.doEncrypt(msg, keyPair.publicKey, cipherMode);

// SM2 decrypt
const plaintext = sm2.doDecrypt(ciphertext, keyPair.privateKey, cipherMode);

// SM3 hash
const hash = sm3('message');

// SM4 encrypt (ECB mode)
const key = '0123456789abcdeffedcba9876543210'; // 128-bit hex
const encrypted = sm4.encrypt(msg, key);

Performance comparison

Operation Web Crypto (AES-256-GCM) sm-crypto (SM4) Ratio
1MB encrypt 2ms 45ms 22x
1MB decrypt 2ms 42ms 21x
Key generation 0.5ms 3ms 6x

Web Crypto is 20×+ faster—native C/Rust (or hardware) under the hood vs pure JS big-integer math in sm-crypto.

Optimization strategies

  1. Web Workers: Offload SM2/SM4 to avoid blocking the UI thread
  2. Wasm acceleration: Community experiments compiling sm-crypto hot paths to Wasm
  3. Chunking: Encrypt large files in blocks with progress UI

Crypto Tool Architecture

Layering in ToolsKu

UI layer (React components)
     ↓
Crypto service layer (unified API)
     ↓
┌──────────────┬──────────────┐
│ Web Crypto   │ sm-crypto    │
│ (standard)   │ (national)   │
│ native       │ pure JS      │
└──────────────┴──────────────┘

Unified interface

interface CryptoService {
  encrypt(data: Uint8Array, key: CryptoKeyInput): Promise<Uint8Array>;
  decrypt(data: Uint8Array, key: CryptoKeyInput): Promise<Uint8Array>;
  generateKey(): Promise<CryptoKeyOutput>;
}

Standard and national algorithms implement the same interface—UI stays agnostic.

File encryption memory management

async function encryptFile(file: File, password: string) {
  // 1. Read file into memory
  const buffer = await file.arrayBuffer();

  // 2. Chunk large files (avoid OOM on single encrypt)
  const CHUNK_SIZE = 64 * 1024 * 1024; // 64MB
  if (buffer.byteLength > CHUNK_SIZE) {
    return encryptFileInChunks(buffer, password, CHUNK_SIZE);
  }

  // 3. Encrypt
  const result = await aesGcmEncrypt(new Uint8Array(buffer), password);

  // 4. Clear sensitive data
  buffer = null; // allow GC

  return result;
}

Common Crypto Mistakes

Mistake 1: Base64 ≠ encryption

Base64("password123") = "5a+G56CBMTIz"  ← reversible in a second
AES-256("password123") = "U2FsdGVkX1..."  ← useless without the key

Base64 is encoding, not encryption. Anyone can decode it.

Mistake 2: MD5/SHA-1 are not "encryption"

Hashes are one-way—you cannot "decrypt" them. Use them for integrity, not confidentiality.

  • MD5: broken—do not use for security
  • SHA-1: collision attacks—avoid
  • SHA-256/SM3: currently considered safe

Mistake 3: ECB mode is not secure

ECB: identical plaintext blocks → identical ciphertext (patterns leak)
CBC/GCM: identical plaintext blocks → different ciphertext (safe)

ToolsKu AES tools only offer GCM—no insecure ECB.


Summary

Browser-side crypto is production-ready today:

  • Web Crypto API: Standard algorithms (AES/RSA/SHA) at near-native speed
  • sm-crypto: National algorithms in pure JS for compliance
  • Zero-upload: Keys and data never leave the device

ToolsKu offers AES encryption, RSA encryption, SM2 encryption, SM3 hash, SM4 encryption, and 30+ more tools—all processed locally in your browser.

Try these browser-local tools — no sign-up required →

#加密#WebCrypto#国密#SM2#AES#安全