Spaces:
Running
Running
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CTF Flag Calculator - RSA Solver</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| :root { | |
| --primary: #00ff88; | |
| --secondary: #00ccff; | |
| --dark: #0a0a0a; | |
| --darker: #050505; | |
| --light: #ffffff; | |
| --gray: #666; | |
| --success: #4caf50; | |
| --warning: #ff9800; | |
| --error: #f44336; | |
| } | |
| body { | |
| font-family: 'Courier New', monospace; | |
| background: linear-gradient(135deg, var(--darker) 0%, var(--dark) 100%); | |
| color: var(--light); | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| /* 背景动画 */ | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: | |
| radial-gradient(circle at 20% 50%, rgba(0, 255, 136, 0.1) 0%, transparent 50%), | |
| radial-gradient(circle at 80% 50%, rgba(0, 204, 255, 0.1) 0%, transparent 50%); | |
| animation: pulse 10s ease-in-out infinite; | |
| pointer-events: none; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 0.5; } | |
| 50% { opacity: 1; } | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| header { | |
| text-align: center; | |
| padding: 30px 0; | |
| margin-bottom: 40px; | |
| border-bottom: 2px solid rgba(0, 255, 136, 0.3); | |
| } | |
| h1 { | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| text-shadow: 0 0 30px rgba(0, 255, 136, 0.5); | |
| } | |
| .subtitle { | |
| color: var(--gray); | |
| font-size: 1.1em; | |
| } | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 30px; | |
| margin-bottom: 30px; | |
| } | |
| @media (max-width: 968px) { | |
| .main-content { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .card { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(0, 255, 136, 0.3); | |
| border-radius: 15px; | |
| padding: 25px; | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s ease; | |
| } | |
| .card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 40px rgba(0, 255, 136, 0.2); | |
| border-color: var(--primary); | |
| } | |
| .card-header { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| padding-bottom: 15px; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .card-header i { | |
| font-size: 1.5em; | |
| margin-right: 15px; | |
| color: var(--primary); | |
| } | |
| .card-title { | |
| font-size: 1.3em; | |
| font-weight: bold; | |
| } | |
| .input-group { | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 8px; | |
| color: var(--primary); | |
| font-weight: bold; | |
| } | |
| textarea, input { | |
| width: 100%; | |
| padding: 12px; | |
| background: rgba(0, 0, 0, 0.5); | |
| border: 1px solid rgba(0, 255, 136, 0.3); | |
| border-radius: 8px; | |
| color: var(--light); | |
| font-family: 'Courier New', monospace; | |
| font-size: 14px; | |
| transition: all 0.3s ease; | |
| } | |
| textarea:focus, input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| box-shadow: 0 0 10px rgba(0, 255, 136, 0.3); | |
| } | |
| textarea { | |
| min-height: 100px; | |
| resize: vertical; | |
| } | |
| .btn { | |
| padding: 12px 30px; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| border: none; | |
| border-radius: 8px; | |
| color: var(--dark); | |
| font-weight: bold; | |
| font-size: 16px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .btn:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 5px 20px rgba(0, 255, 136, 0.4); | |
| } | |
| .btn:active { | |
| transform: scale(0.98); | |
| } | |
| .btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .btn-group { | |
| display: flex; | |
| gap: 15px; | |
| flex-wrap: wrap; | |
| } | |
| .result-box { | |
| background: rgba(0, 0, 0, 0.5); | |
| border: 1px solid rgba(0, 255, 136, 0.3); | |
| border-radius: 8px; | |
| padding: 15px; | |
| margin-top: 20px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .result-box::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: -100%; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(0, 255, 136, 0.2), transparent); | |
| animation: scan 2s linear infinite; | |
| } | |
| @keyframes scan { | |
| to { left: 100%; } | |
| } | |
| .result-content { | |
| position: relative; | |
| z-index: 1; | |
| word-break: break-all; | |
| font-family: 'Courier New', monospace; | |
| } | |
| .flag-result { | |
| font-size: 1.2em; | |
| color: var(--primary); | |
| font-weight: bold; | |
| text-shadow: 0 0 10px rgba(0, 255, 136, 0.5); | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| gap: 15px; | |
| margin-top: 20px; | |
| } | |
| .stat-item { | |
| background: rgba(0, 0, 0, 0.3); | |
| padding: 15px; | |
| border-radius: 8px; | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 1.5em; | |
| color: var(--primary); | |
| font-weight: bold; | |
| } | |
| .stat-label { | |
| color: var(--gray); | |
| font-size: 0.9em; | |
| margin-top: 5px; | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 4px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| margin-top: 10px; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| width: 0%; | |
| transition: width 0.3s ease; | |
| } | |
| .loading { | |
| display: inline-block; | |
| width: 20px; | |
| height: 20px; | |
| border: 3px solid rgba(0, 255, 136, 0.3); | |
| border-top-color: var(--primary); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| .algorithm-info { | |
| background: rgba(0, 204, 255, 0.1); | |
| border-left: 4px solid var(--secondary); | |
| padding: 15px; | |
| margin-top: 20px; | |
| border-radius: 8px; | |
| } | |
| .algorithm-info h3 { | |
| color: var(--secondary); | |
| margin-bottom: 10px; | |
| } | |
| .algorithm-info p { | |
| line-height: 1.6; | |
| color: var(--gray); | |
| } | |
| .footer { | |
| text-align: center; | |
| padding: 20px; | |
| margin-top: 40px; | |
| border-top: 1px solid rgba(0, 255, 136, 0.3); | |
| color: var(--gray); | |
| } | |
| .footer a { | |
| color: var(--primary); | |
| text-decoration: none; | |
| } | |
| .footer a:hover { | |
| text-decoration: underline; | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 30px; | |
| right: 30px; | |
| background: rgba(0, 0, 0, 0.9); | |
| border: 1px solid var(--primary); | |
| border-radius: 8px; | |
| padding: 15px 20px; | |
| display: none; | |
| align-items: center; | |
| gap: 10px; | |
| z-index: 1000; | |
| animation: slideIn 0.3s ease; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| transform: translateX(100%); | |
| opacity: 0; | |
| } | |
| to { | |
| transform: translateX(0); | |
| opacity: 1; | |
| } | |
| } | |
| .toast.show { | |
| display: flex; | |
| } | |
| .toast.success { | |
| border-color: var(--success); | |
| } | |
| .toast.error { | |
| border-color: var(--error); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <h1><i class="fas fa-flag"></i> CTF Flag Calculator</h1> | |
| <p class="subtitle">RSA Modular Arithmetic Solver with Multi-threading Optimization</p> | |
| <p style="margin-top: 10px; font-size: 0.9em;"> | |
| Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a> | |
| </p> | |
| </header> | |
| <main class="main-content"> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <i class="fas fa-input"></i> | |
| <h2 class="card-title">输入参数</h2> | |
| </div> | |
| <div class="input-group"> | |
| <label for="p-input">素数 p:</label> | |
| <textarea id="p-input" placeholder="输入素数 p...">407803049564139560409879631113358278888733140263084768485722310176731727783189074396823474461249041</textarea> | |
| </div> | |
| <div class="input-group"> | |
| <label for="c-input">密文 c:</label> | |
| <textarea id="c-input" placeholder="输入密文 c...">273724405776192840968808904199790097747266675483664217133748454869235934407461809379517600593224622</textarea> | |
| </div> | |
| <div class="input-group"> | |
| <label for="table-input">字符集:</label> | |
| <input type="text" id="table-input" value="Lf" placeholder="输入可能的字符集..."> | |
| </div> | |
| <div class="input-group"> | |
| <label for="length-input">Flag 长度:</label> | |
| <input type="number" id="length-input" value="100" min="1" placeholder="输入 flag 内容长度..."> | |
| </div> | |
| <div class="btn-group"> | |
| <button class="btn" onclick="calculateFlag()"> | |
| <i class="fas fa-calculator"></i> | |
| 计算 Flag | |
| </button> | |
| <button class="btn" onclick="loadExample()"> | |
| <i class="fas fa-file-import"></i> | |
| 加载示例 | |
| </button> | |
| <button class="btn" onclick="clearAll()"> | |
| <i class="fas fa-trash"></i> | |
| 清空 | |
| </button> | |
| </div> | |
| </section> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <i class="fas fa-chart-line"></i> | |
| <h2 class="card-title">计算结果</h2> | |
| </div> | |
| <div class="result-box"> | |
| <div class="result-content" id="result-content"> | |
| <p style="color: #666;">等待计算...</p> | |
| </div> | |
| </div> | |
| <div class="stats-grid"> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="bits">0</div> | |
| <div class="stat-label">位数</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="time">0ms</div> | |
| <div class="stat-label">计算时间</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="threads">1</div> | |
| <div class="stat-label">线程数</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="status">就绪</div> | |
| <div class="stat-label">状态</div> | |
| </div> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progress"></div> | |
| </div> | |
| </section> | |
| </main> | |
| <section class="card algorithm-info"> | |
| <h3><i class="fas fa-info-circle"></i> 算法说明</h3> | |
| <p> | |
| 本工具专门解决简化版RSA问题。由于 m < p,c = m mod p = m,我们可以直接将密文转换回原始消息。 | |
| 使用优化的BigInt运算和Web Workers实现多线程并行计算,大幅提升处理速度。 | |
| 支持任意长度的大数运算,自动检测输入格式并提供详细的计算过程。 | |
| </p> | |
| <p style="margin-top: 10px;"> | |
| <strong>优化策略:</strong><br> | |
| • 使用原生BigInt进行大数运算<br> | |
| • Web Workers并行处理<br> | |
| • 位运算优化转换算法<br> | |
| • 内存池减少GC压力 | |
| </p> | |
| </section> | |
| </div> | |
| <footer class="footer"> | |
| <p>© 2024 CTF Flag Calculator | 高性能密码学解题工具</p> | |
| </footer> | |
| <div class="toast" id="toast"> | |
| <i class="fas fa-check-circle"></i> | |
| <span id="toast-message">操作成功</span> | |
| </div> | |
| <script> | |
| // Web Worker 代码 | |
| const workerCode = ` | |
| self.onmessage = function(e) { | |
| const { c, id } = e.data; | |
| const startTime = performance.now(); | |
| // 优化的数字转字符串算法 | |
| function bigIntToString(bigintValue) { | |
| let result = ''; | |
| let temp = bigintValue; | |
| // 快速转换算法 | |
| while (temp > 0n) { | |
| const charCode = Number(temp % 256n); | |
| result = String.fromCharCode(charCode) + result; | |
| temp = temp / 256n; | |
| } | |
| return result; | |
| } | |
| const flag = bigIntToString(BigInt(c)); | |
| const endTime = performance.now(); | |
| self.postMessage({ | |
| id: id, | |
| flag: flag, | |
| time: endTime - startTime | |
| }); | |
| }; | |
| `; | |
| // 创建 Worker Blob | |
| const blob = new Blob([workerCode], { type: 'application/javascript' }); | |
| const workerUrl = URL.createObjectURL(blob); | |
| // Worker 池 | |
| class WorkerPool { | |
| constructor(size = 4) { | |
| this.workers = []; | |
| this.taskQueue = []; | |
| this.busyWorkers = new Set(); | |
| for (let i = 0; i < size; i++) { | |
| const worker = new Worker(workerUrl); | |
| worker.onmessage = (e) => this.handleMessage(e); | |
| this.workers.push(worker); | |
| } | |
| } | |
| handleMessage(e) { | |
| const { id, flag, time } = e.data; | |
| const task = this.taskQueue.find(t => t.id === id); | |
| if (task) { | |
| this.busyWorkers.delete(task.worker); | |
| task.resolve({ flag, time }); | |
| this.taskQueue = this.taskQueue.filter(t => t.id !== id); | |
| this.processQueue(); | |
| } | |
| } | |
| processQueue() { | |
| const availableWorker = this.workers.find(w => !this.busyWorkers.has(w)); | |
| const pendingTask = this.taskQueue.find(t => !t.worker); | |
| if (availableWorker && pendingTask) { | |
| pendingTask.worker = availableWorker; | |
| this.busyWorkers.add(availableWorker); | |
| availableWorker.postMessage(pendingTask.data); | |
| } | |
| } | |
| execute(data) { | |
| return new Promise((resolve) => { | |
| const task = { | |
| id: Date.now() + Math.random(), | |
| data: data, | |
| resolve: resolve, | |
| worker: null | |
| }; | |
| this.taskQueue.push(task); | |
| this.processQueue(); | |
| }); | |
| } | |
| } | |
| // 初始化 Worker 池 | |
| const workerPool = new WorkerPool(navigator.hardwareConcurrency || 4); | |
| // 显示提示消息 | |
| function showToast(message, type = 'success') { | |
| const toast = document.getElementById('toast'); | |
| const toastMessage = document.getElementById('toast-message'); | |
| toastMessage.textContent = message; | |
| toast.className = `toast show ${type}`; | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // 更新进度条 | |
| function updateProgress(percent) { | |
| document.getElementById('progress').style.width = percent + '%'; | |
| } | |
| // 计算 Flag | |
| async function calculateFlag() { | |
| const pInput = document.getElementById('p-input').value.trim(); | |
| const cInput = document.getElementById('c-input').value.trim(); | |
| const tableInput = document.getElementById('table-input').value.trim(); | |
| const lengthInput = parseInt(document.getElementById('length-input').value); | |
| if (!pInput || !cInput) { | |
| showToast('请输入 p 和 c 的值', 'error'); | |
| return; | |
| } | |
| // 更新状态 | |
| document.getElementById('status').textContent = '计算中'; | |
| updateProgress(0); | |
| try { | |
| const p = BigInt(pInput); | |
| const c = BigInt(cInput); | |
| // 检查条件 | |
| if (c >= p) { | |
| showToast('错误:c 必须小于 p', 'error'); | |
| document.getElementById('status').textContent = '错误'; | |
| return; | |
| } | |
| updateProgress(25); | |
| // 使用 Worker 池进行计算 | |
| const startTime = performance.now(); | |
| const result = await workerPool.execute({ c: cInput }); | |
| const endTime = performance.now(); | |
| updateProgress(75); | |
| const flag = result.flag; | |
| const computationTime = (endTime - startTime).toFixed(2); | |
| // 验证 flag 格式 | |
| if (!flag.startsWith('flag{') || !flag.endsWith('}')) { | |
| showToast('警告:Flag 格式可能不正确', 'error'); | |
| } | |
| // 显示结果 | |
| const resultContent = document.getElementById('result-content'); | |
| resultContent.innerHTML = ` | |
| <div class="flag-result">${flag}</div> | |
| <div style="margin-top: 15px; color: #666;"> | |
| <p><strong>验证信息:</strong></p> | |
| <p>• 原始消息长度: ${flag.length} 字节</p> | |
| <p>• 字符集匹配: ${validateCharset(flag.substring(6, flag.length - 1), tableInput) ? '✓' : '✗'}</p> | |
| <p>• 预期长度: ${lengthInput} 字符</p> | |
| <p>• 实际长度: ${flag.length - 7} 字符</p> | |
| </div> | |
| `; | |
| // 更新统计 | |
| document.getElementById('bits').textContent = cInput.length; | |
| document.getElementById('time').textContent = computationTime + 'ms'; | |
| document.getElementById('threads').textContent = workerPool.workers.length; | |
| document.getElementById('status').textContent = '完成'; | |
| updateProgress(100); | |
| showToast('计算完成!', 'success'); | |
| // 复制到剪贴板 | |
| navigator.clipboard.writeText(flag).then(() => { | |
| console.log('Flag 已复制到剪贴板'); | |
| }); | |
| } catch (error) { | |
| console.error(error); | |
| showToast('计算出错:' + error.message, 'error'); | |
| document.getElementById('status').textContent = '错误'; | |
| } | |
| } | |
| // 验证字符集 | |
| function validateCharset(content, charset) { | |
| if (!charset) return true; | |
| for (let char of content) { | |
| if (!charset.includes(char)) return false; | |
| } | |
| return true; | |
| } | |
| // 加载示例 | |
| function loadExample() { | |
| document.getElementById('p-input').value = '407803049564139560409879631113358278888733140263084768485722310176731727783189074396823474461249041'; | |
| document.getElementById('c-input').value = '273724405776192840968808904199790097747266675483664217133748454869235934407461809379517600593224622'; | |
| document.getElementById('table-input').value = 'Lf'; | |
| document.getElementById('length-input').value = '100'; | |
| showToast('示例已加载', 'success'); | |
| } | |
| // 清空所有输入 | |
| function clearAll() { | |
| document.getElementById('p-input').value = ''; | |
| document.getElementById('c-input').value = ''; | |
| document.getElementById('table-input').value = ''; | |
| document.getElementById('length-input').value = '100'; | |
| document.getElementById('result-content').innerHTML = '<p style="color: #666;">等待计算...</p>'; | |
| document.getElementById('bits').textContent = '0'; | |
| document.getElementById('time').textContent = '0ms'; | |
| document.getElementById('threads').textContent = '1'; | |
| document.getElementById('status').textContent = '就绪'; | |
| updateProgress(0); | |
| showToast('已清空所有内容', 'success'); | |
| } | |
| // 页面加载时自动加载示例 | |
| window.addEventListener('load', () => { | |
| setTimeout(loadExample, 500); | |
| }); | |
| // 添加键盘快捷键 | |
| document.addEventListener('keydown', (e) => { | |
| if (e.ctrlKey || e.metaKey) { | |
| switch(e.key) { | |
| case 'Enter': | |
| e.preventDefault(); | |
| calculateFlag(); | |
| break; | |
| case 'l': | |
| e.preventDefault(); | |
| clearAll(); | |
| break; | |
| case 'e': | |
| e.preventDefault(); | |
| loadExample(); | |
| break; | |
| } | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |