fix: correct key schedule welcome_secret derivation order
The welcome_secret must be derived from member_secret (the Extract of
joiner_secret and psk_secret), not directly from joiner_secret. This
matches the RFC 9420 key schedule diagram where welcome_secret is
derived after the psk extraction step.
Before: welcome = DeriveSecret(joiner_secret, "welcome")
After: member = Extract(joiner_secret, psk_secret)
welcome = DeriveSecret(member, "welcome")
epoch = ExpandWithLabel(member, "epoch", GroupContext, Nh)
This fix was discovered and validated by the IETF interop test vectors.
Key schedule tests now pass all 11 derived secrets across multiple epochs.
https://claude.ai/code/session_01NocQDWj2Y92FugjfgazzL3
This commit is contained in:
+7
-7
@@ -69,14 +69,14 @@ class KeySchedule(
|
||||
val prk = MlsCryptoProvider.hkdfExtract(initSecret, commitSecret)
|
||||
val joinerSecret = MlsCryptoProvider.expandWithLabel(prk, "joiner", groupContext, MlsCryptoProvider.HASH_OUTPUT_LENGTH)
|
||||
|
||||
// welcome_secret = DeriveSecret(joiner_secret, "welcome")
|
||||
val welcomeSecret = MlsCryptoProvider.deriveSecret(joinerSecret, "welcome")
|
||||
// member_secret = HKDF-Extract(joiner_secret, psk_secret)
|
||||
val memberSecret = MlsCryptoProvider.hkdfExtract(joinerSecret, pskSecret)
|
||||
|
||||
// epoch_secret = ExpandWithLabel(
|
||||
// HKDF-Extract(joiner_secret, psk_secret),
|
||||
// "epoch", GroupContext, Nh)
|
||||
val epochPrk = MlsCryptoProvider.hkdfExtract(joinerSecret, pskSecret)
|
||||
val epochSecret = MlsCryptoProvider.expandWithLabel(epochPrk, "epoch", groupContext, MlsCryptoProvider.HASH_OUTPUT_LENGTH)
|
||||
// welcome_secret = DeriveSecret(member_secret, "welcome")
|
||||
val welcomeSecret = MlsCryptoProvider.deriveSecret(memberSecret, "welcome")
|
||||
|
||||
// epoch_secret = ExpandWithLabel(member_secret, "epoch", GroupContext, Nh)
|
||||
val epochSecret = MlsCryptoProvider.expandWithLabel(memberSecret, "epoch", groupContext, MlsCryptoProvider.HASH_OUTPUT_LENGTH)
|
||||
|
||||
// Derive individual secrets from epoch_secret
|
||||
val senderDataSecret = MlsCryptoProvider.deriveSecret(epochSecret, "sender data")
|
||||
|
||||
Reference in New Issue
Block a user