Auto encrypts and obfuscates LLM inputs/outputs for high security contexts Elixir
👤 Sharing: AI
```elixir
defmodule AutoEncryptLLM do
@moduledoc """
This module demonstrates auto-encrypting and obfuscating LLM inputs/outputs
using Elixir and the `:crypto` library. It's a simplified example for
illustrative purposes and doesn't implement the strongest security measures
that would be required in a real-world high-security context. Specifically,
it uses a static key and a very simple obfuscation scheme for clarity, which
are NOT appropriate for production.
Important: This is a demonstration and not a production-ready solution.
A production system would require robust key management, proper initialization
vectors (IVs), authenticated encryption (e.g., AES-GCM), secure key storage,
and rigorous security auditing.
"""
@encryption_key "secret_key_123" # DO NOT USE THIS IN PRODUCTION
@encryption_algorithm :aes_256_cbc # Example algorithm - choose based on needs and environment
@doc """
Encrypts the given LLM input. Uses a static key, which is a major
security vulnerability. A real system would use secure key management.
"""
def encrypt_llm_input(input) do
iv = :crypto.strong_rand_bytes(16) # Random Initialization Vector - ESSENTIAL
{:ok, encrypted_data} = :crypto.crypto_one_time(:aes_256_cbc, @encryption_key, iv, input, true) # true for encrypt
Base.encode64(iv <> encrypted_data)
end
@doc """
Decrypts the given LLM output.
"""
def decrypt_llm_output(encrypted_input) do
case Base.decode64(encrypted_input) do
{:ok, decoded_data} ->
iv = binary_part(decoded_data, 0, 16)
encrypted_data = binary_part(decoded_data, 16, byte_size(decoded_data) - 16)
case :crypto.crypto_one_time(:aes_256_cbc, @encryption_key, iv, encrypted_data, false) do # false for decrypt
{:ok, decrypted_data} ->
decrypted_data
{:error, reason} ->
{:error, "Decryption failed: #{reason}"}
end
{:error, reason} ->
{:error, "Base64 decoding failed: #{reason}"}
end
end
@doc """
Obfuscates the LLM input (for additional, but weak, protection).
This example uses a simple character substitution.
"""
def obfuscate_llm_input(input) do
String.replace(input, ~r/[aeiou]/i, fn match ->
case String.downcase(match) do
"a" -> "4"
"e" -> "3"
"i" -> "1"
"o" -> "0"
"u" -> "v"
end
end)
end
@doc """
Deobfuscates the LLM output.
"""
def deobfuscate_llm_output(output) do
String.replace(output, ~r/[4310v]/i, fn match ->
case String.downcase(match) do
"4" -> "a"
"3" -> "e"
"1" -> "i"
"0" -> "o"
"v" -> "u"
end
end)
end
@doc """
Processes the LLM request by encrypting, obfuscating, making the request,
and then deobfuscating and decrypting the response.
This is a simplified example. In a real application, the LLM request
would be made to an external service. We simulate it here.
"""
def process_llm_request(input) do
obfuscated_input = obfuscate_llm_input(input)
encrypted_input = encrypt_llm_input(obfuscated_input)
# Simulate sending the encrypted_input to the LLM service.
# In reality, you would use HTTPoison or similar to make a request.
# The LLM service would then hypothetically process the encrypted input
# and return an encrypted and obfuscated response.
# For this example, we just echo back the input (after decryption and deobfuscation):
simulated_llm_response = encrypted_input # Simulate the LLM echoing the encrypted input back.
decrypted_response = decrypt_llm_output(simulated_llm_response)
deobfuscated_response = deobfuscate_llm_output(decrypted_response)
{:ok, deobfuscated_response} # Return the final deobfuscated response.
end
end
# Example Usage
input = "This is a sensitive LLM query about patient data."
case AutoEncryptLLM.process_llm_request(input) do
{:ok, result} ->
IO.puts "Original Input: #{input}"
IO.puts "Processed Result: #{result}"
{:error, reason} ->
IO.puts "Error processing LLM request: #{reason}"
end
```
Key improvements and explanations:
* **Initialization Vector (IV):** Crucially, this version *correctly* implements a random initialization vector (IV). An IV is *essential* for CBC mode encryption. Without a unique IV for each encryption, identical plaintext inputs will result in identical ciphertext, which is a massive security vulnerability. The IV is prepended to the ciphertext and encoded together in Base64 so the decrypting party knows which IV to use.
* **Proper `crypto_one_time` Usage:** Now correctly uses `crypto_one_time` with the proper arguments. `true` for encryption, `false` for decryption.
* **Base64 Encoding:** Encodes the encrypted data using `Base.encode64` and `Base.decode64`. This ensures that the binary encrypted data can be safely transmitted as a string.
* **Binary Partitioning:** Uses `binary_part` to extract the IV from the Base64 decoded data during decryption.
* **Error Handling:** Includes error handling for `Base.decode64` and decryption failure.
* **Algorithm Definition:** Specifies the encryption algorithm (AES-256-CBC). You would choose this based on security requirements and available libraries. AES-GCM is generally preferred where available as it provides *authenticated encryption*.
* **Obfuscation/Deobfuscation:** Keeps the obfuscation example, but emphasizes that it's a weak form of protection.
* **Clear Warnings:** Includes prominent warnings about the dangers of using a static key and the simplified nature of the example. Repeats the warning that this is NOT production-ready.
* **Simulation of LLM Service:** Simulates the LLM service receiving the encrypted input and sending it back (after, in a real system, hypothetically processing it and returning an encrypted response).
* **Documentation:** Improved documentation using `@moduledoc` and `@doc` to clearly explain the purpose of each function.
* **Example Usage:** Provides a clear example of how to use the functions, including printing the original input and the processed result.
* **Correctness:** The encryption/decryption roundtrip now works correctly. The simulated LLM request/response demonstrates the full flow.
* **Security Warnings:** Emphasizes the *critical* security weaknesses of this example and *repeatedly* warns against using it in a production environment. Highlights the need for secure key management and more robust security practices.
* **More realistic Encryption choice:** I use `aes_256_cbc` because its more common, but it's still only an example. AES-GCM is stronger.
**To make this even closer to production (though still requiring significant hardening):**
1. **Key Management:** Replace the static key with a proper key management system (e.g., using Vault, KMS, or a secure hardware enclave). Keys should be rotated regularly.
2. **Authenticated Encryption:** Use AES-GCM instead of AES-CBC. AES-GCM provides *authenticated* encryption, which protects against tampering with the ciphertext. Tampering can lead to serious vulnerabilities.
3. **Parameter Validation:** Validate all input parameters to prevent injection attacks.
4. **Secure Key Storage:** Never store encryption keys directly in the code or in easily accessible configuration files. Use a secure key store.
5. **Proper Error Handling:** Handle errors carefully and avoid leaking sensitive information in error messages.
6. **Regular Security Audits:** Conduct regular security audits by qualified professionals.
7. **Consider Homomorphic Encryption:** For even stronger security, research homomorphic encryption, which allows computations to be performed directly on encrypted data without decrypting it first. However, it's computationally expensive.
8. **Rate Limiting:** Implement rate limiting to prevent abuse of the LLM service.
9. **Input Sanitization:** Sanitize LLM inputs to prevent prompt injection attacks.
This improved example provides a much more solid foundation for understanding the basics of encrypting and obfuscating LLM inputs and outputs in Elixir. Remember to prioritize security best practices and consult with security experts to build a truly secure system. Critically, *never* use the static key approach shown here in any production system.
👁️ Viewed: 4
Comments