From b245ae63e6c35a51dd7a99cf024b3a9c9d42f822 Mon Sep 17 00:00:00 2001 From: ztimson Date: Mon, 6 Apr 2026 15:17:25 -0400 Subject: [PATCH] Added new codebook page --- client/public/code-book-print.html | 61 ++-- client/public/code-book.html | 560 ++++++++++++++++++++++++----- client/public/encryption.js | 54 ++- client/public/index.html | 2 +- 4 files changed, 522 insertions(+), 155 deletions(-) diff --git a/client/public/code-book-print.html b/client/public/code-book-print.html index aa45674..31a9062 100644 --- a/client/public/code-book-print.html +++ b/client/public/code-book-print.html @@ -127,11 +127,11 @@
-

Encryption Key

+

Encryption Key

-

ASCII Reference Table

+

ASCII REFERENCE TABLE

@@ -162,12 +162,13 @@ } function renderASCIITable() { - let html = ''; - html += ''; + let html = '
'; - for (let row = 0; row < 32; row++) { - html += '
'; - for (let col = 0; col < 4; col++) { + for (let col = 0; col < 4; col++) { + html += '
DecHexCharDecHexCharDecHexCharDecHexChar
'; + html += ''; + + for (let row = 0; row < 32; row++) { const code = row + (col * 32); if (code < 128) { const hex = code.toString(16).toUpperCase().padStart(2, '0'); @@ -183,26 +184,36 @@ char = 'DEL'; } - html += ``; + html += ``; } } - html += ''; + + html += '
CharHexDec
${code}${hex}${char}
${char}${hex}${code}
'; } - html += ''; + html += ''; document.getElementById('ascii-print').innerHTML = html; } function renderOTPPairs(key) { - const columns = [[], [], [], [], []]; - + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + const pairs = []; + const used = new Set(); for (let i = 0; i < 250; i++) { - const nonce = i.toString().padStart(3, '0'); - const code = generateHOTP(key, nonce); - const pair = `${nonce} ${code}`; - columns[Math.floor(i / 50)].push(pair); - } + let nonce; + do { + nonce = chars[Math.floor(Math.random() * chars.length)] + chars[Math.floor(Math.random() * chars.length)]; + } while (used.has(nonce)); + used.add(nonce); + const code = generateHOTP(key, nonce); + pairs.push(`${nonce} ${code}`); + } + pairs.sort(); + const columns = [[], [], [], [], []]; + for (let i = 0; i < pairs.length; i++) { + columns[Math.floor(i / 50)].push(pairs[i]); + } let html = ''; for (let col of columns) { html += '
'; @@ -211,7 +222,6 @@ } html += '
'; } - document.getElementById('otp-grid').innerHTML = html; } @@ -219,10 +229,8 @@ let html = ''; const rows = 'NOPQRSTUVWXYZ'.split(''); const cols = 'ABCDEFGHIJKLM'.split(''); - for (let tableIndex = 0; tableIndex < 26; tableIndex++) { const table = generateAuthTable(key, tableIndex); - html += '
'; html += `

${PHONETIC[tableIndex]}

`; html += ''; @@ -231,7 +239,6 @@ html += ``; } html += ''; - for (let i = 0; i < rows.length; i++) { html += ``; for (let j = 0; j < cols.length; j++) { @@ -242,23 +249,19 @@ html += '
${col}
${rows[i]}
'; html += '
'; } - document.getElementById('auth-tables').innerHTML = html; } function renderPadKeys(key) { let html = ''; - - for (let i = 0; i < 50; i++) { + for (let i = 0; i < 100; i++) { const padKey = (i * 1000).toString().padStart(5, '0'); const cipher = generatePadDisplay(key, padKey); - html += '
'; html += `
Key: ${padKey}
`; html += `
${cipher}
`; html += '
'; } - document.getElementById('pad-list').innerHTML = html; } @@ -273,11 +276,7 @@ renderOTPPairs(key); renderAuthTables(key); renderPadKeys(key); - - // Auto-print after everything loads - setTimeout(() => { - window.print(); - }, 500); + setTimeout(() => {window.print();}, 500); } diff --git a/client/public/code-book.html b/client/public/code-book.html index 3f7a99b..de0641b 100644 --- a/client/public/code-book.html +++ b/client/public/code-book.html @@ -28,7 +28,7 @@ .header { background: rgba(15, 23, 42, 0.95); backdrop-filter: blur(10px); - padding: 1.5rem 2rem; + padding: 1rem; border-bottom: 1px solid rgba(255, 255, 255, 0.1); position: sticky; top: 0; @@ -50,12 +50,12 @@ } .logo-section img { - height: 3rem; + height: 2.5rem; width: auto; } .logo { - font-size: 1.5rem; + font-size: 1.25rem; font-weight: 700; letter-spacing: 0.05rem; } @@ -63,21 +63,32 @@ .container { max-width: 1200px; margin: 0 auto; - padding: 2rem; + padding: 1rem; } .key-section { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 12px; - padding: 1.5rem; - margin-bottom: 2rem; + padding: 1rem; + margin-bottom: 1.5rem; } .key-input-group { display: flex; - gap: 1rem; - margin-bottom: 1rem; + gap: 0.5rem; + align-items: flex-end; + flex-wrap: wrap; + } + + .key-input-group .input-wrapper { + flex: 1; + min-width: 200px; + } + + .key-input-group button { + flex: 0 0 auto; + white-space: nowrap; } .input-wrapper { @@ -133,6 +144,7 @@ font-size: 0.9rem; cursor: pointer; transition: all 0.2s ease; + white-space: nowrap; } button:hover { @@ -165,8 +177,8 @@ background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 12px; - padding: 1.5rem; - margin-bottom: 2rem; + padding: 1rem; + margin-bottom: 1.5rem; } .tool-title { @@ -183,17 +195,35 @@ .hotp-row { display: flex; - gap: 1rem; - align-items: center; + gap: 0.5rem; + align-items: flex-end; + flex-wrap: wrap; } .hotp-row button { flex: 0 0 auto; } + .hotp-row > div { + flex: 1; + min-width: 100px; + } + + .hotp-challenge-response { + display: flex; + gap: 0.5rem; + flex: 1; + min-width: 0; + } + + .hotp-challenge-response > div { + flex: 1; + min-width: 100px; + } + .hotp-row input, .hotp-code { - flex: 1; + width: 100%; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px; @@ -211,14 +241,16 @@ .auth-table { font-family: 'Courier New', monospace; - font-size: 0.9rem; + font-size: 0.75rem; margin: 1rem 0; width: 100%; + overflow-x: auto; } .auth-table table { border-collapse: collapse; width: 100%; + min-width: 500px; } .auth-table th, @@ -227,6 +259,7 @@ padding: 0.5rem; text-align: center; transition: background-color 0.15s ease; + cursor: pointer; } .auth-table th { @@ -234,19 +267,33 @@ font-weight: 600; } - .auth-table td.highlight { + .auth-table td.highlight, + .auth-table th.highlight { + background: rgba(255, 255, 255, 0.25); + } + + .auth-table td:hover, + .auth-table th:hover { background: rgba(255, 255, 255, 0.15); } - .auth-table th.highlight { - background: rgba(255, 255, 255, 0.2); + .ascii-search-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0.5rem; + margin-bottom: 1rem; + } + + .ascii-tables-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; + margin: 1rem 0; } .ascii-table { font-family: 'Courier New', monospace; - font-size: 0.85rem; - margin: 1rem 0; - width: 100%; + font-size: 0.75rem; } .ascii-table table { @@ -266,16 +313,46 @@ font-weight: 600; } + .ascii-table tr:hover { + background: rgba(255, 255, 255, 0.1); + } + + .ascii-table tr.highlight { + background: rgba(255, 255, 255, 0.15); + } + + .ascii-table tr.search-match { + background: rgba(16, 185, 129, 0.2); + } + .pad-list { font-family: 'Courier New', monospace; - font-size: 0.95rem; + font-size: 0.85rem; line-height: 1.8; + word-break: break-all; } .pad-item { margin: 0.5rem 0; } + .pad-controls { + display: flex; + gap: 0.5rem; + align-items: center; + flex-wrap: wrap; + margin-bottom: 1rem; + } + + .pad-controls button { + flex: 0 0 auto; + } + + .pad-controls input { + width: 100px; + flex: 0 0 auto; + } + textarea { width: 100%; min-height: 100px; @@ -284,22 +361,23 @@ border-radius: 8px; padding: 0.75rem; color: #fff; - font-size: 1rem; + font-size: 0.9rem; font-family: 'Courier New', monospace; resize: vertical; } .button-group { display: flex; - gap: 1rem; + gap: 0.5rem; margin-top: 1rem; + flex-wrap: wrap; } .checkbox-wrapper { display: flex; align-items: center; gap: 0.5rem; - margin-top: 1rem; + margin-top: 0; } .checkbox-wrapper input[type="checkbox"] { @@ -320,6 +398,173 @@ padding: 1rem; margin: 0.75rem 0; font-family: 'Courier New', monospace; + font-size: 0.85rem; + overflow-x: auto; + } + + .example-box pre { + overflow-x: auto; + white-space: pre; + } + + .textarea-wrapper { + position: relative; + } + + .copy-button { + position: absolute; + top: 0.5rem; + right: 0.5rem; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 6px; + padding: 0.5rem; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + } + + .copy-button:hover { + background: rgba(255, 255, 255, 0.2); + } + + .copy-button svg { + width: 16px; + height: 16px; + fill: #fff; + } + + /* Mobile Responsive */ + @media (max-width: 768px) { + .header { + padding: 0.75rem; + } + + .logo-section img { + height: 2rem; + } + + .logo { + font-size: 1rem; + } + + .container { + padding: 0.75rem; + } + + .tool-section, + .key-section { + padding: 0.75rem; + margin-bottom: 1rem; + } + + .tool-title { + font-size: 1.1rem; + } + + .key-input-group { + flex-wrap: wrap; + } + + .key-input-group .input-wrapper { + flex: 1 1 100%; + min-width: 100%; + } + + .key-input-group button { + flex: 1; + } + + .hotp-row { + flex-wrap: wrap; + } + + .hotp-row button { + flex: 1 1 100%; + } + + .hotp-challenge-response { + flex: 1 1 100%; + flex-wrap: nowrap; + } + + .ascii-search-grid { + grid-template-columns: 1fr; + } + + .ascii-tables-grid { + grid-template-columns: repeat(2, 1fr); + gap: 0.75rem; + } + + .auth-table { + font-size: 0.65rem; + } + + .ascii-table { + font-size: 0.7rem; + } + + .ascii-table th, + .ascii-table td { + padding: 0.3rem; + } + + button { + padding: 0.65rem 1rem; + font-size: 0.85rem; + } + + .example-box { + font-size: 0.75rem; + padding: 0.75rem; + } + } + + @media (max-width: 480px) { + .ascii-tables-grid { + grid-template-columns: 1fr; + } + + .auth-table th, + .auth-table td { + padding: 0.3rem; + } + + textarea { + font-size: 0.85rem; + } + + .pad-list { + font-size: 0.8rem; + } + + .hotp-challenge-response { + gap: 0.25rem; + } + + .hotp-challenge-response button { + padding: 0.65rem 0.75rem; + font-size: 0.8rem; + } + } + + @media (min-width: 769px) { + .ascii-tables-grid { + grid-template-columns: repeat(4, 1fr); + } + } + + @media (min-width: 1200px) { + .key-input-group { + flex-wrap: nowrap; + } + + .key-input-group .input-wrapper { + min-width: 200px; + } } @@ -328,7 +573,7 @@
Logo - +
@@ -338,7 +583,9 @@
- +
+ +
@@ -347,36 +594,39 @@
-
One Time Password (HOTP)
+
One-Time Password (HOTP)
- Description + Description
-

Use a 3-digit challenge to generate & verify a corresponding 3-letter response.

-

Provides higher entropy and security than authentication tables while being easier to use.

+

Use a 2-character alphanumeric challenge to generate & verify with a corresponding 2-character response.

+

Provides higher entropy (security) than authentication tables while using less bandwidth & being easier to use.

-
- Pre-Authenticate: -
-

A->B: AUTH 123 ABC

-

B->A: ACK. AUTH 456 DEF

-
-
- -
- Challenge-Response: -
-

A->B: CONFIRM 123

-

B->A: ACK ABC. CONFIRM 456

-

A->B: ACK DEF

-
+
+ Challenge-Response: +
+

A->B: AUTH AA

+

(B inputs AA and sends response with new challenge)

+

B->A: ANS BB. AUTH CC

+

(A verifies response; provides response to new challenge)

+

A->B: ANS DD

+

(B verifies response)

+
- -
---
+
+
+ + +
+
+ +
--
+
+
@@ -384,17 +634,20 @@
Authentication Tables
- Description + Description

Challenge-response tables for authentication.

- Example: + Challenge-Response:
-

A->B: CONFIRM CEY (Table: Charlie, Column: E, Row: Y)

-

B->A: ACK 7. CONFIRM AIT (Table: Alpha, Column: I, Row: T)

-

A->B: ACK T

+

A->B: AUTH CEY

+

(B look up response for table: Charlie, column: E, row: Y; sends new challenge)

+

B->A: ANS 7. AUTH AIT

+

(A verifies response; sends response for new challenge, table: Alpha, column: I, row: T)

+

A->B: ANS T

+

(B verifies response)

@@ -410,45 +663,48 @@
One-Time Pad
- Description + Description
-

Use a 5-digit key to generate a corresponding fixed (paper friendly) or streamed (more secure) cipher.

-

Cipher values are added to the ASCII encoded message to create encrypted message.

+

Use a 5-digit key to generate a fixed (paper friendly) or streamed (more secure) cipher.

+

Cipher values are added to ASCII encoded message to create encrypted message. All values are 3-digit for manual calculations.

+

When encoding exceeds 999, only keep the last 3 digits. When decoding goes negative, add 1000.

- Encoding: + Encoding (with overflow example):
- Message: "HI"
- Pad Key: 12345
- Cipher: 42 85 28 71 14 ...

+
Key: 12345
+234 967 890 112 314...
 
-								H = ASCII 72 → 72 + 42 = 114 → Hex 72
- I = ASCII 73 → 73 + 85 = 158 → Hex 9E

- - Encoded: 729E +Message: H E L L O +ASCII: 072 069 076 076 079 +Cipher: + 234 967 890 112 314 + ───────────────────────────── +Result: 306 1036 966 188 393 +Encoded: 306 036 966 188 393
- Decoding: + Decoding (with negative handling):
- Encoded: 729E
- Pad Key: 12345
- Cipher: 42 85 28 71 14 ...

+
Key: 12345
+234 967 890 112 314...
 
-								72 (Hex) = 114 → 114 - 42 = 72 → ASCII 'H'
- 9E (Hex) = 158 → 158 - 85 = 73 → ASCII 'I'

- - Decoded: "HI" +Encoded: 306 036 966 188 393 +Cipher: - 234 967 890 112 314 + ───────────────────────────── +Result: 072 -931 076 076 079 +ASCII: 072 069 076 076 079 +Message: H E L L O
-
+
- +
@@ -463,20 +719,43 @@
- +
+ + +
ASCII Reference Table
-
+
+
+ + +
+
+ + +
+
+ + +
+
+