wowana.me

website source; use git clone git://wowana.me/wowana.me.git to clone this repository.


fp.c (3315B)


      1 /*
      2 8a89605> add fp.c -- fingerprint colourisation tool
      3     on 2020-11-24T04:26:01+00:00 by opal hart<opal@wowana.me>
      4 used to generate coloured fingerprints on
      5 <https://wowana.me/pages/omemo.xht>, uses openkeychain / dino algorithm
      6 so people can easily compare fingerprints manually
      7 */
      8 
      9 #include <errno.h>
     10 #include <stdbool.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <openssl/sha.h>
     15 
     16 struct colour {
     17 	unsigned char r;
     18 	unsigned char g;
     19 	unsigned char b;
     20 };
     21 
     22 int main (int, char**);
     23 static usage (const char*, int);
     24 static html_format_fp (const char*);
     25 bool take_four (char*, const char*);
     26 static from_hex (const char*);
     27 struct colour get_colour (int);
     28 unsigned char uchar_min (unsigned char, unsigned char);
     29 
     30 int main (int argc, char** argv)
     31 {
     32 	if (argc < 2)
     33 		return usage(argv[0], 1);
     34 	int ret;
     35 	while (--argc && !( ret = html_format_fp(argv[1]) ))
     36 		++argv;
     37 	if (!ret)
     38 		puts("");
     39 	return ret;
     40 }
     41 
     42 usage (const char* arg0, int exit)
     43 {
     44 	fputs("Usage: ", stdout);
     45 	fputs(arg0, stdout);
     46 	puts(" <fingerprint>");
     47 	return exit;
     48 }
     49 
     50 html_format_fp (const char* fp)
     51 {
     52 	const char* ptr = fp;
     53 	bool insert_space = false;
     54 	while (*ptr) {
     55 		char buf[5];
     56 		if (!take_four(buf, ptr))
     57 			return 1;
     58 		int val = from_hex(buf);
     59 		if (val < 0)
     60 			return 1;
     61 		struct colour c = get_colour(val);
     62 		fputs("<span style='color:#", stdout);
     63 		printf("%02x%02x%02x", c.r, c.g, c.b);
     64 		fputs("'>", stdout);
     65 		fputs(buf, stdout);
     66 		fputs("</span>", stdout);
     67 		if (insert_space)
     68 			fputs(" ", stdout);
     69 		insert_space = !insert_space;
     70 		ptr += 4;
     71 	}
     72 	return 0;
     73 }
     74 
     75 bool take_four (char* buf, const char* str)
     76 {
     77 	if (strlen(str) < 4) {
     78 		fputs("string length of value `", stderr);
     79 		fputs(str, stderr);
     80 		fputs("' is not divisible by four\n", stderr);
     81 		return false;
     82 	}
     83 	strncpy(buf, str, 4);
     84 	return true;
     85 }
     86 
     87 /* expects 'str' in range of 0x0000 ~ 0xFFFF.
     88  * returns negative value on error
     89  */
     90 from_hex (const char* str)
     91 {
     92 	errno = 0;
     93 	long val = strtol(str, NULL, 16);
     94 	if (errno) {
     95 		perror("in from_hex(): strtol");
     96 		return -1;
     97 	}
     98 	else if (val > 0xFFFF) {
     99 		fputs("BUG: value `", stderr);
    100 		fputs(str, stderr);
    101 		fputs("' is greater than 0xFFFF\n", stderr);
    102 		return -1;
    103 	}
    104 	else if (val < 0x0000) {
    105 		fputs("BUG: value `", stderr);
    106 		fputs(str, stderr);
    107 		fputs("' is negative\n", stderr);
    108 		return -1;
    109 	}
    110 	else return (int) val;
    111 }
    112 
    113 /* algorithm stolen from Dino, in turn stolen from OpenKeyChain */
    114 struct colour get_colour (int val)
    115 {
    116 	unsigned char bytes[2] = {
    117 		(unsigned char) ((val >> 8) & 0xff - 128),
    118 		(unsigned char) (val & 0xff - 128),
    119 	};
    120 	unsigned char* hash = SHA1(bytes, sizeof bytes, NULL);
    121 	struct colour c = {
    122 		.r = hash[0],
    123 		.g = hash[1],
    124 		.b = hash[2],
    125 	};
    126 	if (0 == (c.r | c.g | c.b))
    127 		c.r = c.g = c.b = 1;
    128 	double brightness =
    129 	 (.2126 * c.r) +
    130 	 (.7152 * c.g) +
    131 	 (.0722 * c.b);
    132 	if (brightness < 80.) {
    133 		double factor = 80. / brightness;
    134 #define brighten(which) which = uchar_min(255, (unsigned char) (which * factor))
    135 		brighten(c.r);
    136 		brighten(c.g);
    137 		brighten(c.b);
    138 #undef brighten
    139 	}
    140 	else if (brightness > 180) {
    141 		double factor = 180. / brightness;
    142 #define darken(which) which = (unsigned char) (which * factor)
    143 		darken(c.r);
    144 		darken(c.g);
    145 		darken(c.b);
    146 #undef darken
    147 	}
    148 	return c;
    149 }
    150 
    151 unsigned char uchar_min (unsigned char a, unsigned char b)
    152 {
    153 	return (a<b)? a : b;
    154 }