[Pgp-tools-commit] r610 - in trunk: . keyart keyart/doc
Aaron Toponce
atoponce-guest at moszumanska.debian.org
Tue May 13 19:36:20 UTC 2014
Author: atoponce-guest
Date: 2014-05-13 19:36:20 +0000 (Tue, 13 May 2014)
New Revision: 610
Added:
trunk/keyart/
trunk/keyart/LICENSE
trunk/keyart/README
trunk/keyart/TODO
trunk/keyart/doc/
trunk/keyart/doc/druken-bishop.txt
trunk/keyart/keyart
Log:
Initial commit.
* Migration from https://github.com/atoponce/scripts/blob/master/art.py
* Move documentation out of script into docs/drunken-bishop.txt
* Change to 2-clause BSD license
* Add logic and try/except for catching errors.
* Create TODO and README.
Added: trunk/keyart/LICENSE
===================================================================
--- trunk/keyart/LICENSE (rev 0)
+++ trunk/keyart/LICENSE 2014-05-13 19:36:20 UTC (rev 610)
@@ -0,0 +1,22 @@
+Copyright (c) 2014, Aaron Toponce <aaron.toponce at gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Added: trunk/keyart/README
===================================================================
--- trunk/keyart/README (rev 0)
+++ trunk/keyart/README 2014-05-13 19:36:20 UTC (rev 610)
@@ -0,0 +1,32 @@
+OpenPGP Random Art
+------------------
+
+keyart takes a single exported public key file as an argument, and prints
+out its random visualization ASCII art based on the public key fingerprint.
+Please see 'docs/README' for more information about the algorithm and
+changes compared to OpenSSH keys.
+
+Usage
+-----
+
+The exported public key file can be in binary or ASCII armor format. To
+export the desired key:
+
+ $ gpg --output /tmp/0x808606060F.pgp --export 0x8086060F
+
+Then to produce the random art for that key:
+
+ $ keyart /tmp/0x8086060F.pgp
+ +----[DSA 1024]-----+
+ |l^ . ^^?^. |
+ |l. . .l:.? |
+ |^ E ...ll |
+ |^. . ^:. |
+ |^ . . .. |
+ | . . . S |
+ | . . . . |
+ | . . |
+ | |
+ | |
+ | |
+ +----[8086060F]-----+
Added: trunk/keyart/TODO
===================================================================
--- trunk/keyart/TODO (rev 0)
+++ trunk/keyart/TODO 2014-05-13 19:36:20 UTC (rev 610)
@@ -0,0 +1,9 @@
+TODO
+----
+
+* Replace the python-gnupg module with subprocess.
+* Add support for providing multiple exported keys.
+* Add support for providing a 40-character OpenPGP fingerprint string.
+* Add support for keyrings.
+* Add ability to ceate an HTML/PDF document for keysigning parties.
+* Create documentation on analysis of art collisions, similar to OpenSSH.
Added: trunk/keyart/doc/druken-bishop.txt
===================================================================
--- trunk/keyart/doc/druken-bishop.txt (rev 0)
+++ trunk/keyart/doc/druken-bishop.txt 2014-05-13 19:36:20 UTC (rev 610)
@@ -0,0 +1,180 @@
+Reimplement the "Drunken Bishop" walk as implemented by OpenSSH. We use a
+larger field size for GnuPG due to SHA1 fingerprint sizes (11x19).
+
+See http://www.dirk-loss.de/sshvis/drunken_bishop.pdf for the algorithm
+and security analysis for OpenSSH.
+
+The field is as defined:
+
+ 111111111
+ 0123456789012345678
+ +-------------------+x (column)
+ 0| |
+ 1| |
+ 2| |
+ 3| |
+ 4| |
+ 5| S |
+ 6| |
+ 7| |
+ 8| |
+ 9| |
+10| |
+ +-------------------+
+ y
+(row)
+
+Each position on the board can be represented by its cartesian
+coordinates (x,y). We can assign each positition a numerical value by
+using the equation:
+
+ pos = x + 19y
+
+Each position on the board contains an ASCII character the represents the
+frequency of visits by the bishop. A blank position has not been visited.
+The more the bishop has visited a square, the heavier or more dense the
+ASCII character should be. From light -> dark, the following scale should
+be used:
+
+ " .'`^",:;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
+
+See the table below (note, this does not necessarily follow OpenSSH):
+
++-+-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--++--+--+
+|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18||19|20|
++-+-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--++--+--+
+| |.|^|:|l|i|?|{|f|x|X |Z |# |M |W |& |8 |% |@ ||S |E |
++-+-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--++--+--+
+
+'S' and 'E' are special characters that represent the starting and ending
+location of the bishop respectively. 'S' always starts at coordinates
+(9,5), which is position 104, the center of the board.
+
+Movement is defined by taking the fingerprint, and coverting each
+character to its binary value. For exmaple, the fingerprint:
+
+ E041 3539 273A 6534 A3E1 9259 22EE E048 8086 060F
+
+has the binary values of:
+
+ 1110000001000001 0011010100111001 0010011100101010 0110010100110100
+ 1010001111100001 1001001001011001 0010001011101110 1110000001001000
+ 1000000010000110 0000011000001111
+
+In OpenSSH, the movement is found using bit-pairs at a time, left to
+right, least significant bit to most sifginifant bit. So:
+
+ +-----+-----++-----+-----++-----++-----+-----++-----+-----+
+Fingerprint: | E | 0 || 4 | 1 || ... || 0 | 6 || 0 | F |
+ +--+--+--+--++--+--+--+--++-----++--+--+--+--++--+--+--+--+
+ Bit-pair: |11|10|00|00||01|00|00|01|| ... ||00|00|01|10||00|00|11|11|
+ +--+--+--+--++--+--+--+--++-----++--+--+--+--++--+--+--+--+
+ Step: |4 |3 |2 |1 ||8 |7 |6 |5 || ... ||76|75|74|73||80|79|78|77|
+ +--+--+--+--++--+--+--+--++-----++--+--+--+--++--+--+--+--+
+
+For this GnuPG implementation, rather than following OpenSSH and read the
+bits with little endian, I've decided to read the bits in big endian
+(left to right the full way). This greatly simplifies the code, and I
+don't see any advantage to reading the bits with little endian, as the
+SHA1 output should be random anyway.
+
+The direction of our drunken bishop follows standard Chess rules for the
+bishop piece, moving only on the diagnal across the beard, which is
+defined as follows:
+
+ +------+-----+
+ | Pair | Dir |
+ +------+-----+ N
+ | 00 | NW | ^
+ +------+-----+ |
+ | 01 | NE | W <--+--> E
+ +------+-----+ |
+ | 10 | SW | v
+ +------+-----+ S
+ | 11 | SE |
+ +------+-----+
+
+The bishop starts in the center of the board at position 104. So, each
+possible move would place him on the following positions on the board,
+after the first move:
+
+ +------+-----+------+
+ | Pair | Pos | Diff |
+ +------+-----+------+
+ | 00 | 84 | -20 |
+ +------+-----+------+
+ | 01 | 86 | -18 |
+ +------+-----+------+
+ | 10 | 122 | +18 |
+ +------+-----+------+
+ | 11 | 124 | +20 |
+ +------+-----+------+
+
+We must cleanly handle how the bishop behaves when he reaches the edge of
+the board, or a corner. We'll define the types of positions as follows:
+
+ +-------------------+
+ |aTTTTTTTTTTTTTTTTTb|
+ |LMMMMMMMMMMMMMMMMMR| a = NW corner
+ |LMMMMMMMMMMMMMMMMMR| b = NE corner
+ |LMMMMMMMMMMMMMMMMMR| c = SW corner
+ |LMMMMMMMMMMMMMMMMMR| d = SE corner
+ |LMMMMMMMMMMMMMMMMMR| T = Top edge
+ |LMMMMMMMMMMMMMMMMMR| B = Bottom edge
+ |LMMMMMMMMMMMMMMMMMR| R = Right edge
+ |LMMMMMMMMMMMMMMMMMR| L = Left edge
+ |LMMMMMMMMMMMMMMMMMR| M = Middle pos.
+ |cBBBBBBBBBBBBBBBBBd|
+ +-------------------+
+
+When a bishop finds himself in one of these positions, we'll define his
+adjusted movement, if necessary, as follows:
+
+ +-----+------+---------+----------+--------+
+ | Pos | Bits | Heading | Adjusted | Offset |
+ +-----+------+---------+----------+--------+
+ | a | 00 | NW | no move | 0 |
+ | | 01 | NE | E | +1 |
+ | | 10 | SW | S | +19 |
+ | | 11 | SE | SE | +20 |
+ +-----+------+---------+----------+--------+
+ | b | 00 | NW | W | -1 |
+ | | 01 | NE | no move | 0 |
+ | | 10 | SW | SW | +18 |
+ | | 11 | SE | S | +19 |
+ +-----+------+---------+----------+--------+
+ | c | 00 | NW | N | -19 |
+ | | 01 | NE | NE | -18 |
+ | | 10 | SW | no move | 0 |
+ | | 11 | SE | E | +1 |
+ +-----+------+---------+----------+--------+
+ | d | 00 | NW | NW | -20 |
+ | | 01 | NE | N | -19 |
+ | | 10 | SW | W | -1 |
+ | | 11 | SE | no move | 0 |
+ +-----+------+---------+----------+--------+
+ | T | 00 | NW | W | -1 |
+ | | 01 | NE | E | +1 |
+ | | 10 | SW | SW | +18 |
+ | | 11 | SE | SE | +20 |
+ +-----+------+---------+----------+--------+
+ | B | 00 | NW | NW | -20 |
+ | | 01 | NE | NE | -18 |
+ | | 10 | SW | W | -1 |
+ | | 11 | SE | E | +1 |
+ +-----+------+---------+----------+--------+
+ | R | 00 | NW | NW | -20 |
+ | | 01 | NE | N | -19 |
+ | | 10 | SW | SW | +18 |
+ | | 11 | SE | S | +19 |
+ +-----+------+---------+----------+--------+
+ | L | 00 | NW | N | -19 |
+ | | 01 | NE | NE | -18 |
+ | | 10 | SW | S | +19 |
+ | | 11 | SE | SE | +20 |
+ +-----+------+---------+----------+--------+
+ | M | 00 | NW | NW | -20 |
+ | | 01 | NE | NE | -18 |
+ | | 10 | SW | SW | +18 |
+ | | 11 | SE | SE | +20 |
+ +-----+------+---------+----------+--------+
Added: trunk/keyart/keyart
===================================================================
--- trunk/keyart/keyart (rev 0)
+++ trunk/keyart/keyart 2014-05-13 19:36:20 UTC (rev 610)
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+
+# Currently the GnuPG python module is used. The search_keys() requires an
+# online connection. This is less than optimal, and slow. Eventually, it
+# will be replaced with subprocess, and fully offline.
+import gnupg
+import os
+import os.path
+import sys
+
+try:
+ keyfile = sys.argv[1]
+except IndexError:
+ print "Usage: keyart /path/to/exported-key"
+ sys.exit(1)
+
+if os.path.isfile(keyfile) and os.access(keyfile, os.R_OK):
+ with open(keyfile) as f:
+ key_data = f.read()
+elif not os.path.isfile(keyfile):
+ print "No such file or directory: {0}".format(keyfile)
+ sys.exit(2)
+else:
+ print "{0} is not readable. Check permissions.".format(keyfile)
+ sys.exit(3)
+
+gpg = gnupg.GPG(gnupghome='/tmp', keyring='/tmp/keyring.pgp')
+key = gpg.import_keys(key_data)
+fingerprint = key.fingerprints[0]
+
+# search_keys(query, keyserver='pgp.mit.edu')
+key_dict = gpg.search_keys(fingerprint[-16:])[0]
+key_size = key_dict['length']
+key_algo = key_dict['algo']
+
+coin = ''
+f_bytes = []
+pos = 104
+walk = [pos]
+visits = [0]*209
+coins = [' ','.','^',':','l','i','?','{','f','x','X','Z','#','M','W','&','8','%','@']
+
+zfill = str.zfill
+
+for c in fingerprint:
+ f_bytes.append(zfill(bin(int(c,16))[2:],4)[:2]) # last 2 bits
+ f_bytes.append(zfill(bin(int(c,16))[2:],4)[2:]) # first 2 bits
+
+# I break from the OpenSSH implementation here. Rather than reading the
+# bytes in little endian, the code is simpler reading in big endian. I
+# don't see the point in complicating the code for little endian reading,
+# when the fingerprint is SHA1 output, and should provide random output.
+for d in f_bytes:
+ if (20 <= pos <= 36 or 39 <= pos <= 55 or 58 <= pos <= 74 or
+ 77 <= pos <= 93 or 96 <= pos <= 112 or 115 <= pos <= 131 or
+ 134 <= pos <= 150 or 153 <= pos <= 169 or 172 <= pos <= 188):
+ if d == '00': pos -= 20 # Square 'M'
+ elif d == '01': pos -= 18
+ elif d == '10': pos += 18
+ else: pos += 20
+ elif 1 <= pos <= 17: # Square 'T'
+ if d == '00': pos -= 1
+ elif d == '01': pos += 1
+ elif d == '10': pos += 18
+ else: pos += 20
+ elif 191 <= pos <= 207: # Square 'B'
+ if d == '00': pos -= 20
+ elif d == '01': pos -= 18
+ elif d == '10': pos -= 1
+ else: pos += 1
+ elif pos in [19, 38, 57, 76, 95, 114, 133, 152, 171]: # Square 'L'
+ if d == '00': pos -= 19
+ elif d == '01': pos -= 18
+ elif d == '10': pos += 19
+ else: pos += 20
+ elif pos in [37, 56, 75, 94, 113, 132, 151, 170, 189]: # Square 'R'
+ if d == '00': pos -= 20
+ elif d == '01': pos -= 19
+ elif d == '10': pos += 18
+ else: pos += 19
+ elif pos == 0: # Square 'a'
+ if d == '01': pos += 1
+ elif d == '10': pos += 19
+ elif d == '11': pos += 20
+ elif pos == 18: # Square 'b'
+ if d == '00': pos -= 1
+ elif d == '10': pos += 18
+ elif d == '11': pos += 19
+ elif pos == 190: # Square 'c'
+ if d == '00': pos -= 19
+ elif d == '01': pos -= 18
+ elif d == '11': pos += 1
+ else: # Square 'd'
+ if d == '00': pos -= 20
+ elif d == '01': pos -= 19
+ elif d == '10': pos -= 1
+ walk.append(pos)
+
+for w in walk:
+ visits[w] += 1
+ if visits[w] > 18: visits[w] = 18
+
+# See https://tools.ietf.org/html/rfc4880#section-9.1
+# Also https://tools.ietf.org/html/rfc6637#section4
+if key_algo == '17':
+ key_algo = 'DSA'
+elif key_algo == '1' or key_algo == '2' or key_algo == '3':
+ key_algo = 'RSA'
+elif key_algo == '16' or key_algo == '20':
+ key_algo = 'Elg'
+elif key_algo == '18':
+ key_algo = 'ECDH'
+elif key_algo == '19':
+ key_algo = 'ECDSA'
+elif key_algo == '21':
+ key_algo = 'X9.42'
+else: key_algo = 'N/A'
+
+if len("["+key_algo+" "+key_size+"]") == 10:
+ print '+----[{0} {1}]-----+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 11:
+ print '+----[{0} {1}]----+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 9:
+ print '+-----[{0} {1}]-----+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 12:
+ print '+---[{0} {1}]----+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 13:
+ print '+---[{0} {1}]---+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 14:
+ print '+--[{0} {1}]---+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 15:
+ print '+--[{0} {1}]--+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 16:
+ print '+-[{0} {1}]--+'.format(key_algo, key_size)
+elif len("["+key_algo+" "+key_size+"]") == 17:
+ print '+-[{0} {1}]-+'.format(key_algo, key_size)
+else:
+ print '+-------------------+'
+
+for i, v in enumerate(visits):
+ coin += coins[v]
+ if i % 19 == 0:
+ coin = "|%s" % coin
+ if i == 104:
+ coin = "%sS" % coin[:10]
+ if i == walk[len(walk)-1]:
+ coin = "%sE" % coin[:len(coin)-1]
+ if i % 19 == 18:
+ print "%s|" % coin
+ coin = ''
+print '+----[{0}]-----+'.format(fingerprint[-8:])
Property changes on: trunk/keyart/keyart
___________________________________________________________________
Added: svn:executable
+ *
More information about the Pgp-tools-commit
mailing list