Cybersecurity-Projects/PROJECTS/advanced/encrypted-p2p-chat/frontend/src/lib/base64.ts

93 lines
2.4 KiB
TypeScript

/**
* Base64URL encoding/decoding utilities for WebAuthn and encryption
* Uses URL-safe alphabet without padding (per RFC 4648)
*/
export function base64UrlEncode(buffer: ArrayBuffer | Uint8Array): string {
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)
let binary = ''
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i])
}
const base64 = btoa(binary)
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
}
export function base64UrlDecode(str: string): Uint8Array {
let base64 = str.replace(/-/g, '+').replace(/_/g, '/')
const paddingNeeded = (4 - (base64.length % 4)) % 4
base64 += '='.repeat(paddingNeeded)
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
}
export function arrayBufferToBase64Url(buffer: ArrayBuffer): string {
return base64UrlEncode(buffer)
}
export function base64UrlToArrayBuffer(str: string): ArrayBuffer {
return base64UrlDecode(str).buffer as ArrayBuffer
}
export function stringToUint8Array(str: string): Uint8Array {
const encoder = new TextEncoder()
return encoder.encode(str)
}
export function uint8ArrayToString(bytes: Uint8Array): string {
const decoder = new TextDecoder()
return decoder.decode(bytes)
}
export function hexEncode(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('')
}
export function hexDecode(hex: string): Uint8Array {
const bytes = new Uint8Array(hex.length / 2)
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)
}
return bytes
}
export function concatUint8Arrays(...arrays: Uint8Array[]): Uint8Array {
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0)
const result = new Uint8Array(totalLength)
let offset = 0
for (const arr of arrays) {
result.set(arr, offset)
offset += arr.length
}
return result
}
export function compareUint8Arrays(a: Uint8Array, b: Uint8Array): boolean {
if (a.length !== b.length) {
return false
}
let result = 0
for (let i = 0; i < a.length; i++) {
result |= a[i] ^ b[i]
}
return result === 0
}