Web Cryptography TypeScript Samples

Web TypeScript cryptography examples including hash calculation, symmetric encryption, and Base64 encoding

Key Facts

Category
TypeScript
Items
3
Format Families
markdown

Sample Overview

Web TypeScript cryptography examples including hash calculation, symmetric encryption, and Base64 encoding This sample set belongs to TypeScript and can be used to test related workflows inside Elysia Tools.

💻 Hash Calculation typescript

🟢 simple ⭐⭐⭐

Calculate MD5, SHA-1, SHA-256, SHA-384, SHA-512 hash values using Web Crypto API

⏱️ 20 min 🏷️ typescript, web, cryptography, hash
Prerequisites: Basic TypeScript, Web Crypto API
// Web TypeScript Hash Calculation Examples
// Using Web Crypto API for secure hash computation

// 1. SHA Hash Calculator
class SHAHashCalculator {
  // Calculate SHA-256 hash
  async sha256(message: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    return this.bufferToHex(hashBuffer);
  }

  // Calculate SHA-384 hash
  async sha384(message: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-384', data);
    return this.bufferToHex(hashBuffer);
  }

  // Calculate SHA-512 hash
  async sha512(message: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-512', data);
    return this.bufferToHex(hashBuffer);
  }

  // Calculate SHA-1 hash (for legacy compatibility)
  async sha1(message: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-1', data);
    return this.bufferToHex(hashBuffer);
  }

  // Convert ArrayBuffer to hex string
  private bufferToHex(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
}

// 2. File Hash Calculator
class FileHashCalculator {
  private shaCalculator = new SHAHashCalculator();

  // Calculate hash of file
  async hashFile(file: File, algorithm: 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256'): Promise<string> {
    const arrayBuffer = await file.arrayBuffer();
    const hashBuffer = await crypto.subtle.digest(algorithm, arrayBuffer);
    return this.bufferToHex(hashBuffer);
  }

  // Calculate hash with progress
  async hashFileWithProgress(
    file: File,
    algorithm: 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256',
    onProgress: (progress: number) => void
  ): Promise<string> {
    const chunkSize = 1024 * 1024; // 1MB chunks
    let offset = 0;

    // For progress tracking, we'll read in chunks
    while (offset < file.size) {
      const end = Math.min(offset + chunkSize, file.size);
      offset = end;
      const progress = Math.floor((offset / file.size) * 100);
      onProgress(progress);
    }

    // Actually hash the file
    return this.hashFile(file, algorithm);
  }

  // Calculate multiple hashes
  async hashMultipleAlgorithms(file: File): Promise<Record<string, string>> {
    const arrayBuffer = await file.arrayBuffer();

    const algorithms = ['SHA-256', 'SHA-384', 'SHA-512'] as const;
    const hashes: Record<string, string> = {};

    for (const algo of algorithms) {
      const hashBuffer = await crypto.subtle.digest(algo, arrayBuffer);
      hashes[algo] = this.bufferToHex(hashBuffer);
    }

    return hashes;
  }

  private bufferToHex(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
}

// 3. HMAC Calculator
class HMACCalculator {
  // Calculate HMAC-SHA256
  async hmacSha256(message: string, key: string): Promise<string> {
    const encoder = new TextEncoder();
    const keyData = encoder.encode(key);
    const messageData = encoder.encode(message);

    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['sign']
    );

    const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
    return this.bufferToHex(signature);
  }

  // Calculate HMAC-SHA512
  async hmacSha512(message: string, key: string): Promise<string> {
    const encoder = new TextEncoder();
    const keyData = encoder.encode(key);
    const messageData = encoder.encode(message);

    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: 'SHA-512' },
      false,
      ['sign']
    );

    const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
    return this.bufferToHex(signature);
  }

  // Verify HMAC
  async verifyHMAC(
    message: string,
    key: string,
    signature: string,
    algorithm: 'SHA-256' | 'SHA-512' = 'SHA-256'
  ): Promise<boolean> {
    const encoder = new TextEncoder();
    const keyData = encoder.encode(key);
    const messageData = encoder.encode(message);

    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: algorithm },
      false,
      ['verify']
    );

    const signatureBytes = this.hexToBuffer(signature);

    const isValid = await crypto.subtle.verify(
      'HMAC',
      cryptoKey,
      signatureBytes,
      messageData
    );

    return isValid;
  }

  private bufferToHex(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }

  private hexToBuffer(hex: string): Uint8Array {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < bytes.length; i++) {
      bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return bytes;
  }
}

// 4. Hash Comparison Utility
class HashComparison {
  // Constant-time comparison to prevent timing attacks
  static constantTimeCompare(hash1: string, hash2: string): boolean {
    if (hash1.length !== hash2.length) {
      return false;
    }

    let result = 0;
    for (let i = 0; i < hash1.length; i++) {
      result |= hash1.charCodeAt(i) ^ hash2.charCodeAt(i);
    }

    return result === 0;
  }

  // Compare hashes (case-insensitive)
  static compare(hash1: string, hash2: string): boolean {
    return hash1.toLowerCase() === hash2.toLowerCase();
  }

  // Find matching hash in list
  static findMatch(targetHash: string, hashList: string[]): string | null {
    const normalized = targetHash.toLowerCase();

    for (const hash of hashList) {
      if (hash.toLowerCase() === normalized) {
        return hash;
      }
    }

    return null;
  }
}

// 5. Password Hasher (PBKDF2)
class PasswordHasher {
  // Hash password with PBKDF2
  async hashPassword(
    password: string,
    salt?: string,
    iterations: number = 100000
  ): Promise<{ hash: string; salt: string }> {
    // Generate salt if not provided
    const saltBytes = salt
      ? this.hexToBuffer(salt)
      : crypto.getRandomValues(new Uint8Array(16));

    const encoder = new TextEncoder();
    const passwordData = encoder.encode(password);

    const importedKey = await crypto.subtle.importKey(
      'raw',
      passwordData,
      { name: 'PBKDF2' },
      false,
      ['deriveBits']
    );

    const hashBuffer = await crypto.subtle.deriveBits(
      {
        name: 'PBKDF2',
        salt: saltBytes,
        iterations: iterations,
        hash: 'SHA-256'
      },
      importedKey,
      256
    );

    return {
      hash: this.bufferToHex(hashBuffer),
      salt: this.bufferToHex(saltBytes)
    };
  }

  // Verify password
  async verifyPassword(
    password: string,
    hash: string,
    salt: string,
    iterations: number = 100000
  ): Promise<boolean> {
    const { hash: computedHash } = await this.hashPassword(password, salt, iterations);
    return HashComparison.constantTimeCompare(hash, computedHash);
  }

  // Hash password with custom parameters
  async hashPasswordAdvanced(
    password: string,
    options: {
      saltLength?: number;
      iterations?: number;
      hashLength?: number;
    } = {}
  ): Promise<{ hash: string; salt: string; iterations: number }> {
    const {
      saltLength = 16,
      iterations = 100000,
      hashLength = 32
    } = options;

    const saltBytes = crypto.getRandomValues(new Uint8Array(saltLength));
    const encoder = new TextEncoder();
    const passwordData = encoder.encode(password);

    const importedKey = await crypto.subtle.importKey(
      'raw',
      passwordData,
      { name: 'PBKDF2' },
      false,
      ['deriveBits']
    );

    const hashBuffer = await crypto.subtle.deriveBits(
      {
        name: 'PBKDF2',
        salt: saltBytes,
        iterations: iterations,
        hash: 'SHA-256'
      },
      importedKey,
      hashLength * 8
    );

    return {
      hash: this.bufferToHex(hashBuffer),
      salt: this.bufferToHex(saltBytes),
      iterations
    };
  }

  private bufferToHex(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }

  private hexToBuffer(hex: string): Uint8Array {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < bytes.length; i++) {
      bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return bytes;
  }
}

// 6. Checksum Calculator
class ChecksumCalculator {
  // Simple checksum (sum of bytes)
  calculateSimpleChecksum(data: string): number {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(data);

    let sum = 0;
    for (const byte of bytes) {
      sum += byte;
    }

    return sum & 0xFF; // Keep only lowest byte
  }

  // XOR checksum
  calculateXORChecksum(data: string): number {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(data);

    let checksum = 0;
    for (const byte of bytes) {
      checksum ^= byte;
    }

    return checksum;
  }

  // CRC-32 checksum
  calculateCRC32(data: string): number {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(data);

    let crc = 0xFFFFFFFF;

    for (const byte of bytes) {
      crc ^= byte;
      for (let i = 0; i < 8; i++) {
        if (crc & 1) {
          crc = (crc >>> 1) ^ 0xEDB88320;
        } else {
          crc = crc >>> 1;
        }
      }
    }

    return (crc ^ 0xFFFFFFFF) >>> 0;
  }

  // Adler-32 checksum
  calculateAdler32(data: string): number {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(data);

    let a = 1;
    let b = 0;

    for (const byte of bytes) {
      a = (a + byte) % 65521;
      b = (b + a) % 65521;
    }

    return (b << 16) | a;
  }
}

// 7. Hash Utility Functions
class HashUtils {
  // Generate random hash
  static async generateRandomHash(algorithm: 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256'): Promise<string> {
    const randomBytes = crypto.getRandomValues(new Uint8Array(32));
    const hashBuffer = await crypto.subtle.digest(algorithm, randomBytes);
    return HashUtils.bufferToHex(hashBuffer);
  }

  // Generate hash from multiple inputs
  static async combineHashes(hashes: string[]): Promise<string> {
    const combined = hashes.join('');
    const encoder = new TextEncoder();
    const data = encoder.encode(combined);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    return HashUtils.bufferToHex(hashBuffer);
  }

  // Hash object (JSON)
  static async hashObject(obj: any): Promise<string> {
    const json = JSON.stringify(obj);
    const encoder = new TextEncoder();
    const data = encoder.encode(json);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    return HashUtils.bufferToHex(hashBuffer);
  }

  private static bufferToHex(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
}

// Usage Examples
async function demonstrateHashCalculation() {
  console.log('=== Web TypeScript Hash Calculation Examples ===\n');

  const shaCalc = new SHAHashCalculator();
  const hmacCalc = new HMACCalculator();
  const passwordHasher = new PasswordHasher();
  const checksumCalc = new ChecksumCalculator();

  // 1. SHA hashes
  console.log('--- 1. SHA Hashes ---');
  const message = 'Hello, World!';

  const sha256 = await shaCalc.sha256(message);
  const sha384 = await shaCalc.sha384(message);
  const sha512 = await shaCalc.sha512(message);

  console.log(`SHA-256: ${sha256}`);
  console.log(`SHA-384: ${sha384}`);
  console.log(`SHA-512: ${sha512}`);

  // 2. HMAC
  console.log('\n--- 2. HMAC ---');
  const key = 'secret-key';
  const hmac = await hmacCalc.hmacSha256(message, key);
  console.log(`HMAC-SHA256: ${hmac}`);

  const verified = await hmacCalc.verifyHMAC(message, key, hmac);
  console.log(`Verified: ${verified}`);

  // 3. Password hashing
  console.log('\n--- 3. Password Hashing ---');
  const password = 'MySecurePassword123!';
  const { hash: pwdHash, salt } = await passwordHasher.hashPassword(password);
  console.log(`Password hash: ${pwdHash}`);
  console.log(`Salt: ${salt}`);

  const isValid = await passwordHasher.verifyPassword(password, pwdHash, salt);
  console.log(`Password valid: ${isValid}`);

  // 4. Checksums
  console.log('\n--- 4. Checksums ---');
  const data = 'The quick brown fox jumps over the lazy dog';

  console.log(`Simple checksum: ${checksumCalc.calculateSimpleChecksum(data)}`);
  console.log(`XOR checksum: ${checksumCalc.calculateXORChecksum(data)}`);
  console.log(`CRC-32: ${checksumCalc.calculateCRC32(data)}`);
  console.log(`Adler-32: ${checksumCalc.calculateAdler32(data)}`);

  // 5. Hash utilities
  console.log('\n--- 5. Hash Utilities ---');
  const randomHash = await HashUtils.generateRandomHash();
  console.log(`Random hash: ${randomHash}`);

  const objHash = await HashUtils.hashObject({ name: 'Alice', age: 30 });
  console.log(`Object hash: ${objHash}`);

  console.log('\n=== All Hash Calculation Examples Completed ===');
}

// Export functions
export { SHAHashCalculator, FileHashCalculator, HMACCalculator, HashComparison, PasswordHasher, ChecksumCalculator, HashUtils };
export { demonstrateHashCalculation };

💻 Base64 Encoding typescript

🟢 simple ⭐⭐

Encode and decode data to/from Base64 format with support for Unicode and binary data

⏱️ 15 min 🏷️ typescript, web, cryptography, base64
Prerequisites: Basic TypeScript, Base64 encoding
// Web TypeScript Base64 Encoding Examples
// Encoding and decoding data to/from Base64 format

// 1. Basic Base64 Encoder/Decoder
class Base64Coder {
  // Encode string to Base64
  encode(input: string): string {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(input);
    return this.bufferToBase64(bytes);
  }

  // Decode Base64 to string
  decode(input: string): string {
    const bytes = this.base64ToBuffer(input);
    const decoder = new TextDecoder();
    return decoder.decode(bytes);
  }

  // Encode Uint8Array to Base64
  encodeBytes(bytes: Uint8Array): string {
    return this.bufferToBase64(bytes);
  }

  // Decode Base64 to Uint8Array
  decodeBytes(input: string): Uint8Array {
    return this.base64ToBuffer(input);
  }

  // Convert ArrayBuffer/Base64 to Base64 string
  private bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    let binary = '';
    for (const byte of bytes) {
      binary += String.fromCharCode(byte);
    }
    return btoa(binary);
  }

  // Convert Base64 string to Uint8Array
  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// 2. URL-Safe Base64 Encoder/Decoder
class URLSafeBase64Coder {
  // Encode to URL-safe Base64
  encode(input: string): string {
    const base64 = btoa(input);
    return this.makeURLSafe(base64);
  }

  // Decode from URL-safe Base64
  decode(input: string): string {
    const base64 = this.makeStandard(input);
    return atob(base64);
  }

  // Encode bytes to URL-safe Base64
  encodeBytes(bytes: Uint8Array): string {
    const base64 = this.bufferToBase64(bytes);
    return this.makeURLSafe(base64);
  }

  // Decode URL-safe Base64 to bytes
  decodeBytes(input: string): Uint8Array {
    const base64 = this.makeStandard(input);
    return this.base64ToBuffer(base64);
  }

  // Convert to URL-safe format
  private makeURLSafe(base64: string): string {
    return base64
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '');
  }

  // Convert to standard format
  private makeStandard(urlSafe: string): string {
    let base64 = urlSafe
      .replace(/-/g, '+')
      .replace(/_/g, '/');

    // Add padding
    while (base64.length % 4) {
      base64 += '=';
    }

    return base64;
  }

  private bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    let binary = '';
    for (const byte of bytes) {
      binary += String.fromCharCode(byte);
    }
    return btoa(binary);
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// 3. Unicode Base64 Encoder/Decoder
class UnicodeBase64Coder {
  // Encode Unicode string to Base64
  encode(input: string): string {
    // Escape Unicode characters
    const escaped = encodeURIComponent(input);
    const binary = unescape(escaped);
    return btoa(binary);
  }

  // Decode Base64 to Unicode string
  decode(input: string): string {
    const binary = atob(input);
    const escaped = escape(binary);
    return decodeURIComponent(escaped);
  }

  // Encode using UTF-8
  encodeUTF8(input: string): string {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(input);
    return this.bufferToBase64(bytes);
  }

  // Decode using UTF-8
  decodeUTF8(input: string): string {
    const bytes = this.base64ToBuffer(input);
    const decoder = new TextDecoder();
    return decoder.decode(bytes);
  }

  private bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    let binary = '';
    for (const byte of bytes) {
      binary += String.fromCharCode(byte);
    }
    return btoa(binary);
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// 4. File Base64 Encoder/Decoder
class FileBase64Coder {
  // Convert file to Base64
  async fileToBase64(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        const result = reader.result as string;
        // Remove data URL prefix (e.g., "data:image/png;base64,")
        const base64 = result.split(',')[1];
        resolve(base64);
      };

      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(file);
    });
  }

  // Convert file to Data URL
  async fileToDataURL(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        resolve(reader.result as string);
      };

      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(file);
    });
  }

  // Convert Base64 to Blob
  base64ToBlob(base64: string, mimeType: string = 'application/octet-stream'): Blob {
    const bytes = this.base64ToBuffer(base64);
    return new Blob([bytes], { type: mimeType });
  }

  // Convert Base64 to File
  base64ToFile(base64: string, fileName: string, mimeType: string = 'application/octet-stream'): File {
    const blob = this.base64ToBlob(base64, mimeType);
    return new File([blob], fileName, { type: mimeType });
  }

  // Convert file to Base64 with progress
  async fileToBase64WithProgress(
    file: File,
    onProgress: (progress: number) => void
  ): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        const result = reader.result as string;
        const base64 = result.split(',')[1];
        resolve(base64);
      };

      reader.onerror = () => reject(reader.error);

      if (reader.onprogress) {
        reader.onprogress = (event) => {
          if (event.lengthComputable) {
            const progress = Math.floor((event.loaded / event.total) * 100);
            onProgress(progress);
          }
        };
      }

      reader.readAsDataURL(file);
    });
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// 5. Image Base64 Encoder/Decoder
class ImageBase64Coder {
  private fileCoder = new FileBase64Coder();

  // Convert image file to Base64
  async imageToBase64(file: File): Promise<{
    base64: string;
    dataURL: string;
    mimeType: string;
  }> {
    const dataURL = await this.fileCoder.fileToDataURL(file);
    const base64 = dataURL.split(',')[1];
    const mimeType = file.type;

    return { base64, dataURL, mimeType };
  }

  // Convert Base64 to image element
  base64ToImage(base64: string, mimeType: string = 'image/png'): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const img = new Image();
      const dataURL = `data:${mimeType};base64,${base64}`;

      img.onload = () => resolve(img);
      img.onerror = () => reject(new Error('Failed to load image'));
      img.src = dataURL;
    });
  }

  // Resize image and convert to Base64
  async resizeAndEncode(
    file: File,
    maxWidth: number,
    maxHeight: number
  ): Promise<string> {
    const img = await this.fileCoder.fileToDataURL(file);

    return new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        if (!ctx) {
          reject(new Error('Failed to get canvas context'));
          return;
        }

        // Calculate new dimensions
        let width = image.width;
        let height = image.height;

        if (width > maxWidth) {
          height = (maxWidth / width) * height;
          width = maxWidth;
        }

        if (height > maxHeight) {
          width = (maxHeight / height) * width;
          height = maxHeight;
        }

        canvas.width = width;
        canvas.height = height;

        ctx.drawImage(image, 0, 0, width, height);

        const dataURL = canvas.toDataURL(file.type);
        const base64 = dataURL.split(',')[1];
        resolve(base64);
      };

      image.onerror = () => reject(new Error('Failed to load image'));
      image.src = img;
    });
  }

  // Get image dimensions from Base64
  async getImageDimensions(base64: string): Promise<{
    width: number;
    height: number;
  }> {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => {
        resolve({ width: img.width, height: img.height });
      };
      img.onerror = () => reject(new Error('Failed to load image'));
      img.src = `data:image/png;base64,${base64}`;
    });
  }
}

// 6. Base64 Utility Functions
class Base64Utils {
  // Check if string is valid Base64
  isValidBase64(str: string): boolean {
    try {
      return btoa(atob(str)) === str;
    } catch (e) {
      return false;
    }
  }

  // Get Base64 string length in bytes
  getByteLength(base64: string): number {
    const padding = (base64.match(/=/g) || []).length;
    return (base64.length * 3) / 4 - padding;
  }

  // Truncate Base64 string
  truncate(base64: string, maxLength: number): string {
    if (base64.length <= maxLength) {
      return base64;
    }
    return base64.substring(0, maxLength) + '...';
  }

  // Split Base64 into chunks
  chunk(base64: string, chunkSize: number): string[] {
    const chunks: string[] = [];
    for (let i = 0; i < base64.length; i += chunkSize) {
      chunks.push(base64.substring(i, Math.min(i + chunkSize, base64.length)));
    }
    return chunks;
  }

  // Concatenate Base64 chunks
  concat(chunks: string[]): string {
    return chunks.join('');
  }

  // Calculate Base64 checksum
  checksum(base64: string): number {
    const bytes = this.base64ToBuffer(base64);
    let sum = 0;
    for (const byte of bytes) {
      sum += byte;
    }
    return sum & 0xFF;
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// 7. Base64 Stream Encoder/Decoder
class Base64StreamCoder {
  // Encode stream to Base64
  async encodeStream(stream: ReadableStream): Promise<string> {
    const reader = stream.getReader();
    const chunks: Uint8Array[] = [];

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      chunks.push(value);
    }

    // Combine all chunks
    const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
    const combined = new Uint8Array(totalLength);

    let offset = 0;
    for (const chunk of chunks) {
      combined.set(chunk, offset);
      offset += chunk.length;
    }

    return this.bufferToBase64(combined);
  }

  // Decode Base64 to stream
  decodeStream(base64: string): ReadableStream {
    const bytes = this.base64ToBuffer(base64);

    return new ReadableStream({
      start(controller) {
        controller.enqueue(bytes);
        controller.close();
      }
    });
  }

  private bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    let binary = '';
    for (const byte of bytes) {
      binary += String.fromCharCode(byte);
    }
    return btoa(binary);
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }
}

// Usage Examples
async function demonstrateBase64Encoding() {
  console.log('=== Web TypeScript Base64 Encoding Examples ===\n');

  const coder = new Base64Coder();
  const urlSafeCoder = new URLSafeBase64Coder();
  const unicodeCoder = new UnicodeBase64Coder();
  const fileCoder = new FileBase64Coder();
  const imageCoder = new ImageBase64Coder();
  const utils = new Base64Utils();

  // 1. Basic encoding/decoding
  console.log('--- 1. Basic Encoding/Decoding ---');
  const text = 'Hello, World!';
  const encoded = coder.encode(text);
  const decoded = coder.decode(encoded);

  console.log(`Original: ${text}`);
  console.log(`Encoded: ${encoded}`);
  console.log(`Decoded: ${decoded}`);

  // 2. URL-safe encoding
  console.log('\n--- 2. URL-Safe Encoding ---');
  const urlSafeEncoded = urlSafeCoder.encode(text);
  console.log(`URL-safe encoded: ${urlSafeEncoded}`);
  console.log(`URL-safe decoded: ${urlSafeCoder.decode(urlSafeEncoded)}`);

  // 3. Unicode encoding
  console.log('\n--- 3. Unicode Encoding ---');
  const unicodeText = 'Hello, 世界! 🌍';
  const unicodeEncoded = unicodeCoder.encodeUTF8(unicodeText);
  const unicodeDecoded = unicodeCoder.decodeUTF8(unicodeEncoded);

  console.log(`Unicode original: ${unicodeText}`);
  console.log(`Unicode encoded: ${unicodeEncoded}`);
  console.log(`Unicode decoded: ${unicodeDecoded}`);

  // 4. Bytes encoding
  console.log('\n--- 4. Bytes Encoding ---');
  const bytes = new Uint8Array([72, 101, 108, 108, 111]);
  const bytesEncoded = coder.encodeBytes(bytes);
  console.log(`Bytes encoded: ${bytesEncoded}`);

  // 5. Validation
  console.log('\n--- 5. Validation ---');
  console.log(`Is valid Base64: ${utils.isValidBase64(encoded)}`);
  console.log(`Is invalid Base64: ${utils.isValidBase64('invalid!@#')}`);

  // 6. Utility functions
  console.log('\n--- 6. Utility Functions ---');
  console.log(`Byte length: ${utils.getByteLength(encoded)}`);
  console.log(`Truncated: ${utils.truncate(encoded, 10)}`);
  console.log(`Checksum: ${utils.checksum(encoded)}`);

  // 7. Chunks
  console.log('\n--- 7. Chunks ---');
  const longText = 'A'.repeat(100);
  const longEncoded = coder.encode(longText);
  const chunks = utils.chunk(longEncoded, 20);
  console.log(`Number of chunks: ${chunks.length}`);

  const concatenated = utils.concat(chunks);
  console.log(`Concatenated equals original: ${concatenated === longEncoded}`);

  console.log('\n=== All Base64 Encoding Examples Completed ===');
}

// Export functions
export { Base64Coder, URLSafeBase64Coder, UnicodeBase64Coder, FileBase64Coder, ImageBase64Coder, Base64Utils, Base64StreamCoder };
export { demonstrateBase64Encoding };

💻 Symmetric Encryption typescript

🟡 intermediate ⭐⭐⭐⭐

Encrypt and decrypt data using AES-GCM algorithm with Web Crypto API

⏱️ 30 min 🏷️ typescript, web, cryptography, encryption
Prerequisites: Intermediate TypeScript, Web Crypto API, Cryptography basics
// Web TypeScript Symmetric Encryption Examples
// Using AES-GCM algorithm with Web Crypto API

// 1. AES-GCM Encryptor
class AESGCMEncryptor {
  // Generate random key
  async generateKey(): Promise<CryptoKey> {
    return await crypto.subtle.generateKey(
      {
        name: 'AES-GCM',
        length: 256
      },
      true,
      ['encrypt', 'decrypt']
    );
  }

  // Encrypt data
  async encrypt(
    key: CryptoKey,
    data: string,
    associatedData?: string
  ): Promise<{ ciphertext: string; iv: string; tag?: string }> {
    const encoder = new TextEncoder();
    const encodedData = encoder.encode(data);

    // Generate random IV (Initialization Vector)
    const iv = crypto.getRandomValues(new Uint8Array(12));

    let encryptOptions: any = {
      name: 'AES-GCM',
      iv: iv
    };

    // Add associated data if provided (for authenticated encryption)
    if (associatedData) {
      encryptOptions.additionalData = encoder.encode(associatedData);
    }

    const encrypted = await crypto.subtle.encrypt(
      encryptOptions,
      key,
      encodedData
    );

    return {
      ciphertext: this.bufferToBase64(encrypted),
      iv: this.bufferToHex(iv)
    };
  }

  // Decrypt data
  async decrypt(
    key: CryptoKey,
    ciphertext: string,
    iv: string,
    associatedData?: string
  ): Promise<string> {
    const encryptedData = this.base64ToBuffer(ciphertext);
    const ivBytes = this.hexToBuffer(iv);

    let decryptOptions: any = {
      name: 'AES-GCM',
      iv: ivBytes
    };

    if (associatedData) {
      const encoder = new TextEncoder();
      decryptOptions.additionalData = encoder.encode(associatedData);
    }

    const decrypted = await crypto.subtle.decrypt(
      decryptOptions,
      key,
      encryptedData
    );

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

  // Export key to base64
  async exportKey(key: CryptoKey): Promise<string> {
    const exported = await crypto.subtle.exportKey('raw', key);
    return this.bufferToBase64(exported);
  }

  // Import key from base64
  async importKey(keyData: string): Promise<CryptoKey> {
    const keyBytes = this.base64ToBuffer(keyData);

    return await crypto.subtle.importKey(
      'raw',
      keyBytes,
      {
        name: 'AES-GCM',
        length: 256
      },
      true,
      ['encrypt', 'decrypt']
    );
  }

  // Generate key from password
  async deriveKey(
    password: string,
    salt?: string,
    iterations: number = 100000
  ): Promise<{ key: CryptoKey; salt: string }> {
    // Generate salt if not provided
    const saltBytes = salt
      ? this.hexToBuffer(salt)
      : crypto.getRandomValues(new Uint8Array(16));

    const encoder = new TextEncoder();
    const passwordData = encoder.encode(password);

    const importedKey = await crypto.subtle.importKey(
      'raw',
      passwordData,
      { name: 'PBKDF2' },
      false,
      ['deriveKey']
    );

    const key = await crypto.subtle.deriveKey(
      {
        name: 'PBKDF2',
        salt: saltBytes,
        iterations: iterations,
        hash: 'SHA-256'
      },
      importedKey,
      {
        name: 'AES-GCM',
        length: 256
      },
      true,
      ['encrypt', 'decrypt']
    );

    return {
      key,
      salt: this.bufferToHex(saltBytes)
    };
  }

  private bufferToBase64(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (const byte of bytes) {
      binary += String.fromCharCode(byte);
    }
    return btoa(binary);
  }

  private base64ToBuffer(base64: string): Uint8Array {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes;
  }

  private bufferToHex(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }

  private hexToBuffer(hex: string): Uint8Array {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < bytes.length; i++) {
      bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return bytes;
  }
}

// 2. Encrypted Message Formatter
class EncryptedMessageFormatter {
  private encryptor: AESGCMEncryptor;

  constructor() {
    this.encryptor = new AESGCMEncryptor();
  }

  // Format encrypted message
  formatMessage(
    ciphertext: string,
    iv: string,
    salt?: string
  ): string {
    const message: any = {
      ct: ciphertext,
      iv: iv
    };

    if (salt) {
      message.salt = salt;
    }

    return JSON.stringify(message);
  }

  // Parse encrypted message
  parseMessage(message: string): {
    ciphertext: string;
    iv: string;
    salt?: string;
  } {
    const data = JSON.parse(message);
    return {
      ciphertext: data.ct,
      iv: data.iv,
      salt: data.salt
    };
  }
}

// 3. File Encryptor
class FileEncryptor {
  private encryptor = new AESGCMEncryptor();

  // Encrypt file
  async encryptFile(
    key: CryptoKey,
    file: File,
    chunkSize: number = 1024 * 1024 // 1MB
  ): Promise<{ encryptedData: Blob; iv: string }> {
    const iv = crypto.getRandomValues(new Uint8Array(12));
    const encryptedChunks: BlobPart[] = [];

    let offset = 0;
    while (offset < file.size) {
      const end = Math.min(offset + chunkSize, file.size);
      const chunk = file.slice(offset, end);
      const arrayBuffer = await chunk.arrayBuffer();

      const encrypted = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv: iv },
        key,
        arrayBuffer
      );

      encryptedChunks.push(new Uint8Array(encrypted));
      offset = end;
    }

    const encryptedBlob = new Blob(encryptedChunks, { type: 'application/octet-stream' });

    return {
      encryptedData: encryptedBlob,
      iv: this.bufferToHex(iv)
    };
  }

  // Decrypt file
  async decryptFile(
    key: CryptoKey,
    encryptedFile: File,
    iv: string,
    chunkSize: number = 1024 * 1024
  ): Promise<Blob> {
    const ivBytes = this.hexToBuffer(iv);
    const decryptedChunks: BlobPart[] = [];

    let offset = 0;
    while (offset < encryptedFile.size) {
      const end = Math.min(offset + chunkSize, encryptedFile.size);
      const chunk = encryptedFile.slice(offset, end);
      const arrayBuffer = await chunk.arrayBuffer();

      const decrypted = await crypto.subtle.decrypt(
        { name: 'AES-GCM', iv: ivBytes },
        key,
        arrayBuffer
      );

      decryptedChunks.push(new Uint8Array(decrypted));
      offset = end;
    }

    return new Blob(decryptedChunks, { type: 'application/octet-stream' });
  }

  // Encrypt file with progress
  async encryptFileWithProgress(
    key: CryptoKey,
    file: File,
    onProgress: (progress: number) => void
  ): Promise<{ encryptedData: Blob; iv: string }> {
    const iv = crypto.getRandomValues(new Uint8Array(12));
    const chunkSize = 1024 * 1024;
    const encryptedChunks: BlobPart[] = [];

    let offset = 0;
    while (offset < file.size) {
      const end = Math.min(offset + chunkSize, file.size);
      const chunk = file.slice(offset, end);
      const arrayBuffer = await chunk.arrayBuffer();

      const encrypted = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv: iv },
        key,
        arrayBuffer
      );

      encryptedChunks.push(new Uint8Array(encrypted));
      offset = end;

      const progress = Math.floor((offset / file.size) * 100);
      onProgress(progress);
    }

    const encryptedBlob = new Blob(encryptedChunks, { type: 'application/octet-stream' });

    return {
      encryptedData: encryptedBlob,
      iv: this.bufferToHex(iv)
    };
  }

  private bufferToHex(buffer: ArrayBuffer | Uint8Array): string {
    const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
    return Array.from(bytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }

  private hexToBuffer(hex: string): Uint8Array {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < bytes.length; i++) {
      bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return bytes;
  }
}

// 4. Key Management
class KeyManager {
  // Store key in IndexedDB
  async storeKey(keyId: string, key: CryptoKey, dbName: string = 'encryptionKeys'): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction(['keys'], 'readwrite');
        const store = transaction.objectStore('keys');

        const encryptor = new AESGCMEncryptor();

        encryptor.exportKey(key).then(exportedKey => {
          store.put({ id: keyId, keyData: exportedKey, created: Date.now() });

          transaction.oncomplete = () => resolve();
          transaction.onerror = () => reject(transaction.error);
        });
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains('keys')) {
          db.createObjectStore('keys', { keyPath: 'id' });
        }
      };
    });
  }

  // Retrieve key from IndexedDB
  async retrieveKey(keyId: string, dbName: string = 'encryptionKeys'): Promise<CryptoKey | null> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction(['keys'], 'readonly');
        const store = transaction.objectStore('keys');
        const getRequest = store.get(keyId);

        getRequest.onsuccess = async () => {
          const data = getRequest.result;
          if (data) {
            const encryptor = new AESGCMEncryptor();
            const key = await encryptor.importKey(data.keyData);
            resolve(key);
          } else {
            resolve(null);
          }
        };

        getRequest.onerror = () => reject(getRequest.error);
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains('keys')) {
          db.createObjectStore('keys', { keyPath: 'id' });
        }
      };
    });
  }

  // Delete key from storage
  async deleteKey(keyId: string, dbName: string = 'encryptionKeys'): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction(['keys'], 'readwrite');
        const store = transaction.objectStore('keys');

        store.delete(keyId);

        transaction.oncomplete = () => resolve();
        transaction.onerror = () => reject(transaction.error);
      };
    });
  }

  // List all stored key IDs
  async listKeys(dbName: string = 'encryptionKeys'): Promise<string[]> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction(['keys'], 'readonly');
        const store = transaction.objectStore('keys');
        const getAllRequest = store.getAllKeys();

        getAllRequest.onsuccess = () => {
          resolve(getAllRequest.result as string[]);
        };

        getAllRequest.onerror = () => reject(getAllRequest.error);
      };
    });
  }
}

// 5. Secure Messaging
class SecureMessaging {
  private encryptor = new AESGCMEncryptor();
  private formatter = new EncryptedMessageFormatter();

  // Send secure message
  async sendMessage(
    recipientKey: CryptoKey,
    message: string,
    associatedData?: string
  ): Promise<string> {
    const encrypted = await this.encryptor.encrypt(
      recipientKey,
      message,
      associatedData
    );

    return this.formatter.formatMessage(
      encrypted.ciphertext,
      encrypted.iv
    );
  }

  // Receive secure message
  async receiveMessage(
    privateKey: CryptoKey,
    encryptedMessage: string,
    associatedData?: string
  ): Promise<string> {
    const parsed = this.formatter.parseMessage(encryptedMessage);

    return await this.encryptor.decrypt(
      privateKey,
      parsed.ciphertext,
      parsed.iv,
      associatedData
    );
  }

  // Create secure conversation
  async createConversation(): Promise<{
    key: CryptoKey;
    keyData: string;
  }> {
    const key = await this.encryptor.generateKey();
    const keyData = await this.encryptor.exportKey(key);

    return { key, keyData };
  }
}

// Usage Examples
async function demonstrateSymmetricEncryption() {
  console.log('=== Web TypeScript Symmetric Encryption Examples ===\n');

  const encryptor = new AESGCMEncryptor();
  const fileEncryptor = new FileEncryptor();
  const keyManager = new KeyManager();
  const messaging = new SecureMessaging();

  // 1. Generate key
  console.log('--- 1. Generate Key ---');
  const key = await encryptor.generateKey();
  const keyData = await encryptor.exportKey(key);
  console.log(`Key: ${keyData.substring(0, 32)}...`);

  // 2. Encrypt/Decrypt message
  console.log('\n--- 2. Encrypt/Decrypt Message ---');
  const message = 'This is a secret message!';
  const encrypted = await encryptor.encrypt(key, message);
  console.log(`Encrypted: ${encrypted.ciphertext.substring(0, 32)}...`);

  const decrypted = await encryptor.decrypt(key, encrypted.ciphertext, encrypted.iv);
  console.log(`Decrypted: ${decrypted}`);

  // 3. Encrypt with associated data
  console.log('\n--- 3. Encrypt with Associated Data ---');
  const aad = 'user123';
  const encryptedAAD = await encryptor.encrypt(key, message, aad);
  const decryptedAAD = await encryptor.decrypt(
    key,
    encryptedAAD.ciphertext,
    encryptedAAD.iv,
    aad
  );
  console.log(`With AAD: ${decryptedAAD}`);

  // 4. Derive key from password
  console.log('\n--- 4. Derive Key from Password ---');
  const password = 'MySecurePassword';
  const { key: derivedKey, salt } = await encryptor.deriveKey(password);
  const derivedEncrypted = await encryptor.encrypt(derivedKey, message);
  console.log(`Derived key encrypted: ${derivedEncrypted.ciphertext.substring(0, 32)}...`);

  // 5. Key management
  console.log('\n--- 5. Key Management ---');
  await keyManager.storeKey('test-key', key);
  const retrievedKey = await keyManager.retrieveKey('test-key');
  console.log(`Key retrieved: ${retrievedKey ? 'Yes' : 'No'}`);

  const keyIds = await keyManager.listKeys();
  console.log(`Stored keys: ${keyIds.join(', ')}`);

  // 6. Secure messaging
  console.log('\n--- 6. Secure Messaging ---');
  const secureMsg = await messaging.sendMessage(key, 'Hello, secure world!');
  console.log(`Secure message: ${secureMsg.substring(0, 50)}...`);

  const receivedMsg = await messaging.receiveMessage(key, secureMsg);
  console.log(`Received: ${receivedMsg}`);

  console.log('\n=== All Symmetric Encryption Examples Completed ===');
}

// Export functions
export { AESGCMEncryptor, EncryptedMessageFormatter, FileEncryptor, KeyManager, SecureMessaging };
export { demonstrateSymmetricEncryption };