|
@@ -96,7 +96,7 @@ func TestEncryptedNeverFallsBackToPlaintext(t *testing.T) {
|
|
|
c, _ := NewCodec(ModeRequired, testRing(t, "k1", "k1"))
|
|
c, _ := NewCodec(ModeRequired, testRing(t, "k1", "k1"))
|
|
|
enc, _ := c.Encrypt(1, "tok")
|
|
enc, _ := c.Encrypt(1, "tok")
|
|
|
// Corrupt the ciphertext body — must error, never return raw bytes.
|
|
// Corrupt the ciphertext body — must error, never return raw bytes.
|
|
|
- bad := enc[:len(enc)-2] + "AA"
|
|
|
|
|
|
|
+ bad := flipLastCiphertextBit(t, enc)
|
|
|
if _, err := c.Decrypt(1, bad); err == nil {
|
|
if _, err := c.Decrypt(1, bad); err == nil {
|
|
|
t.Fatal("corrupted ciphertext must fail, not fall back to plaintext")
|
|
t.Fatal("corrupted ciphertext must fail, not fall back to plaintext")
|
|
|
}
|
|
}
|
|
@@ -108,6 +108,19 @@ func TestEncryptedNeverFallsBackToPlaintext(t *testing.T) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// flipLastCiphertextBit rewrites the body through its decoded bytes, because
|
|
|
|
|
+// editing the trailing base64 characters can leave those bytes untouched.
|
|
|
|
|
+func flipLastCiphertextBit(t *testing.T, stored string) string {
|
|
|
|
|
+ t.Helper()
|
|
|
|
|
+ cut := strings.LastIndex(stored, ":") + 1
|
|
|
|
|
+ blob, err := base64.RawURLEncoding.DecodeString(stored[cut:])
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatalf("decode ciphertext body: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ blob[len(blob)-1] ^= 0x01
|
|
|
|
|
+ return stored[:cut] + base64.RawURLEncoding.EncodeToString(blob)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func TestEncryptionMarkerPassesThroughWhenDisabled(t *testing.T) {
|
|
func TestEncryptionMarkerPassesThroughWhenDisabled(t *testing.T) {
|
|
|
c, _ := NewCodec(ModeOff, nil)
|
|
c, _ := NewCodec(ModeOff, nil)
|
|
|
stored := "enc:v1:not-ciphertext"
|
|
stored := "enc:v1:not-ciphertext"
|