From 676a4ceb87e8c8e0811b4312ce4b3b74f53b4368 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 2 Sep 2021 09:57:06 +0200 Subject: stupidgcm: deduplicate tests 1/2 Pull the code shared between chacha and gcm into generic functions. --- internal/stupidgcm/common_test.go | 152 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 internal/stupidgcm/common_test.go (limited to 'internal/stupidgcm/common_test.go') diff --git a/internal/stupidgcm/common_test.go b/internal/stupidgcm/common_test.go new file mode 100644 index 0000000..28f3308 --- /dev/null +++ b/internal/stupidgcm/common_test.go @@ -0,0 +1,152 @@ +package stupidgcm + +import ( + "bytes" + "crypto/cipher" + "encoding/hex" + "testing" +) + +// testEncryptDecrypt encrypts and decrypts using both stupidgcm and Go's built-in +// GCM implementation and verifies that the results are identical. +func testEncryptDecrypt(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) { + if c1.NonceSize() != c2.NonceSize() { + t.Fatal("different NonceSize") + } + if c1.Overhead() != c2.Overhead() { + t.Fatal("different Overhead") + } + + authData := randBytes(24) + iv := randBytes(c1.NonceSize()) + + dst := make([]byte, 71) // 71 = arbitrary length + + // Check all block sizes from 1 to 5000 + for i := 1; i < 5000; i++ { + in := make([]byte, i) + + c1out := c1.Seal(dst, iv, in, authData) + c2out := c2.Seal(dst, iv, in, authData) + + // Ciphertext must be identical to Go GCM + if !bytes.Equal(c1out, c2out) { + t.Fatalf("Compare failed for encryption, size %d", i) + t.Log("c1out:") + t.Log("\n" + hex.Dump(c1out)) + t.Log("c2out:") + t.Log("\n" + hex.Dump(c2out)) + } + + c1out2, sErr := c1.Open(dst, iv, c1out[len(dst):], authData) + if sErr != nil { + t.Fatal(sErr) + } + c2out2, gErr := c2.Open(dst, iv, c2out[len(dst):], authData) + if gErr != nil { + t.Fatal(gErr) + } + + // Plaintext must be identical to Go GCM + if !bytes.Equal(c1out2, c2out2) { + t.Fatalf("Compare failed for decryption, size %d", i) + } + } +} + +// Seal re-uses the "dst" buffer it is large enough. +// Check that this works correctly by testing different "dst" capacities from +// 5000 to 16 and "in" lengths from 1 to 5000. +func testInplaceSeal(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) { + authData := randBytes(24) + iv := randBytes(c1.NonceSize()) + + max := 5016 + // Check all block sizes from 1 to 5000 + for i := 1; i < max-16; i++ { + in := make([]byte, i) + dst := make([]byte, max-i) + dst = dst[:16] + + c1out := c1.Seal(dst, iv, in, authData) + dst2 := make([]byte, 16) + c2out := c2.Seal(dst2, iv, in, authData) + + // Ciphertext must be identical to Go GCM + if !bytes.Equal(c1out, c2out) { + t.Fatalf("Compare failed for encryption, size %d", i) + t.Log("sOut:") + t.Log("\n" + hex.Dump(c1out)) + t.Log("gOut:") + t.Log("\n" + hex.Dump(c2out)) + } + } +} + +// testInplaceOpen - Open re-uses the "dst" buffer it is large enough. +// Check that this works correctly by testing different "dst" capacities from +// 5000 to 16 and "in" lengths from 1 to 5000. +func testInplaceOpen(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) { + authData := randBytes(24) + iv := randBytes(c1.NonceSize()) + + max := 5016 + // Check all block sizes from 1 to 5000 + for i := 1; i < max-c1.NonceSize(); i++ { + in := make([]byte, i) + + c2ciphertext := c2.Seal(iv, iv, in, authData) + + dst := make([]byte, max-i) + // sPlaintext ... stupidgcm plaintext + c1plaintext, err := c1.Open(dst[:0], iv, c2ciphertext[c1.NonceSize():], authData) + if err != nil { + t.Fatal(err) + } + + // Plaintext must be identical to Go GCM + if !bytes.Equal(in, c1plaintext) { + t.Fatalf("Compare failed, i=%d", i) + } + } +} + +// testCorruption verifies that changes in the ciphertext result in a decryption +// error +func testCorruption(t *testing.T, c cipher.AEAD) { + authData := randBytes(24) + iv := randBytes(c.NonceSize()) + + in := make([]byte, 354) + out := c.Seal(nil, iv, in, authData) + out2, sErr := c.Open(nil, iv, out, authData) + if sErr != nil { + t.Fatal(sErr) + } + if !bytes.Equal(in, out2) { + t.Fatalf("Compare failed") + } + + // Corrupt first byte + out[0]++ + out2, sErr = c.Open(nil, iv, out, authData) + if sErr == nil || out2 != nil { + t.Fatalf("Should have gotten error") + } + out[0]-- + + // Corrupt last byte + out[len(out)-1]++ + out2, sErr = c.Open(nil, iv, out, authData) + if sErr == nil || out2 != nil { + t.Fatalf("Should have gotten error") + } + out[len(out)-1]-- + + // Append one byte + out = append(out, 0) + out2, sErr = c.Open(nil, iv, out, authData) + if sErr == nil || out2 != nil { + t.Fatalf("Should have gotten error") + } +} -- cgit v1.2.3