forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package randomart
2
3/*
4 * Draw an ASCII-Art representing the fingerprint so human brain can
5 * profit from its built-in pattern recognition ability.
6 * This technique is called "random art" and can be found in some
7 * scientific publications like this original paper:
8 *
9 * "Hash Visualization: a New Technique to improve Real-World Security",
10 * Perrig A. and Song D., 1999, International Workshop on Cryptographic
11 * Techniques and E-Commerce (CrypTEC '99)
12 * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
13 *
14 * The subject came up in a talk by Dan Kaminsky, too.
15 *
16 * If you see the picture is different, the key is different.
17 * If the picture looks the same, you still know nothing.
18 *
19 * The algorithm used here is a worm crawling over a discrete plane,
20 * leaving a trace (augmenting the field) everywhere it goes.
21 * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
22 * makes the respective movement vector be ignored for this turn.
23 * Graphs are not unambiguous, because circles in graphs can be
24 * walked in either direction.
25 */
26
27import (
28 "os"
29)
30
31func MAX(a, b int) int {
32 if a > b {
33 return a
34 }
35 return b
36}
37
38func MIN(a, b int) int {
39 if a < b {
40 return a
41 }
42 return b
43}
44
45/*
46 * Field sizes for the random art. Have to be odd, so the starting point
47 * can be in the exact middle of the picture, and FLDBASE should be >=8 .
48 * Else pictures would be too dense, and drawing the frame would
49 * fail, too, because the key type would not fit in anymore.
50 */
51const (
52 FLDBASE = 8
53 FLDSIZE_Y = (FLDBASE + 1)
54 FLDSIZE_X = (FLDBASE*2 + 1)
55)
56
57func FromString(str string) string {
58 ch := make(chan byte)
59
60 go func() {
61 defer close(ch)
62 for _, v := range []byte(str) {
63 ch <- v
64 }
65 }()
66 return key_fingerprint_randomart(ch)
67}
68
69func FromFile(file *os.File) string {
70 ch := make(chan byte)
71
72 go func() {
73 defer close(ch)
74 // TODO make input a 1 element byte array
75 input := make([]byte, 1)
76 nread, err := file.Read(input)
77 for err == nil && nread > 0 {
78 ch <- input[0]
79 nread, err = file.Read(input)
80 }
81 }()
82 return key_fingerprint_randomart(ch)
83}
84
85func key_fingerprint_randomart(ch chan byte) string {
86 /*
87 * Chars to be used after each other every time the worm
88 * intersects with itself. Matter of taste.
89 */
90 augment_string := " .o+=*BOX@%&#/^SE"
91 var field [FLDSIZE_X][FLDSIZE_Y]byte
92 len_aug := len(augment_string) - 1
93 var retval [(FLDSIZE_X + 3) * (FLDSIZE_Y + 2)]byte
94
95 /* initialize field */
96 x := FLDSIZE_X / 2
97 y := FLDSIZE_Y / 2
98
99 /* process raw key */
100 for input, ok := <-ch; ok; input, ok = <-ch {
101 /* each byte conveys four 2-bit move commands */
102 for b := 0; b < 4; b++ {
103 /* evaluate 2 bit, rest is shifted later */
104 if input&0x1 > 0 {
105 x += 1
106 } else {
107 x += -1
108 }
109
110 if input&0x2 > 0 {
111 y++
112 } else {
113 y--
114 }
115
116 /* assure we are still in bounds */
117 x = MAX(x, 0)
118 y = MAX(y, 0)
119 x = MIN(x, FLDSIZE_X-1)
120 y = MIN(y, FLDSIZE_Y-1)
121
122 /* augment the field */
123 if int(field[x][y]) < len_aug-2 {
124 field[x][y]++
125 }
126 input = input >> 2
127 }
128 }
129
130 /* mark starting point and end point*/
131 field[FLDSIZE_X/2][FLDSIZE_Y/2] = byte(len_aug - 1)
132 field[x][y] = byte(len_aug)
133
134 i := 0
135 retval[i] = '+'
136 i++
137
138 /* output upper border */
139 for x := 0; x < FLDSIZE_X; x++ {
140 retval[i] = '-'
141 i++
142 }
143 retval[i] = '+'
144 i++
145 retval[i] = '\n'
146 i++
147
148 /* output content */
149 for y := 0; y < FLDSIZE_Y; y++ {
150 retval[i] = '|'
151 i++
152 for x := 0; x < FLDSIZE_X; x++ {
153 retval[i] = augment_string[MIN(int(field[x][y]), len_aug)]
154 i++
155 }
156 retval[i] = '|'
157 i++
158 retval[i] = '\n'
159 i++
160 }
161
162 /* output lower border */
163 retval[i] = '+'
164 i++
165 for j := 0; j < FLDSIZE_X; j++ {
166 retval[i] = '-'
167 i++
168 }
169 retval[i] = '+'
170 i++
171
172 return string(retval[0:i])
173}