Welcome, guest | Sign In | My Account | Store | Cart

This module provides a bubblebabble function, which computes a (somewhat more) human readable format for message digests.

Python, 72 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#! /usr/bin/env python
"""Compute a (somewhat more) human readable format for message
digests. This is port of the perl module Digest-BubbleBabble-0.01
(http://search.cpan.org/~btrott/Digest-BubbleBabble-0.01/)
"""

vowels = "aeiouy"
consonants = "bcdfghklmnprstvzx"


def bubblebabble(digest):
    """compute bubblebabble representation of digest.
    
    @param digest: raw string representation of digest (e.g. what md5.digest returns)
    @type digest: str

    @return: bubblebabble representation of digest
    @rtype: str
    """
    
    
    
    digest = [ord(x) for x in digest]
    
    dlen = len(digest)
    seed = 1
    rounds = 1+dlen/2
    retval = "x"
    for i in range(rounds):
	if i+1<rounds or dlen % 2:
	    idx0 = (((digest[2*i] >> 6) & 3) + seed) % 6
	    idx1 = (digest[2*i] >> 2) & 15;
            idx2 = ((digest[2*i] & 3) + seed / 6) % 6;
            retval += "%s%s%s" % (vowels[idx0], consonants[idx1], vowels[idx2])
	    if i+1 < rounds:
                idx3 = (digest[2 * i + 1] >> 4) & 15;
                idx4 = digest[2 * i + 1] & 15;
                retval += "%s-%s" % (consonants[idx3], consonants[idx4])
                seed = (seed * 5 + digest[2*i] * 7 +
                        digest[2*i+1]) % 36;
	else:
            idx0 = seed % 6;
            idx1 = 16;
            idx2 = seed / 6;
            retval += "%s%s%s" % (vowels[idx0], consonants[idx1], vowels[idx2])

    retval += "x"
    return retval

def hexstring2string(s):
    """convert hex representation of digest back to raw digest"""
    assert (len(s) % 2 == 0)
    if s.startswith("0x") or s.startswith("0X"):
	s = s[2:]
    return "".join([chr(eval("0x%s" % s[i:i+2])) for i in range(0, len(s), 2)])

def _test():
    tests = """432cc46b5c67c9adaabdcc6c69e23d6d xibod-sycik-rilak-lydap-tipur-tifyk-sipuv-dazok-tixox
5a1edbe07020525fd28cba1ea3b76694 xikic-vikyv-besed-begyh-zagim-sevic-vomer-lunon-gexex
1c453603cdc914c1f2eeb1abddae2e03 xelag-hatyb-fafes-nehys-cysyv-vasop-rylop-vorab-fuxux
df8ec33d78ae78280e10873f5e58d5ad xulom-vebyf-tevyp-vevid-mufic-bucef-zylyh-mehyp-tuxax
02b682a73739a9fb062370eaa8bcaec9 xebir-kybyp-latif-napoz-ricid-fusiv-popir-soras-nixyx"""
    # ...as computed by perl
    
    tests = [x.split()[:2] for x in tests.split("\n")]
    for digest, expected in tests:
	res=bubblebabble(hexstring2string(digest))
	print digest, res, ("failure", "ok")[expected==res]


if __name__=="__main__":
    _test()

Message digests in 'hexadecimal representation' are rather hard to read and compare for humans. bubblebabble representation is somewhat more readable. Therefore one might choose to show bubblebabble instead of hexadecimal representation to users. Openssh's ssh-keygen also uses bubblebabble representation, when called with '-B'. The above implementation is based on the equivalent perl one (which isn't very different from the OpenSSH one).

3 comments

Ian Bicking 19 years, 7 months ago  # | flag

base64. What is the advantage of this over base64? For instance:

>>> src = hexstring2string("432cc46b5c67c9adaabdcc6c69e23d6d")
>>> src.encode('base64').replace('\n', '')
'QyzEa1xnya2qvcxsaeI9bQ=='

Base64 strings can contain \n's, which is inconvenient in many contexts, but the decoding process ignores their presence so they can simply be removed.

In hexstring2string, it is faster to turn a hex pair into a character with chr(int(s[i:i+2], 16)). My benchmarks show it makes that function almost 10x as fast with that change. Use of eval is usually a bad sign -- there's almost always a better (faster, safer) way to do it.

Ralf Schmitt (author) 19 years, 7 months ago  # | flag

It's really only useful, when presenting digests to humans. bubblebabble looks like a series of words (of a strange language). base64 is even worse as one now has to differntiate between 1 and l, 0 and O.... hexstring2string can also be replaced by binascii.unhexlify.

a 13 years, 8 months ago  # | flag

eval("0x%s" % s[i:i+2]) should be changed to int(s[i:i+2], 16). eval() is dangerous and unnecessary here.

Created by Ralf Schmitt on Tue, 10 Aug 2004 (PSF)
Python recipes (4591)
Ralf Schmitt's recipes (1)

Forks

Required Modules

  • (none specified)

Other Information and Tasks