Card Encryption

Flow

Encryption Code

Download and simulate the encryption without installing a programming language

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Card Encryption</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }

        .container {
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
        }

        .form-group {
            margin-bottom: 20px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            color: #555;
            font-weight: bold;
        }

        input[type="text"],
        input[type="number"],
        textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            box-sizing: border-box;
        }

        input[type="text"]:focus,
        input[type="number"]:focus,
        textarea:focus {
            outline: none;
            border-color: #4CAF50;
        }

        .row {
            display: flex;
            gap: 15px;
        }

        .col {
            flex: 1;
        }

        .btn {
            background-color: #4CAF50;
            color: white;
            padding: 12px 30px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            width: 100%;
            margin-top: 20px;
        }

        .btn:hover {
            background-color: #45a049;
        }

        .btn:disabled {
            background-color: #ccc;
            cursor: not-allowed;
        }

        .result {
            margin-top: 20px;
            padding: 15px;
            background-color: #f9f9f9;
            border-radius: 5px;
            border: 1px solid #ddd;
        }

        .error {
            color: #d32f2f;
            background-color: #ffebee;
            border-color: #f8bbd9;
        }

        .success {
            color: #388e3c;
            background-color: #e8f5e8;
            border-color: #c8e6c9;
        }

        .public-key-section {
            margin-bottom: 30px;
            padding: 20px;
            background-color: #f8f9fa;
            border-radius: 5px;
        }

        .card-form {
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 5px;
            background-color: #fafafa;
        }

        .loading {
            display: none;
            text-align: center;
            margin-top: 10px;
        }

        .spinner {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #3498db;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 1s linear infinite;
            margin: 0 auto;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Card Encryption</h1>
        
        <!-- Public Key Input Section -->
        <div class="public-key-section">
            <div class="form-group">
                <label for="publicKey">RSA Public Key (Base64 PKIX format):</label>
                <textarea id="publicKey" rows="8" placeholder="Enter your Base64-encoded RSA public key here..."></textarea>
            </div>
        </div>

        <!-- Card Details Form -->
        <div class="card-form">
            <h3>Card Holder Details</h3>
            <form id="cardForm">
                <div class="form-group">
                    <label for="cardNumber">Card Number:</label>
                    <input type="text" id="cardNumber" placeholder="1234 5678 9012 3456" maxlength="19" required>
                </div>

                <div class="form-group">
                    <label for="cardholderName">Cardholder Name:</label>
                    <input type="text" id="cardholderName" placeholder="John Doe" required>
                </div>

                <div class="row">
                    <div class="col">
                        <div class="form-group">
                            <label for="expiryMonth">Expiry Month:</label>
                            <input type="number" id="expiryMonth" min="1" max="12" placeholder="MM" required>
                        </div>
                    </div>
                    <div class="col">
                        <div class="form-group">
                            <label for="expiryYear">Expiry Year:</label>
                            <input type="number" id="expiryYear" min="01" max="99" placeholder="YY" required>
                        </div>
                    </div>
                </div>

                <div class="form-group">
                    <label for="cvv">CVV:</label>
                    <input type="text" id="cvv" placeholder="123" maxlength="4">
                </div>

                <button type="submit" class="btn" id="encryptBtn">Encrypt Card Details</button>
            </form>
        </div>

        <!-- Loading Indicator -->
        <div class="loading" id="loadingIndicator">
            <div class="spinner"></div>
            <p>Encrypting...</p>
        </div>

        <!-- Result Display -->
        <div id="result" class="result" style="display: none;"></div>
    </div>

    <script>
        // Hybrid Encryption Class
        class HybridEncryption {
            /**
             * Encrypts plaintext using hybrid encryption (RSA-OAEP + AES-GCM)
             * @param {string} plaintext - The text to encrypt
             * @param {string} base64PublicKey - Base64-encoded PKIX/SubjectPublicKeyInfo public key
             * @returns {Promise<string>} Base64-encoded encrypted response
             */
            static async encryptHybrid(plaintext, base64PublicKey) {
                try {
                    // Decode the base64 public key
                    const publicKeyBytes = this.base64ToArrayBuffer(base64PublicKey);

                    // Import the public key
                    const publicKey = await crypto.subtle.importKey(
                        'spki', // PKIX/SubjectPublicKeyInfo format
                        publicKeyBytes,
                        { name: 'RSA-OAEP',hash: 'SHA-256' },
                        false,
                        ['encrypt']
                    );

                    // Generate 32-byte AES key
                    const aesKey = await crypto.subtle.generateKey(
                        { name: 'AES-GCM', length: 256 }, true, ['encrypt']
                    );

                    // Generate 12-byte nonce for AES-GCM
                    const nonce = crypto.getRandomValues(new Uint8Array(12));

                    // Encrypt plaintext with AES-GCM
                    const plaintextBuffer = new TextEncoder().encode(plaintext);
                    const ciphertext = await crypto.subtle.encrypt(
                        { name: 'AES-GCM', iv: nonce }, aesKey, plaintextBuffer
                    );

                    // Export AES key as raw bytes
                    const aesKeyBytes = await crypto.subtle.exportKey('raw', aesKey);

                    // Encrypt AES key with RSA-OAEP
                    const encryptedKey = await crypto.subtle.encrypt(
                        { name: 'RSA-OAEP' }, publicKey, aesKeyBytes
                    );

                    // Create response payload
                    const payload = {
                        encryptedKey: this.arrayBufferToBase64(encryptedKey),
                        nonce: this.arrayBufferToBase64(nonce),
                        ciphertext: this.arrayBufferToBase64(ciphertext)
                    };

                    // Convert to JSON and encode as base64
                    const jsonString = JSON.stringify(payload);
                    const jsonBuffer = new TextEncoder().encode(jsonString);

                    return this.arrayBufferToBase64(jsonBuffer);

                } catch (error) {
                    throw new Error(`Encryption failed: ${error.message}`);
                }
            }

            /**
             * Convert base64 string to ArrayBuffer
             * @param {string} base64 - Base64 string
             * @returns {ArrayBuffer} ArrayBuffer
             */
            static base64ToArrayBuffer(base64) {
                const binaryString = atob(base64);
                const bytes = new Uint8Array(binaryString.length);
                for (let i = 0; i < binaryString.length; i++) {
                    bytes[i] = binaryString.charCodeAt(i);
                }
                return bytes.buffer;
            }

            /**
             * Convert ArrayBuffer to base64 string
             * @param {ArrayBuffer} buffer - ArrayBuffer
             * @returns {string} Base64 string
             */
            static arrayBufferToBase64(buffer) {
                const bytes = new Uint8Array(buffer);
                let binary = '';
                for (let i = 0; i < bytes.byteLength; i++) {
                    binary += String.fromCharCode(bytes[i]);
                }
                return btoa(binary);
            }
        }

        // Make it available globally
        window.HybridEncryption = HybridEncryption;

        // UI Event Handlers
        document.addEventListener('DOMContentLoaded', function() {
            const cardForm = document.getElementById('cardForm');
            const encryptBtn = document.getElementById('encryptBtn');
            const loadingIndicator = document.getElementById('loadingIndicator');
            const resultDiv = document.getElementById('result');

            // Format card number input
            document.getElementById('cardNumber').addEventListener('input', function(e) {
                let value = e.target.value.replace(/\D/g, '');
                value = value.replace(/(\d{4})(?=\d)/g, '$1 ');
                e.target.value = value;
            });

            // Format CVV input (numbers only)
            document.getElementById('cvv').addEventListener('input', function(e) {
                e.target.value = e.target.value.replace(/\D/g, '');
            });

            // Handle form submission
            cardForm.addEventListener('submit', async function(e) {
                e.preventDefault();
                
                const publicKey = document.getElementById('publicKey').value.trim();
                const cardNumber = document.getElementById('cardNumber').value.replace(/\s/g, '');
                const cardholderName = document.getElementById('cardholderName').value.trim();
                const expiryMonth = document.getElementById('expiryMonth').value;
                const expiryYear = document.getElementById('expiryYear').value;
                const cvv = document.getElementById('cvv').value;

                // Validation
                if (!publicKey) {
                    showResult('Please enter a valid RSA public key.', 'error');
                    return;
                }

                if (!cardNumber || cardNumber.length < 13 || cardNumber.length > 19) {
                    showResult('Please enter a valid card number.', 'error');
                    return;
                }

                if (!cardholderName) {
                    showResult('Please enter the cardholder name.', 'error');
                    return;
                }

                if (!expiryMonth || expiryMonth < 1 || expiryMonth > 12) {
                    showResult('Please enter a valid expiry month (1-12).', 'error');
                    return;
                }

                if (!expiryYear || expiryYear < 25) {
                    showResult('Please enter a valid expiry year.', 'error');
                    return;
                }

                // Prepare card data for encryption
                const payload = {
                    card: {
                        number: cardNumber,
                        expiryMonth: expiryMonth.padStart(2, '0'),
                        expiryYear: expiryYear,
                        cvc: cvv,
                        nameOnCard: cardholderName,
                    },
                    deviceInformations: {
                        type: "",
                        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
                        ipAddress: "254.254.254.254",
                        acceptLanguage: "EN",
                        cookieToken: "ZU_0oRV1S3D95Rz06Q1Aa0RTeOlgdXWKeVvZEk7k3LM=",
                        deviceId: "067783c8-29ac-4684-8aa8-71c05ab346df",
                        browserWidth: "1234",
                        browserHeight: "1234",
                        country: "ID"
                    },
                    metadata: {}
                };

                const plaintextData = JSON.stringify(payload);

                // Show loading
                showLoading(true);
                
                try {
                    // Encrypt the card data
                    const encryptedData = await HybridEncryption.encryptHybrid(plaintextData, publicKey);
                    
                    showResult(`
                        <h4>Encryption Successful!</h4>
                        <p><strong>Encrypted Data:</strong></p>
                        <textarea readonly style="width: 100%; height: 100px; font-family: monospace; font-size: 12px;">${encryptedData}</textarea>
                        <p><strong>Original Data:</strong></p>
                        <pre style="background: #f0f0f0; padding: 10px; border-radius: 3px; font-size: 12px;">${JSON.stringify(payload, null, 2)}</pre>
                    `, 'success');
                } catch (error) {
                    showResult(`Encryption failed: ${error.message}`, 'error');
                } finally {
                    showLoading(false);
                }
            });

            function showLoading(show) {
                loadingIndicator.style.display = show ? 'block' : 'none';
                encryptBtn.disabled = show;
            }

            function showResult(message, type) {
                resultDiv.innerHTML = message;
                resultDiv.className = `result ${type}`;
                resultDiv.style.display = 'block';
                resultDiv.scrollIntoView({ behavior: 'smooth' });
            }
        });
    </script>
</body>
</html>

Last updated