telegabber/e2ee/omemo/version.go
2026-07-28 23:14:32 -04:00

80 lines
2.7 KiB
Go

package omemo
import (
"fmt"
"dev.narayana.im/narayana/telegabber/e2ee/omemo/libsignal"
)
// Version identifies which OMEMO wire-format generation a message, device
// list, or bundle uses - the full namespace+XML dialect, not just the
// underlying crypto-engine version (see libsignal.ProtocolVersionV3/V4,
// which is a strictly coarser, two-way distinction shared by two of the
// three versions below).
type Version int
const (
// Omemo0 is the original "siacs" OMEMO (eu.siacs.conversations.axolotl,
// XEP-0384 <= 0.3.0): libsignal.ProtocolVersionV3, AES-128-GCM directly
// on the plaintext body, key||tag distributed per-device, <iv> element
// present. Still the most widely deployed version as of this writing,
// and the current implementation priority.
Omemo0 Version = iota
// Omemo1 is urn:xmpp:omemo:1 (XEP-0384 0.4.0-0.7.x, introduced
// 2020-03-08): libsignal.ProtocolVersionV4, AES-256-CBC+HMAC-SHA256
// (via HKDF) over an SCE envelope using the OLD (pre-0.4.0) XEP-0420
// dialect: root element <content xmlns='urn:xmpp:sce:0'>, inner
// wrapper <payload/>. Confirmed by reading the archived XEP-0420 0.3.2
// spec directly (https://xmpp.org/extensions/attic/xep-0420-0.3.2.html),
// not assumed - see sceEncodeV0/sceDecodeV0.
Omemo1
// Omemo2 is urn:xmpp:omemo:2 (XEP-0384 0.8.0+, current spec):
// libsignal.ProtocolVersionV4, the same AES-256-CBC+HMAC-SHA256 scheme
// as Omemo1, but over the NEW (XEP-0420 0.4.0+) dialect: root element
// <envelope xmlns='urn:xmpp:sce:1'>, inner wrapper <content/>.
Omemo2
)
func (v Version) String() string {
switch v {
case Omemo0:
return "omemo0"
case Omemo1:
return "omemo1"
case Omemo2:
return "omemo2"
default:
return "omemo?"
}
}
// ParseVersion maps an e2ee.Variant string (omemo0/omemo1/omemo2 - see
// Version.String()) back to a Version, at every point the generic
// e2ee.Backend interface hands one in (DeviceListNode, BundleNode,
// PublishedIdentity, PublishedBundle).
func ParseVersion(s string) (Version, error) {
switch s {
case "omemo0":
return Omemo0, nil
case "omemo1":
return Omemo1, nil
case "omemo2":
return Omemo2, nil
default:
return 0, fmt.Errorf("omemo: unknown version %q (want omemo0, omemo1, or omemo2)", s)
}
}
// libsignalVersion returns the underlying Signal-protocol wire version
// this OMEMO version uses. Omemo1 and Omemo2 share the same crypto-engine
// version - libomemo-c itself only branches on "message_version >= 4", not
// on which OMEMO namespace is in play (confirmed by reading protocol.c) -
// they differ only in the outer XML/SCE dialect (see envelope.go).
func (v Version) libsignalVersion() int {
if v == Omemo0 {
return libsignal.ProtocolVersionV3
}
return libsignal.ProtocolVersionV4
}