A simple, secure implementation of One-Time Pad encryption in Go.
A One-Time Pad (OTP) is a theoretically unbreakable encryption technique when used correctly. It works by combining a message with a random secret (the "pad") that is:
- As long as the message - The key must be exactly the same length as the plaintext
- Truly random - Generated using cryptographically secure random number generation
- Used only once - Each key must never be reused (hence "one-time")
- Kept secret - Both sender and receiver must have the key, but no one else
When these conditions are met, OTP provides perfect secrecy - the encrypted message reveals absolutely nothing about the original message to an attacker.
- Encryption: Each byte of the message is added to the corresponding byte of the key (modulo 256)
- Decryption: Each byte of the encrypted message has the corresponding key byte subtracted (modulo 256)
Plaintext: "HELLO"
Key: [Random bytes]
Encrypted: [XOR result]
Decrypted: "HELLO" (using same key)
go get github.com/IzyPro/otppackage main
import (
"fmt"
"log"
"github.com/IzyPro/otp"
)
func main() {
// Your secret message
message := []byte("Hello, this is a secret message!")
// Step 1: Generate a one-time pad (same length as message)
secret, err := otp.GenerateOTP(len(message))
if err != nil {
log.Fatal("Failed to generate OTP:", err)
}
fmt.Printf("Generated OTP (%d bytes)\n", len(secret))
// Step 2: Encrypt the message
encrypted, err := otp.Encrypt(message, secret)
if err != nil {
log.Fatal("Encryption failed:", err)
}
fmt.Printf("Original: %s\n", message)
fmt.Printf("Encrypted: %x\n", encrypted)
// Step 3: Decrypt the message
decrypted, err := otp.Decrypt(encrypted, secret)
if err != nil {
log.Fatal("Decryption failed:", err)
}
fmt.Printf("Decrypted: %s\n", decrypted)
// Output:
// Generated OTP (33 bytes)
// Original: Hello, this is a secret message!
// Encrypted: 7a3f2e1b... (hex representation)
// Decrypted: Hello, this is a secret message!
}package main
import (
"encoding/base64"
"fmt"
"log"
"github.com/yourusername/otp"
)
func main() {
message := []byte("Transfer $1000 to account 12345")
// Sender: Generate OTP and encrypt
secret, _ := otp.GenerateOTP(len(message))
encrypted, _ := otp.Encrypt(message, secret)
// Convert to base64 for transmission
encryptedB64 := base64.StdEncoding.EncodeToString(encrypted)
secretB64 := base64.StdEncoding.EncodeToString(secret)
fmt.Println("Send this encrypted message:", encryptedB64)
fmt.Println("Share this secret key (securely!):", secretB64)
// Receiver: Decrypt the message
// (In practice, decode from base64 first)
decrypted, _ := otp.Decrypt(encrypted, secret)
fmt.Printf("Decrypted message: %s\n", decrypted)
}package main
import (
"io/ioutil"
"log"
"github.com/yourusername/otp"
)
func encryptFile(inputPath, outputPath, keyPath string) error {
// Read the file
plaintext, err := ioutil.ReadFile(inputPath)
if err != nil {
return err
}
// Generate OTP
secret, err := otp.GenerateOTP(len(plaintext))
if err != nil {
return err
}
// Encrypt
encrypted, err := otp.Encrypt(plaintext, secret)
if err != nil {
return err
}
// Save encrypted file
if err := ioutil.WriteFile(outputPath, encrypted, 0644); err != nil {
return err
}
// Save key file (keep this secure!)
if err := ioutil.WriteFile(keyPath, secret, 0600); err != nil {
return err
}
return nil
}
func decryptFile(inputPath, keyPath, outputPath string) error {
// Read encrypted file
encrypted, err := ioutil.ReadFile(inputPath)
if err != nil {
return err
}
// Read key
secret, err := ioutil.ReadFile(keyPath)
if err != nil {
return err
}
// Decrypt
decrypted, err := otp.Decrypt(encrypted, secret)
if err != nil {
return err
}
// Save decrypted file
return ioutil.WriteFile(outputPath, decrypted, 0644)
}
func main() {
// Encrypt a file
if err := encryptFile("secret.txt", "secret.enc", "secret.key"); err != nil {
log.Fatal(err)
}
// Decrypt a file
if err := decryptFile("secret.enc", "secret.key", "decrypted.txt"); err != nil {
log.Fatal(err)
}
}Generates a cryptographically secure random one-time pad of the specified length.
Parameters:
length- The number of random bytes to generate
Returns:
[]byte- The generated one-time paderror- Error if random generation fails
Example:
secret, err := otp.GenerateOTP(32)
if err != nil {
log.Fatal(err)
}Encrypts a message using a one-time pad.
Parameters:
message- The plaintext message to encryptsecret- The one-time pad (must be same length as message)
Returns:
[]byte- The encrypted ciphertexterror- Error if message and secret lengths don't match
Example:
message := []byte("Secret message")
secret, _ := otp.GenerateOTP(len(message))
encrypted, err := otp.Encrypt(message, secret)Decrypts a message using a one-time pad.
Parameters:
message- The encrypted ciphertextsecret- The one-time pad used for encryption
Returns:
[]byte- The decrypted plaintexterror- Error if message and secret lengths don't match
Example:
decrypted, err := otp.Decrypt(encrypted, secret)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Decrypted: %s\n", decrypted)-
Never reuse a key - Each OTP must be used exactly once. Reusing a key completely breaks the security.
-
Keep keys secure - The secret key must be transmitted through a secure channel separate from the encrypted message.
-
Key length equals message length - The key must be exactly as long as the message you're encrypting.
-
Use truly random keys - This implementation uses
crypto/randwhich is cryptographically secure. Don't use weaker random sources. -
Destroy keys after use - Once a key is used, it should be securely deleted from both sender and receiver.
// ❌ WRONG: Reusing the same key
secret, _ := otp.GenerateOTP(100)
encrypted1, _ := otp.Encrypt(message1, secret)
encrypted2, _ := otp.Encrypt(message2, secret) // INSECURE!
// ❌ WRONG: Key shorter than message
secret, _ := otp.GenerateOTP(10)
message := []byte("This message is much longer than 10 bytes")
encrypted, err := otp.Encrypt(message, secret) // Returns error
// ❌ WRONG: Using predictable "random" data
secret := []byte{1, 2, 3, 4, 5} // NOT random!// ✅ CORRECT: Generate new key for each message
message := []byte("Secret message")
secret, _ := otp.GenerateOTP(len(message))
encrypted, _ := otp.Encrypt(message, secret)
// Use the encrypted message and key once, then discard the key
// ✅ CORRECT: Check for errors
encrypted, err := otp.Encrypt(message, secret)
if err != nil {
log.Fatal("Encryption failed:", err)
}- Key Distribution Problem: Both parties need to securely share the one-time pad before communication. This is the main practical limitation of OTP.
- Key Size: You need as much key material as you have data to encrypt, which can be impractical for large amounts of data.
- One-Time Use Only: Keys cannot be reused, requiring constant generation and secure distribution of new keys.
OTP is ideal when:
- Maximum security is required
- Message size is relatively small
- You have a secure channel for key distribution
- You can ensure keys are never reused
For most applications, modern algorithms like AES-GCM are more practical while still being very secure.
Run the tests:
go test -vRun benchmarks:
go test -bench=.MIT License - See LICENSE file for details
Contributions are welcome! Please feel free to submit a Pull Request.