drunken_bishop.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Drunken bishop randomart algorithm
4  *
5  * Copyright (c) 2015-2020 by the developers. See the LICENSE file for details.
6  *
7  * A description and analysis of this algorithm can be found here:
8  * <br>
9  * http://dirk-loss.de/sshvis/drunken_bishop.pdf
10  *
11  * If nothing else is specified, function return zero to indicate success
12  * and a negative value to indicate an error.
13  */
14 
15 
16 /* ========================================================================== */
17 /* Include headers */
18 
19 #include "posix.h" /* Include this first because of feature test macros */
20 
21 #include <string.h>
22 
23 #include "digest.h"
24 #include "encoding.h"
25 #include "main.h"
26 
27 
28 /* ========================================================================== */
29 /*! \addtogroup DIGEST */
30 /*! @{ */
31 
32 
33 /* ========================================================================== */
34 /* Constants */
35 
36 /* Message prefix for DIGEST module */
37 #define MAIN_ERR_PREFIX "DIGEST: "
38 
39 
40 /* ========================================================================== */
41 /* Create and print randomart image using "drunken bishop" algorithm
42  *
43  * Every 2 bits of data are translated to a move on the field. The bits are
44  * mapped to the moves in pairs with most significant byte first and least
45  * significant bit pair (of every byte) first. Example:
46  *
47  * Data fc : 94 : b0 : ... : b7
48  * Bits 11 11 11 00 : 10 01 01 00 : 10 11 00 00 : ... : 10 11 01 11
49  * | | | | | | | | | | | | | | | |
50  * Move 4 3 2 1 8 7 6 5 12 11 10 9 ... 64 63 62 61
51  *
52  * The field is initialized with SP (whitespace) and every time the bishop moves
53  * to a field its value is incremented. The value of a field is printed using
54  * the following characters:
55  *
56  * 1: .
57  * 2: o
58  * 3: +
59  * 4: =
60  * 5: *
61  * 6: B
62  * 7: O
63  * 8: X
64  * 9: @
65  * 10: %
66  * 11: &
67  * 12: #
68  * 13: /
69  * 14: ^
70  *
71  * Exceptions: The start field is marked with 'S' and the end field with 'E'.
72  */
73 
74 static void drunken_bishop(const char* prefix,
75  const unsigned char* data, size_t data_len)
76 {
77  const char trace[] = " .o+=*BOX@%&#/^SE";
78  const unsigned int trace_start = 15U;
79  const unsigned int trace_end = 16U;
80  unsigned int field[DIGEST_RA_X][DIGEST_RA_Y];
81  size_t x = DIGEST_RA_X / (size_t) 2;
82  size_t y = DIGEST_RA_Y / (size_t) 2;
83  size_t x_lim = DIGEST_RA_X - (size_t) 1;
84  size_t y_lim = DIGEST_RA_Y - (size_t) 1;
85  size_t i;
86  unsigned int ii;
87  unsigned int move[4];
88 
89  /* Initialize field */
90  for(i = 0; i < DIGEST_RA_Y; ++i)
91  {
92  for(ii = 0; (size_t) ii < DIGEST_RA_X; ++ii) { field[ii][i] = 0; }
93  }
94  field[x][y] = trace_start;
95 
96  /* Split data into 2bit groups */
97  for(i = 0; i < data_len; ++i)
98  {
99  for(ii = 0; ii < 4; ++ii)
100  {
101  /* Extract direction */
102  move[ii] = ((unsigned int) data[i] & (3U << ii * 2U)) >> ii * 2U;
103 
104  /* Move on field */
105  switch(move[ii])
106  {
107  case 0U:
108  {
109  if(x) { --x; }
110  if(y) { --y; }
111  break;
112  }
113  case 1U:
114  {
115  if(x_lim > x) { ++x; }
116  if(y) { --y; }
117  break;
118  }
119  case 2U:
120  {
121  if(x) { --x; }
122  if(y_lim > y) { ++y; }
123  break;
124  }
125  case 3U:
126  {
127  if(x_lim > x) { ++x; }
128  if(y_lim > y) { ++y; }
129  break;
130  }
131  default:
132  {
133  PRINT_ERROR("Bishop was too drunk (bug)");
134  break;
135  }
136  }
137 
138  /* Update field content */
139  if(14U > field[x][y]) { field[x][y] += 1U; }
140  }
141  }
142  field[x][y] = trace_end;
143 
144  /* Print top line */
145  printf("%s+", prefix);
146  for(x = 0; x < DIGEST_RA_X; ++x) { printf("-"); }
147  printf("+\n");
148  /* Print field */
149  for(y = 0; y < DIGEST_RA_Y; ++y)
150  {
151  printf("%s|", prefix);
152  for(x = 0; x < DIGEST_RA_X; ++x) { printf("%c", trace[field[x][y]]); }
153  printf("|\n");
154  }
155  /* Print bottom line */
156  printf("%s+", prefix);
157  for(x = 0; x < DIGEST_RA_X; ++x) { printf("-"); }
158  printf("+\n");
159 
160  return;
161 }
162 
163 
164 /* ========================================================================== */
165 /*! \brief Create randomart image of a key
166  *
167  * \param[in] prefix Prefix to prepend for each output line
168  * \param[in] buf Pointer to data buffer
169  * \param[in] len Length of data in buffer
170  *
171  * The data from \e buf is hashed with the SHA2-256 algorithm to create a
172  * fingerprint. The first 16 bytes of this fingerprint are used to create a
173  * randomart image with the drunken bishop algorithm.
174  *
175  * \return
176  * - 0 on success
177  * - Negative value on error
178  */
179 
180 int digest_randomart(const char* prefix, const char* buf, size_t len)
181 {
182  int res = -1;
183  unsigned char md[DIGEST_SHA2_256_LEN];
184  const char* fingerprint = NULL;
185 
186  /* Calculate SHA2-256 hash of data */
187  res = digest_sha2_256(buf, len, md);
188  if(!res)
189  {
190  res = enc_mime_encode_base64(&fingerprint, (const char*) md,
192  if(!res)
193  {
194  printf("%sKey fingerprint is SHA256:%s\n", prefix, fingerprint);
195  /*
196  * Create randomart
197  *
198  * Use with 16 bytes of data (resulting in 64 moves of the bishop,
199  * matching a 17x9 field size).
200  */
201  drunken_bishop(prefix, md, 16);
202  }
203  }
204  enc_free((void*) fingerprint);
205 
206  /* Check for error */
207  if(res) { PRINT_ERROR("Creating randomart image failed"); }
208 
209  return(res);
210 }
211 
212 
213 /*! @} */
214 
215 /* EOF */
enc_free
void enc_free(void *p)
Free an object allocated by encoding module.
Definition: encoding.c:8868
DIGEST_RA_X
#define DIGEST_RA_X
Field width: 17 units.
Definition: digest.h:24
digest_randomart
int digest_randomart(const char *prefix, const char *buf, size_t len)
Create randomart image of a key.
Definition: drunken_bishop.c:180
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19
data
struct core_data data
Global data object (shared by all threads)
Definition: core.c:242
DIGEST_SHA2_256_LEN
#define DIGEST_SHA2_256_LEN
256 bit
Definition: digest.h:19
enc_mime_encode_base64
int enc_mime_encode_base64(const char **enc, const char *data, size_t len)
Encode binary data to base64.
Definition: encoding.c:4744
digest_sha2_256
int digest_sha2_256(const char *text, size_t text_len, unsigned char *md)
Secure Hash Algorithm SHA2-256.
Definition: digest.c:182
DIGEST_RA_Y
#define DIGEST_RA_Y
Field height: 9 units.
Definition: digest.h:25

Generated at 2024-04-27 using  doxygen