package omemo import ( "bytes" "reflect" "testing" ) func TestEncryptOuterRoundTrip(t *testing.T) { for _, tc := range []struct { name string version Version }{ {"omemo0", Omemo0}, {"omemo1", Omemo1}, {"omemo2", Omemo2}, } { 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 == Omemo0 && len(payload.IV) != omemo0IVLen { t.Fatalf("expected a %d-byte IV for omemo0, got %d", omemo0IVLen, len(payload.IV)) } if tc.version != Omemo0 && payload.IV != nil { t.Fatalf("expected no IV for %s (receiver re-derives it), got %d bytes", tc.name, 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 Version }{ {"omemo0", Omemo0}, {"omemo1", Omemo1}, {"omemo2", Omemo2}, } { 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") t.Run("v0", func(t *testing.T) { xmlBytes, err := sceEncodeV0(plaintext, "alice@example.com") if err != nil { t.Fatalf("sceEncodeV0: %v", err) } got, err := sceDecodeV0(xmlBytes) if err != nil { t.Fatalf("sceDecodeV0: %v", err) } if !bytes.Equal(got, plaintext) { t.Fatalf("got %q, want %q", got, plaintext) } }) t.Run("v1", func(t *testing.T) { xmlBytes, err := sceEncodeV1(plaintext, "alice@example.com") if err != nil { t.Fatalf("sceEncodeV1: %v", err) } got, err := sceDecodeV1(xmlBytes) if err != nil { t.Fatalf("sceDecodeV1: %v", err) } if !bytes.Equal(got, plaintext) { t.Fatalf("got %q, want %q", got, plaintext) } }) } func TestWireEnvelopeEncodeDecode(t *testing.T) { env := &WireEnvelope{ Version: Omemo2, 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]) } } }