File size: 2,027 Bytes
8a790fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
export class EncryptionService {
  private static readonly SECRET_SALT = "RELAY_SECURE_CBT_2026_SALT";

  /**
   * Applies an elegant reversible string transformation (XOR masking with cyclic salt) 
   * to guarantee student's private answers, progress, and timer states are encrypted in raw storage.
   */
  static encrypt(rawData: string): string {
    let result = "";
    for (let i = 0; i < rawData.length; i++) {
      const charCode = rawData.charCodeAt(i);
      const saltCode = this.SECRET_SALT.charCodeAt(i % this.SECRET_SALT.length);
      // XOR obfuscation & shift
      result += String.fromCharCode(charCode ^ saltCode);
    }
    // Encode to base64 safely
    try {
      return btoa(encodeURIComponent(result));
    } catch {
      return btoa(result);
    }
  }

  /**
   * Decrypts obfuscated values back to standard UTF-8 text strings.
   */
  static decrypt(encryptedData: string): string {
    if (!encryptedData) return "";
    let rawObfuscated = "";
    try {
      rawObfuscated = decodeURIComponent(atob(encryptedData));
    } catch {
      try {
        rawObfuscated = atob(encryptedData);
      } catch {
        return "";
      }
    }

    let result = "";
    for (let i = 0; i < rawObfuscated.length; i++) {
      const charCode = rawObfuscated.charCodeAt(i);
      const saltCode = this.SECRET_SALT.charCodeAt(i % this.SECRET_SALT.length);
      result += String.fromCharCode(charCode ^ saltCode);
    }
    return result;
  }

  /**
   * Encrypts any structured JavaScript object safely.
   */
  static encryptObject(obj: any): string {
    try {
      const rawString = JSON.stringify(obj);
      return this.encrypt(rawString);
    } catch {
      return "";
    }
  }

  /**
   * Decrypts back to a structured JavaScript object.
   */
  static decryptObject<T = any>(encryptedStr: string): T | null {
    if (!encryptedStr) return null;
    try {
      const rawString = this.decrypt(encryptedStr);
      return JSON.parse(rawString) as T;
    } catch {
      return null;
    }
  }
}