+def csrf_tag(sec, stamp, user):
+ """Compute a tag using secret SEC on `STAMP.USER'."""
+ hmac = HM.HMAC(sec, digestmod = CFG.AUTHHASH)
+ hmac.update('chpwd-nonce.%d.%s' % (stamp, user))
+ return hmac.digest()
+
+def xor_strings(x, y):
+ """Return the bitwise XOR of two octet strings."""
+ return ''.join(chr(ord(xc) ^ ord(yc)) for xc, yc in I.izip(x, y))
+
+def aont_step(x, y):
+ """Perform a step of the OAEP-based all-or-nothing transform."""
+ return xor_strings(y, CFG.AUTHHASH(x).digest())
+
+def aont_transform(m):
+ """
+ Apply an all-or-nothing transform to a (short, binary) message M.
+
+ The result is returned as a binary string.
+ """
+
+ ## The current all-or-nothing transform is basically OAEP: a two-round
+ ## Feistel network applied to a (possibly lopsided) block consisting of the
+ ## message and a random nonce. Showing that this is an AONT (in the
+ ## random-oracle model) is pretty easy.
+ hashsz = CFG.AUTHHASH().digest_size
+ assert len(m) <= hashsz
+ r = OS.urandom(hashsz)
+ m = aont_step(r, m)
+ r = aont_step(m, r)
+ return r + m
+
+def aont_recover(c):
+ """
+ Recover a message from an all-or-nothing transform C (as a binary string).
+ """
+ hashsz = CFG.AUTHHASH().digest_size
+ if not (hashsz <= len(c) <= 2*hashsz):
+ raise AuthenticationFailed, 'BADNONCE'
+ r, m = c[:hashsz], c[hashsz:]
+ r = aont_step(m, r)
+ m = aont_step(r, m)
+ return m
+