package omemo import ( "bytes" "reflect" "testing" "dev.narayana.im/narayana/telegabber/e2ee/omemo/libsignal" ) func TestEncryptOuterRoundTrip(t *testing.T) { for _, tc := range []struct { name string version int }{ {"legacy", libsignal.ProtocolVersionLegacy}, {"modern", libsignal.ProtocolVersionModern}, } { t.Run(tc.name, func(t *testing.T) { plaintext := []byte("hello from telegram") payload, err := EncryptOuter(tc.version, plaintext, "gateway@example.com") if err != nil { t.Fatalf("EncryptOuter: %v", err) } if len(payload.Ciphertext) == 0 { t.Fatalf("expected non-empty ciphertext") } if tc.version == libsignal.ProtocolVersionLegacy && len(payload.IV) != legacyIVLen { t.Fatalf("expected a %d-byte IV for legacy, got %d", legacyIVLen, len(payload.IV)) } if tc.version == libsignal.ProtocolVersionModern && payload.IV != nil { t.Fatalf("expected no IV for modern (receiver re-derives it), got %d bytes", len(payload.IV)) } got, err := DecryptOuter(tc.version, payload) if err != nil { t.Fatalf("DecryptOuter: %v", err) } if !bytes.Equal(got, plaintext) { t.Fatalf("round trip mismatch: got %q, want %q", got, plaintext) } }) } } func TestEncryptOuterTamperDetection(t *testing.T) { for _, tc := range []struct { name string version int }{ {"legacy", libsignal.ProtocolVersionLegacy}, {"modern", libsignal.ProtocolVersionModern}, } { t.Run(tc.name, func(t *testing.T) { payload, err := EncryptOuter(tc.version, []byte("secret"), "gateway@example.com") if err != nil { t.Fatalf("EncryptOuter: %v", err) } tampered := *payload tampered.Ciphertext = append([]byte{}, payload.Ciphertext...) tampered.Ciphertext[0] ^= 0xFF if _, err := DecryptOuter(tc.version, &tampered); err == nil { t.Fatalf("expected DecryptOuter to reject tampered ciphertext") } }) } } func TestSCERoundTrip(t *testing.T) { plaintext := []byte("hello sce") xmlBytes, err := sceEncode(plaintext, "alice@example.com") if err != nil { t.Fatalf("sceEncode: %v", err) } got, err := sceDecode(xmlBytes) if err != nil { t.Fatalf("sceDecode: %v", err) } if !bytes.Equal(got, plaintext) { t.Fatalf("got %q, want %q", got, plaintext) } } func TestWireEnvelopeEncodeDecode(t *testing.T) { env := &WireEnvelope{ Version: libsignal.ProtocolVersionModern, SenderSID: 12345, Payload: []byte("ciphertext-bytes"), Keys: []WireKey{ {RecipientJID: "bob@example.com", DeviceID: 1, IsPreKey: true, Ciphertext: []byte("key-ciphertext-1")}, {RecipientJID: "bob@example.com", DeviceID: 2, IsPreKey: false, Ciphertext: []byte("key-ciphertext-2")}, }, } raw, err := env.Encode() if err != nil { t.Fatalf("Encode: %v", err) } got, err := DecodeWireEnvelope(raw) if err != nil { t.Fatalf("DecodeWireEnvelope: %v", err) } if got.Version != env.Version || got.SenderSID != env.SenderSID || !bytes.Equal(got.Payload, env.Payload) { t.Fatalf("round trip mismatch: got %+v", got) } if len(got.Keys) != len(env.Keys) { t.Fatalf("expected %d keys, got %d", len(env.Keys), len(got.Keys)) } for i := range env.Keys { if !reflect.DeepEqual(got.Keys[i], env.Keys[i]) { t.Fatalf("key %d mismatch: got %+v, want %+v", i, got.Keys[i], env.Keys[i]) } } }