fareqr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * Copyright (c) 2021 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "fareqr.h"
  21. int fareqr_lookup_decode(char *seedfn, char *fareqr_s, char *dst_cred) {
  22. int i, n, r, _ret = 0;;
  23. char *p=NULL, *stop_tok=NULL;
  24. char *enc_str = NULL, *dec_str = NULL, *plain_str=NULL,
  25. *pub_key = NULL, *priv_key = NULL;
  26. if ((!seedfn) || (!fareqr_s) || (!dst_cred)) { return -1; }
  27. if (fareqr_s[0] != '@') { return -2; }
  28. stop_tok = strchr(fareqr_s, '%');
  29. if (!stop_tok) { return -3; }
  30. pub_key = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  31. priv_key = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  32. enc_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  33. dec_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  34. plain_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  35. pub_key[0] = priv_key[0] = enc_str[0] = dec_str[0] = plain_str[0] = '\0';
  36. for (i=0, p = (fareqr_s+1); (i<(LINE_BUFFER_SIZE-1)) && (p<stop_tok) && (*p); p++, i++) {
  37. pub_key[i] = *p;
  38. }
  39. pub_key[i] = '\0';
  40. for (n=0, p = (stop_tok+1); (n<(LINE_BUFFER_SIZE-1)) && (*p) && ((*p) != '$'); p++, n++) {
  41. enc_str[n] = *p;
  42. }
  43. enc_str[n] = '\0';
  44. r = fareqr_lookup_seed_secret(seedfn, pub_key, priv_key);
  45. if (r<0) { _ret = r; }
  46. else {
  47. r = fareqr_decode(fareqr_s, pub_key, priv_key, dst_cred);
  48. if (r<0) { _ret = r; }
  49. }
  50. if (pub_key) { free(pub_key); }
  51. if (priv_key) { free(priv_key); }
  52. if (enc_str) { free(enc_str); }
  53. if (dec_str) { free(dec_str); }
  54. if (plain_str) { free(plain_str); }
  55. return _ret;
  56. }
  57. int fareqr_encode(char *tok_public, char *tok_secret, char *tok_cred, char *fareqr_str) {
  58. int i, r;
  59. uint8_t x,y,z;
  60. uint8_t *src_data = NULL, *dst_data = NULL;
  61. int src_data_n = 0;
  62. //int dst_data_n = 0;
  63. src_data = (uint8_t *)malloc(sizeof(uint8_t)*LINE_BUFFER_SIZE);
  64. dst_data = (uint8_t *)malloc(sizeof(uint8_t)*LINE_BUFFER_SIZE);
  65. for (i=0; tok_cred[i]; i++) {
  66. x = (uint8_t)tok_secret[i];
  67. y = (uint8_t)tok_cred[i];
  68. z = x^y;
  69. src_data[i] = z;
  70. src_data_n++;
  71. }
  72. for (i=0; i<src_data_n; i++) {
  73. x = (uint8_t)tok_secret[i];
  74. }
  75. //dst_data_n = Base64encode_len(src_data_n);
  76. r = Base64encode((char *)dst_data, (const char *)src_data, src_data_n);
  77. if (r<=0) {
  78. free(src_data);
  79. free(dst_data);
  80. return -1;
  81. }
  82. if (fareqr_str) {
  83. snprintf(fareqr_str, LINE_BUFFER_SIZE-1, "@%s%%%s$", tok_public, dst_data);
  84. }
  85. free(src_data);
  86. free(dst_data);
  87. return 0;
  88. }
  89. int fareqr_decode(char *fareqr_s, char *check_pub, char *tok_secret, char *dst_cred) {
  90. int i, n, _ret=0;
  91. char *p, *stop_tok;
  92. int pub_tok_read_len = 0, check_pub_len = 0;
  93. char *enc_str = NULL, *dec_str = NULL, *plain_str=NULL;
  94. uint8_t x,y,z;
  95. if (fareqr_s[0] != '@') { return -1; }
  96. stop_tok = strchr(fareqr_s, '%');
  97. if (!stop_tok) { return -2; }
  98. if (!tok_secret) { return -3; }
  99. if (check_pub) {
  100. check_pub_len = strlen(check_pub);
  101. for ( p = (fareqr_s+1); p < stop_tok; p++) {
  102. if (pub_tok_read_len >= check_pub_len) { return -3; }
  103. if ( (*p) != check_pub[pub_tok_read_len] ) { return -4; }
  104. pub_tok_read_len++;
  105. }
  106. }
  107. enc_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  108. dec_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  109. plain_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  110. for (n=0, p = (stop_tok+1); (*p) && ((*p) != '$'); p++, n++) {
  111. enc_str[n] = *p;
  112. }
  113. enc_str[n] = '\0';
  114. Base64decode(dec_str, enc_str);
  115. for (i=0; dec_str[i]; i++) {
  116. if (tok_secret[i]==0) {
  117. _ret = -5;
  118. goto _fareqr_decode_cleanup;
  119. }
  120. x = (uint8_t)dec_str[i];
  121. y = (uint8_t)tok_secret[i];
  122. z = (x^y);
  123. plain_str[i] = (char)z;
  124. }
  125. plain_str[i]='\0';
  126. if (dst_cred) {
  127. for (i=0; plain_str[i]; i++) {
  128. dst_cred[i] = plain_str[i];
  129. }
  130. dst_cred[i] = '\0';
  131. }
  132. _fareqr_decode_cleanup:
  133. if (enc_str) { free(enc_str); }
  134. if (dec_str) { free(dec_str); }
  135. if (plain_str) { free(plain_str); }
  136. return _ret;
  137. }
  138. // return negative on error or not found
  139. // 0 on success (found)
  140. //
  141. int fareqr_lookup_seed_secret(char *seedfn, char *pub, char *priv) {
  142. int i;
  143. FILE *fp;
  144. char buf[LINE_BUFFER_SIZE] = {0};
  145. int pos = 0, ch=0, line_no=0;
  146. char *tok0_ptr=NULL,
  147. *tok1_ptr=NULL;
  148. fp = fopen(seedfn, "r");
  149. if (!fp) { perror(seedfn); return -2;}
  150. while (!feof(fp)) {
  151. ch = fgetc(fp);
  152. // process line if we reach a newline or eof
  153. //
  154. if (feof(fp) || (ch == '\n')) {
  155. // if the line is empty or a comment, skip
  156. //
  157. if ((pos==0) || (buf[0] == '#')) {
  158. }
  159. // get tokens out of line, using ' ' as the
  160. // delimeter
  161. //
  162. else {
  163. tok0_ptr = buf;
  164. tok1_ptr = strchr(buf, ' ');
  165. if (tok1_ptr) {
  166. *tok1_ptr = '\0';
  167. tok1_ptr++;
  168. // Cechk it against our supplied 'pulbic' key
  169. //
  170. if (strcmp(pub, tok0_ptr)==0) {
  171. // If we've found it, copy it over to the `priv`
  172. // above and return
  173. //
  174. for (i=0; tok1_ptr[i]; i++) {
  175. priv[i] = tok1_ptr[i];
  176. }
  177. priv[i]='\0';
  178. return 0;
  179. }
  180. }
  181. line_no++;
  182. }
  183. pos=0;
  184. buf[0]='\0';
  185. continue;
  186. }
  187. buf[pos] = ch;
  188. pos++;
  189. buf[pos] = '\0';
  190. }
  191. fclose(fp);
  192. return -1;
  193. }
  194. // to compile:
  195. // gcc -D__FAREQR_MAIN__ fareqr.c b64.c -o fareqr
  196. //
  197. #ifdef __FAREQR_MAIN__
  198. void show_help(FILE *ofp) {
  199. fprintf(ofp, "\nusage:\n\n");
  200. fprintf(ofp, " fareqr encode <pubkey> <privatekey> <str>\n");
  201. fprintf(ofp, " fareqr decode <privatekey> <encstr>\n");
  202. fprintf(ofp, " fareqr dbdecode <qrseedfile> <fareqr>\n");
  203. fprintf(ofp, " fareqr help\n");
  204. fprintf(ofp, "\n");
  205. fprintf(ofp, "fareqr is a program to help with encoding and decoding 'fareqr' strings.\n");
  206. fprintf(ofp, "\n");
  207. fprintf(ofp, "A fareqr string is of the form:\n");
  208. fprintf(ofp, "\n");
  209. fprintf(ofp, " @<pubkey>%%<b64(xor(privkey,credential))>$\n");
  210. fprintf(ofp, "\n");
  211. fprintf(ofp, "Where `<b64(xor(privkey,credential))>` is the base64 encoded XOR of the private key\n");
  212. fprintf(ofp, "and the credential to be presented. The reasoning behind the XOR is to not allow a\n");
  213. fprintf(ofp, "snooper to get credential information if exposed to the string and the base64\n");
  214. fprintf(ofp, "encoding is to make it easily transportable.\n");
  215. fprintf(ofp, "\n");
  216. fprintf(ofp, "The <qrseedfile> is a text file of <pubkey> <privkey> pairs.\n");
  217. fprintf(ofp, "\n");
  218. fprintf(ofp, "Here is some example usage:\n");
  219. fprintf(ofp, "\n");
  220. fprintf(ofp, " $ fareqr encode 'wu9XouSh' 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' ';123456789060535?'\n");
  221. fprintf(ofp, " @wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=\n");
  222. fprintf(ofp, " $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
  223. fprintf(ofp, " ;123456789060535?\n");
  224. fprintf(ofp, " $ echo 'wu9XouSh ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' > ./qr.seed\n");
  225. fprintf(ofp, " $ fareqr dbdecode ./qr.seed '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
  226. fprintf(ofp, " ;123456789060535?\n");
  227. fprintf(ofp, "\n");
  228. fprintf(ofp, "Where 'wu9XouSh' is the public key, 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' is the private key and\n");
  229. fprintf(ofp, "';123456789060535?' is the credential information to be encoded.\n");
  230. fprintf(ofp, "\n");
  231. fprintf(ofp, "\n");
  232. fflush(ofp);
  233. }
  234. /*
  235. *
  236. * quick test/start:
  237. *
  238. * $ fareqr encode 'wu9XouSh' 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' ';123456789060535?'
  239. * @wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=
  240. *
  241. * $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'
  242. * ;123456789060535?
  243. *
  244. * $ fareqr dbdecode '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'
  245. * ;123456789060535?
  246. *
  247. */
  248. int main(int argc, char **argv) {
  249. int i, r;
  250. char *tok_public = NULL,
  251. *tok_secret = NULL,
  252. *tok_cred = NULL,
  253. *fareqr_str = NULL;
  254. uint8_t x,y,z;
  255. uint8_t *src_data = NULL, *dst_data = NULL;
  256. int src_data_n = 0, dst_data_n = 0;
  257. char *fn = NULL;
  258. if (argc <= 1) {
  259. show_help(stderr);
  260. exit(1);
  261. }
  262. if (strcmp(argv[1], "encode")==0) {
  263. if (argc>2) {
  264. tok_public = strdup(argv[2]);
  265. if (argc>3) {
  266. tok_secret = strdup(argv[3]);
  267. if (argc>4) {
  268. tok_cred = strdup(argv[4]);
  269. }
  270. }
  271. }
  272. if ((!tok_public) || (!tok_secret) || (!tok_cred)) {
  273. show_help(stderr);
  274. if (tok_public) { free(tok_public); }
  275. if (tok_secret) { free(tok_secret); }
  276. if (tok_cred) { free(tok_cred); }
  277. exit(2);
  278. }
  279. fareqr_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  280. r = fareqr_encode(tok_public, tok_secret, tok_cred, fareqr_str);
  281. if (r==0) {
  282. printf("%s\n", fareqr_str);
  283. }
  284. }
  285. else if (strcmp(argv[1], "decode")==0) {
  286. if (argc>2) {
  287. tok_secret = strdup(argv[2]);
  288. if (argc>3) {
  289. fareqr_str = strdup(argv[3]);
  290. }
  291. }
  292. tok_cred = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  293. tok_cred[0] = '0';
  294. r = fareqr_decode(fareqr_str, tok_public, tok_secret, tok_cred);
  295. if (r<0) {
  296. fprintf(stderr, "error, failed to decode qr fare string (%i)\n", r);
  297. }
  298. else {
  299. printf("%s\n", tok_cred);
  300. }
  301. }
  302. else if (strcmp(argv[1], "dbdecode")==0) {
  303. if (argc>2) {
  304. fn = strdup(argv[2]);
  305. if (argc>3) {
  306. fareqr_str = strdup(argv[3]);
  307. }
  308. }
  309. tok_cred = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  310. tok_cred[0] = '0';
  311. r = fareqr_lookup_decode(fn, fareqr_str, tok_cred);
  312. if (r<0) {
  313. fprintf(stderr, "could not decode '%s' with db '%s', exiting (got %i)\n",
  314. fareqr_str, fn, r);
  315. }
  316. else {
  317. printf("%s\n", tok_cred);
  318. }
  319. }
  320. else if (strcmp(argv[1], "help")==0) {
  321. show_help(stdout);
  322. exit(0);
  323. }
  324. else {
  325. fprintf(stderr, "unknown operation '%s'\n", argv[1]);
  326. show_help(stderr);
  327. exit(3);
  328. }
  329. if (tok_public) { free(tok_public); }
  330. if (tok_secret) { free(tok_secret); }
  331. if (tok_cred) { free(tok_cred); }
  332. if (fareqr_str) { free(fareqr_str); }
  333. if (src_data) { free(src_data); }
  334. if (dst_data) { free(dst_data); }
  335. if (fn) { free(fn); }
  336. }
  337. #endif