Python/JS开发者求助:GOST 28147-89算法加解密使用问题
GOST 28147-89 Encryption/Decryption for Large Texts (Python & JavaScript)
Hey there! Let's work through your GOST 28147-89 implementation issues for both Python and JavaScript, including handling large texts like lorem1000.
Python (Using pygost)
First, let's fix up your pygost setup. You've already imported parts of gost28147, but we need to add key decoding, block handling, padding, and actual encryption/decryption logic. Your provided key is Base64-encoded, so we'll start by decoding that.
Step-by-Step Implementation
- Decode the Base64 Key: Convert your key string into raw bytes.
- Use a Secure Mode: We'll use CBC mode (safer than ECB) with an initialization vector (IV).
- Handle Padding: GOST 28147 uses 64-bit (8-byte) blocks, so we need to pad text that doesn't fit perfectly into blocks.
- Encrypt/Decrypt Large Text: Split the text into blocks, process each, and combine results.
Full Code Example
import base64 from pygost.gost28147 import encrypt, decrypt, DEFAULT_SBOX, BLOCKSIZE # Decode your Base64 key key = base64.b64decode("afdfGRerehrehtwICJAAGByqFAwICHgEDQwAEQHuYflp31mEqb1YLSTOlzWJCUWDsDmNVZ9Lor7bkJfbrSnsFg7gcHGNuGoIhfds+Shgfhrtgergerfewwer7W2Wd3P+sPnrmtw=") # PKCS#7 padding function (required for block alignment) def pad(data): padding_len = BLOCKSIZE - len(data) % BLOCKSIZE return data + bytes([padding_len]) * padding_len # PKCS#7 unpadding function def unpad(data): padding_len = data[-1] return data[:-padding_len] # Encrypt function (CBC mode) def gost_encrypt(plaintext, key, iv): plaintext_bytes = plaintext.encode("utf-8") padded_data = pad(plaintext_bytes) ciphertext = b"" prev_block = iv for i in range(0, len(padded_data), BLOCKSIZE): block = padded_data[i:i+BLOCKSIZE] # XOR block with previous ciphertext block (IV for first block) xor_block = bytes([a ^ b for a, b in zip(block, prev_block)]) encrypted_block = encrypt(key, xor_block, sbox=DEFAULT_SBOX) ciphertext += encrypted_block prev_block = encrypted_block return base64.b64encode(ciphertext).decode("utf-8") # Decrypt function (CBC mode) def gost_decrypt(ciphertext_b64, key, iv): ciphertext = base64.b64decode(ciphertext_b64) plaintext = b"" prev_block = iv for i in range(0, len(ciphertext), BLOCKSIZE): block = ciphertext[i:i+BLOCKSIZE] decrypted_block = decrypt(key, block, sbox=DEFAULT_SBOX) # XOR with previous block to get plaintext block plaintext_block = bytes([a ^ b for a, b in zip(decrypted_block, prev_block)]) plaintext += plaintext_block prev_block = block return unpad(plaintext).decode("utf-8") # Example usage with lorem1000 iv = b"abcdefgh" # 8-byte IV (generate a random one for production!) large_text = "Lorem ipsum dolor sit amet..." # Replace with your lorem1000 text # Encrypt encrypted = gost_encrypt(large_text, key, iv) print("Encrypted text:", encrypted) # Decrypt decrypted = gost_decrypt(encrypted, key, iv) print("Decrypted text:", decrypted)
Notes:
- IV: Always generate a cryptographically random IV for production use (never reuse an IV with the same key).
- Mode: If you need ECB mode (not recommended for large texts), you can skip the XOR step with the previous block.
JavaScript (Using GostCipher)
Your error Uncaught Error: Invalid block length happens because the GostCipher constructor requires a valid S-box parameter. GOST 28147 uses standard S-boxes—we'll use the default one matching pygost's DEFAULT_SBOX.
Step-by-Step Implementation
- Define the Standard S-box: Use the default GOST 28147 S-box values.
- Correctly Instantiate GostCipher: Pass the S-box as a parameter.
- Decode the Base64 Key: Convert your key string into a Uint8Array.
- Handle Padding: Add/remove padding to align text with 8-byte blocks.
- Process Large Text: Split into blocks and encrypt/decrypt.
Full Code Example
// Standard GOST 28147-89 S-box (matches pygost's DEFAULT_SBOX) const DEFAULT_SBOX = [ [4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3], [14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9], [5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11], [7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3], [6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2], [4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14], [13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12], [1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12] ]; // PKCS#7 padding function function pad(data) { const blockSize = 8; const paddingLen = blockSize - (data.length % blockSize); const padding = new Uint8Array(paddingLen).fill(paddingLen); return new Uint8Array([...data, ...padding]); } // PKCS#7 unpadding function function unpad(data) { const paddingLen = data[data.length - 1]; return data.slice(0, data.length - paddingLen); } // Base64 decode to Uint8Array function base64Decode(str) { const binStr = atob(str); const arr = new Uint8Array(binStr.length); for (let i = 0; i < binStr.length; i++) { arr[i] = binStr.charCodeAt(i); } return arr; } // Base64 encode from Uint8Array function base64Encode(arr) { const binStr = String.fromCharCode(...arr); return btoa(binStr); } // Example usage const keyBase64 = "afdfGRerehrehtwICJAAGByqFAwICHgEDQwAEQHuYflp31mEqb1YLSTOlzWJCUWDsDmNVZ9Lor7bkJfbrSnsFg7gcHGNuGoIhfds+Shgfhrtgergerfewwer7W2Wd3P+sPnrmtw="; const key = base64Decode(keyBase64); const iv = new Uint8Array([97, 98, 99, 100, 101, 102, 103, 104]); // "abcdefgh" as bytes const largeText = "Lorem ipsum dolor sit amet..."; // Replace with your lorem1000 text // Initialize GostCipher with correct parameters const gostCipher = new GostCipher('GOST 28147', 1989, 64, 'ES', DEFAULT_SBOX); // Encrypt const plaintextBytes = new TextEncoder().encode(largeText); const paddedPlaintext = pad(plaintextBytes); const ciphertextBytes = gostCipher.encrypt(paddedPlaintext, key, iv); const encryptedBase64 = base64Encode(ciphertextBytes); console.log("Encrypted text:", encryptedBase64); // Decrypt const ciphertextDecoded = base64Decode(encryptedBase64); const decryptedPaddedBytes = gostCipher.decrypt(ciphertextDecoded, key, iv); const decryptedBytes = unpad(decryptedPaddedBytes); const decryptedText = new TextDecoder().decode(decryptedBytes); console.log("Decrypted text:", decryptedText);
Notes:
- S-box: Make sure you're using the correct S-box for your use case (some implementations use regional variants, but the one above is the standard default).
- IV: Just like in Python, use a random IV for production and share it with the decryptor (it doesn't need to be secret).
内容的提问来源于stack exchange,提问作者Nikolay Gogol




