diff --git a/src/wormhole/blocking/transcribe.py b/src/wormhole/blocking/transcribe.py index b51d898..167fd9f 100644 --- a/src/wormhole/blocking/transcribe.py +++ b/src/wormhole/blocking/transcribe.py @@ -16,6 +16,11 @@ from ..channel_monitor import monitor SECOND = 1 MINUTE = 60*SECOND +CONFMSG_NONCE_LENGTH = 128//8 +CONFMSG_MAC_LENGTH = 256//8 +def make_confmsg(confkey, nonce): + return nonce+HKDF(confkey, CONFMSG_MAC_LENGTH, nonce) + def to_bytes(u): return unicodedata.normalize("NFC", u).encode("utf-8") @@ -318,8 +323,10 @@ class Wormhole: self.verifier = self.derive_key(u"wormhole:verifier") if not self._send_confirm: return - conf = self.derive_key(u"wormhole:confirmation") - self._channel.send(u"_confirm", conf) + confkey = self.derive_key(u"wormhole:confirmation") + nonce = os.urandom(CONFMSG_NONCE_LENGTH) + confmsg = make_confmsg(confkey, nonce) + self._channel.send(u"_confirm", confmsg) @close_on_error def get_verifier(self): @@ -365,7 +372,9 @@ class Wormhole: phases.append(phase) (got_phase, body) = self._channel.get_first_of(phases) if got_phase == u"_confirm": - if body != self.derive_key(u"wormhole:confirmation"): + confkey = self.derive_key(u"wormhole:confirmation") + nonce = body[:CONFMSG_NONCE_LENGTH] + if body != make_confmsg(confkey, nonce): raise WrongPasswordError self._got_confirmation = True (got_phase, body) = self._channel.get_first_of([phase]) diff --git a/src/wormhole/twisted/transcribe.py b/src/wormhole/twisted/transcribe.py index 9081ba1..c38f702 100644 --- a/src/wormhole/twisted/transcribe.py +++ b/src/wormhole/twisted/transcribe.py @@ -18,6 +18,11 @@ from ..errors import ServerError, WrongPasswordError, UsageError from ..util.hkdf import HKDF from ..channel_monitor import monitor +CONFMSG_NONCE_LENGTH = 128//8 +CONFMSG_MAC_LENGTH = 256//8 +def make_confmsg(confkey, nonce): + return nonce+HKDF(confkey, CONFMSG_MAC_LENGTH, nonce) + def to_bytes(u): return unicodedata.normalize("NFC", u).encode("utf-8") @@ -336,8 +341,10 @@ class Wormhole: self.verifier = self.derive_key(u"wormhole:verifier") if not self._send_confirm: return key - conf = self.derive_key(u"wormhole:confirmation") - d1 = self._channel.send(u"_confirm", conf) + confkey = self.derive_key(u"wormhole:confirmation") + nonce = os.urandom(CONFMSG_NONCE_LENGTH) + confmsg = make_confmsg(confkey, nonce) + d1 = self._channel.send(u"_confirm", confmsg) d1.addCallback(lambda _: key) return d1 d.addCallback(_got_pake) @@ -387,7 +394,9 @@ class Wormhole: def _maybe_got_confirm(phase_and_body): (got_phase, body) = phase_and_body if got_phase == u"_confirm": - if body != self.derive_key(u"wormhole:confirmation"): + confkey = self.derive_key(u"wormhole:confirmation") + nonce = body[:CONFMSG_NONCE_LENGTH] + if body != make_confmsg(confkey, nonce): raise WrongPasswordError self._got_confirmation = True return self._channel.get_first_of([phase])