diff options
| author | Pinapelz <yukais@pinapelz.com> | 2026-06-03 15:26:26 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2026-06-03 15:26:26 -0700 |
| commit | 818db3ef4aadf489dba5ba8ba4f3bb4e150f0b22 (patch) | |
| tree | 0a79f0d61a8738e5083a3ad72f5c3242a6869829 | |
| parent | 495ecca361a7422e7c42dea04a08946cfceef29a (diff) | |
change from aes-gcm to xor shift obfuscation
encryption was pain in the ass on cross platform
| -rw-r--r-- | package.json | 4 | ||||
| -rw-r--r-- | server/index.ts | 29 | ||||
| -rw-r--r-- | src/helpers/fetchSolution.ts | 46 |
3 files changed, 31 insertions, 48 deletions
diff --git a/package.json b/package.json index cd39eef..d9877dd 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@typescript-eslint/eslint-plugin": "^5.15.0", "@typescript-eslint/parser": "^5.15.0", "@vitejs/plugin-react": "^6.0.2", + "@vitest/ui": "^1.0.0", "concurrently": "^10.0.3", "eslint": "^8.3.0", "eslint-config-airbnb": "^19.0.4", @@ -78,8 +79,7 @@ "prettier": "^2.6.0", "ts-node": "^10.9.2", "vite": "^8.0.16", - "vitest": "^1.0.0", - "@vitest/ui": "^1.0.0" + "vitest": "^1.0.0" }, "packageManager": "pnpm@8.15.3" } diff --git a/server/index.ts b/server/index.ts index afe8d81..c78352a 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,6 +1,4 @@ import express from 'express'; -import path from 'path'; -import crypto from 'crypto'; import { songs } from './data/songs'; import { startDate } from './data/startDate'; import cors from 'cors'; @@ -14,27 +12,28 @@ app.use(express.json()); const SERVER_PORT = process.env.SERVER_PORT || 3001; const SALT = process.env.VITE_HEARDLE_SALT ?? 'changeme'; -function getDailyKey(): Buffer { +function getObfuscationKey(): Buffer { const date = new Date().toISOString().split('T')[0]; - return crypto.pbkdf2Sync(date, SALT, 100_000, 32, 'sha256'); + return Buffer.from(SALT + date); +} + +function xorBuffer(data: Buffer, key: Buffer): Buffer { + const output = Buffer.alloc(data.length); + for (let i = 0; i < data.length; i++) { + output[i] = data[i] ^ key[i % key.length]; + } + return output; } app.get('/today', (_req, res) => { const msInDay = 86_400_000; const index = Math.floor((Date.now() - startDate.getTime()) / msInDay); const song = songs[index % songs.length]; - - const key = getDailyKey(); - const iv = crypto.randomBytes(12); - const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); - const encrypted = Buffer.concat([ - cipher.update(JSON.stringify(song), 'utf8'), - cipher.final(), - ]); + const obfuscationKey = getObfuscationKey(); + const songJson = JSON.stringify(song); + const obfuscatedData = xorBuffer(Buffer.from(songJson, 'utf8'), obfuscationKey); res.json({ - iv: iv.toString('hex'), - tag: cipher.getAuthTag().toString('hex'), - data: encrypted.toString('hex'), + data: obfuscatedData.toString('hex'), }); }); diff --git a/src/helpers/fetchSolution.ts b/src/helpers/fetchSolution.ts index dd623a0..2ca2e68 100644 --- a/src/helpers/fetchSolution.ts +++ b/src/helpers/fetchSolution.ts @@ -1,7 +1,7 @@ import { Song } from "../types/song"; const SALT = import.meta.env.VITE_HEARDLE_SALT ?? 'changeme'; -const API_URL = import.meta.env.VITE_HEARDLE_API_URL ?? 'https://127.0.0.1:3001'; +const API_URL = import.meta.env.VITE_HEARDLE_API_URL ?? 'http://localhost:3001'; function hexToBytes(hex: string): Uint8Array { const bytes = new Uint8Array(hex.length / 2); @@ -12,23 +12,17 @@ return bytes; } -async function getDailyKey(): Promise<CryptoKey> { - const enc = new TextEncoder(); +function xor(data: Uint8Array, key: Uint8Array): Uint8Array { + const output = new Uint8Array(data.length); + for (let i = 0; i < data.length; i++) { + output[i] = data[i] ^ key[i % key.length]; + } + return output; +} + +function getObfuscationKey(): Uint8Array { const date = new Date().toISOString().split('T')[0]; - const keyMaterial = await crypto.subtle.importKey( - 'raw', - enc.encode(date), - 'PBKDF2', - false, - ['deriveKey'], - ); - return crypto.subtle.deriveKey( - { name: 'PBKDF2', salt: enc.encode(SALT), iterations: 100_000, hash: 'SHA-256' }, - keyMaterial, - { name: 'AES-GCM', length: 256 }, - false, - ['decrypt'], - ); + return new TextEncoder().encode(SALT + date); } export async function getDailySolution(): Promise<Song> { @@ -36,19 +30,9 @@ export async function getDailySolution(): Promise<Song> { if (!solutionData.ok) { throw new Error(`Failed to fetch solution: ${solutionData.statusText}`); } - const { iv, tag, data } = await solutionData.json(); - const key = await getDailyKey(); - const ciphertext = hexToBytes(data); - const authTag = hexToBytes(tag); - const combined = new Uint8Array(ciphertext.length + authTag.length); - combined.set(ciphertext); - combined.set(authTag, ciphertext.length); - console.log(key.algorithm); - console.log(key.usages); - const decrypted = await crypto.subtle.decrypt( - { name: 'AES-GCM', iv: hexToBytes(iv) }, - key, - combined, - ); + const { data } = await solutionData.json(); + const obfuscationKey = getObfuscationKey(); + const obfuscatedBytes = hexToBytes(data); + const decrypted = xor(obfuscatedBytes, obfuscationKey); return JSON.parse(new TextDecoder().decode(decrypted)) as Song; } |
