Commutative Encryption with GoWith commutative encryption, we can decrypt with the keys in any order. Normally we would encrypt with Bob's key and then encrypt with Alice's key, and then we must decrypt with Alice's key and then Bob's. In commutative encryption, we can decrypt in any order. While our symmetric key block ciphers cannot be made commutative, we can use stream ciphers, as they perform an EX-OR function. In this example we will use the ChaCha20 stream cipher, and encrypt with Bob's key, encrypt with Alice's key, and then decrypt with Bob's key and then Alice's key. |
Theory
With commutative encryption, we can decrypt with the keys in any order. Normally we would encrypt with Bob's key and then encrypt with Alice's key, and then we must decrypt with Alice's key and then Bob's. In commutative encryption, we can decrypt in any order.
With a stream cipher, we can automatically apply commutative as we basically just EX-OR with the key stream. In the following, Bob encrypts, Alice encrypts, Bob decrypts, and the Alice decrypts:
package main import ( "fmt" "crypto/sha256" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20" "os" ) func main() { pass_bob:="pass1" pass_alice:="pass2" msg:="Hello" argCount := len(os.Args[1:]) if (argCount>0) {msg= string(os.Args[1])} if (argCount>1) {pass_bob= string(os.Args[2])} if (argCount>2) {pass_alice= string(os.Args[3])} key_bob := sha256.Sum256([]byte(pass_bob)) key_alice := sha256.Sum256([]byte(pass_alice)) nonce := make([]byte, chacha20poly1305.NonceSizeX) c_bob, _ := chacha20.NewUnauthenticatedCipher(key_bob[:32], nonce) c_alice, _ := chacha20.NewUnauthenticatedCipher(key_alice[:32], nonce) out := []byte(msg) fmt.Printf("Input text:\t%s\nBob passphrase: %s\nAlice passphrase: %s\n\n", out,pass_bob,pass_alice) fmt.Printf("Input text:\t%s\nBob keygen: %x\nAlice keygen: %x\n\n", out,key_bob,key_alice) c_bob.XORKeyStream(out, out) fmt.Printf("Cipher after Bob encrypt: %x\n",out) c_alice.XORKeyStream(out, out) fmt.Printf("Cipher after Alice encrypt: %x\n",out) c_bob, _ = chacha20.NewUnauthenticatedCipher(key_bob[:32], nonce) c_alice, _ = chacha20.NewUnauthenticatedCipher(key_alice[:32], nonce) c_bob.XORKeyStream(out, out) fmt.Printf("Cipher after Bob decrypt: %x\n",out) c_alice.XORKeyStream(out, out) fmt.Printf("Cipher after Alice decrypt: %x\n",out) fmt.Printf("Decrypted text:\t%s\n", out) }
And a sample run:
Input text: Hello Bob passphrase: qwerty Alice passphrase: 123456 Input text: Hello Bob keygen: 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5 Alice keygen: 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 Cipher after Bob encrypt: d9eef8ecdc Cipher after Alice encrypt: 7a5dcd0f43 Cipher after Bob decrypt: ebd6598ff0 Cipher after Alice decrypt: 48656c6c6f Decrypted text: Hello