|
| 1 | +import { Cipher } from "../Cipher.js" |
| 2 | +import { Buffer } from "buffer" |
| 3 | + |
| 4 | +const IP = [ |
| 5 | + // Initial Permutation |
| 6 | + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, |
| 7 | + 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, |
| 8 | + 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, |
| 9 | + 31, 23, 15, 7, |
| 10 | +] |
| 11 | + |
| 12 | +const FP = [ |
| 13 | + // Final Permutation |
| 14 | + 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, |
| 15 | + 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, |
| 16 | + 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, |
| 17 | + 49, 17, 57, 25, |
| 18 | +] |
| 19 | + |
| 20 | +export class DES extends Cipher { |
| 21 | + private key: bigint |
| 22 | + |
| 23 | + constructor(key: string) { |
| 24 | + super() |
| 25 | + if (key.length !== 8) |
| 26 | + throw new Error("DES key must be exactly 8 characters.") |
| 27 | + this.key = this.stringToBigInt(key) |
| 28 | + } |
| 29 | + |
| 30 | + encrypt(text: string): string { |
| 31 | + const paddedText = this.pad(text) |
| 32 | + const encryptedBlocks = [] |
| 33 | + |
| 34 | + for (let i = 0; i < paddedText.length; i += 8) { |
| 35 | + const block = paddedText.substring(i, i + 8) |
| 36 | + const input = this.stringToBigInt(block) |
| 37 | + const permuted = this.permute(input, IP) |
| 38 | + const encrypted = this.feistel(permuted) |
| 39 | + const finalPerm = this.permute(encrypted, FP) |
| 40 | + encryptedBlocks.push(finalPerm.toString(16).padStart(16, "0")) |
| 41 | + } |
| 42 | + |
| 43 | + return encryptedBlocks.join("") // Concatenate hex strings |
| 44 | + } |
| 45 | + |
| 46 | + decrypt(text: string): string { |
| 47 | + let decryptedText = "" |
| 48 | + |
| 49 | + for (let i = 0; i < text.length; i += 16) { |
| 50 | + // 16 hex chars = 8 bytes |
| 51 | + const block = BigInt("0x" + text.substring(i, i + 16)) |
| 52 | + const permuted = this.permute(block, IP) |
| 53 | + const decrypted = this.feistel(permuted) |
| 54 | + const finalPerm = this.permute(decrypted, FP) |
| 55 | + decryptedText += this.bigIntToString(finalPerm) |
| 56 | + } |
| 57 | + |
| 58 | + return this.unpad(decryptedText) |
| 59 | + } |
| 60 | + |
| 61 | + private pad(text: string): string { |
| 62 | + const padLength = 8 - (text.length % 8) |
| 63 | + return text + String.fromCharCode(padLength).repeat(padLength) |
| 64 | + } |
| 65 | + |
| 66 | + private unpad(text: string): string { |
| 67 | + const padLength = text.charCodeAt(text.length - 1) |
| 68 | + return text.slice(0, -padLength) |
| 69 | + } |
| 70 | + |
| 71 | + private feistel(input: bigint): bigint { |
| 72 | + let L = input >> BigInt(32) |
| 73 | + let R = input & BigInt(0xffffffff) |
| 74 | + |
| 75 | + for (let i = 0; i < 16; i++) { |
| 76 | + const roundKey = this.getRoundKey() |
| 77 | + const newR = L ^ this.f(R, roundKey) |
| 78 | + L = R |
| 79 | + R = newR |
| 80 | + } |
| 81 | + |
| 82 | + return (R << BigInt(32)) | L |
| 83 | + } |
| 84 | + |
| 85 | + private getRoundKey(): bigint { |
| 86 | + return this.key // Placeholder (Key Schedule logic needed) |
| 87 | + } |
| 88 | + |
| 89 | + private f(block: bigint, roundKey: bigint): bigint { |
| 90 | + return block ^ roundKey // Placeholder (Expand, S-Box, Permutation) |
| 91 | + } |
| 92 | + |
| 93 | + private permute(input: bigint, table: number[]): bigint { |
| 94 | + let output = BigInt(0) |
| 95 | + for (let i = 0; i < table.length; i++) { |
| 96 | + output |= ((input >> BigInt(64 - table[i])) & BigInt(1)) << BigInt(63 - i) |
| 97 | + } |
| 98 | + return output |
| 99 | + } |
| 100 | + |
| 101 | + private stringToBigInt(str: string): bigint { |
| 102 | + return BigInt("0x" + Buffer.from(str, "utf8").toString("hex")) |
| 103 | + } |
| 104 | + |
| 105 | + private bigIntToString(num: bigint): string { |
| 106 | + return Buffer.from(num.toString(16).padStart(16, "0"), "hex").toString( |
| 107 | + "utf8" |
| 108 | + ) |
| 109 | + } |
| 110 | +} |
0 commit comments