fareqr.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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_encode(char *tok_public, char *tok_secret, char *tok_cred, char *fareqr_str) {
  22. int i, r;
  23. uint8_t x,y,z;
  24. uint8_t *src_data = NULL, *dst_data = NULL;
  25. int src_data_n = 0, dst_data_n = 0;
  26. src_data = (uint8_t *)malloc(sizeof(uint8_t)*LINE_BUFFER_SIZE);
  27. dst_data = (uint8_t *)malloc(sizeof(uint8_t)*LINE_BUFFER_SIZE);
  28. for (i=0; tok_cred[i]; i++) {
  29. x = (uint8_t)tok_secret[i];
  30. y = (uint8_t)tok_cred[i];
  31. z = x^y;
  32. src_data[i] = z;
  33. src_data_n++;
  34. }
  35. for (i=0; i<src_data_n; i++) {
  36. x = (uint8_t)tok_secret[i];
  37. }
  38. dst_data_n = Base64encode_len(src_data_n);
  39. r = Base64encode((char *)dst_data, (const char *)src_data, src_data_n);
  40. if (fareqr_str) {
  41. snprintf(fareqr_str, LINE_BUFFER_SIZE-1, "@%s%%%s$\n", tok_public, dst_data);
  42. }
  43. free(src_data);
  44. free(dst_data);
  45. return 0;
  46. }
  47. int fareqr_decode(char *fareqr_s, char *check_pub, char *tok_secret, char *dst_cred) {
  48. int i, n;
  49. char *p, *stop_tok;
  50. int pub_tok_read_len = 0, check_pub_len = 0;
  51. char *enc_str = NULL, *dec_str = NULL, *plain_str=NULL;
  52. uint8_t x,y,z;
  53. if (fareqr_s[0] != '@') { return -1; }
  54. stop_tok = strchr(fareqr_s, '%');
  55. if (!stop_tok) { return -2; }
  56. if (!tok_secret) { return -3; }
  57. if (check_pub) {
  58. check_pub_len = strlen(check_pub);
  59. for ( p = (fareqr_s+1); p < stop_tok; p++) {
  60. if (pub_tok_read_len >= check_pub_len) { return -3; }
  61. if ( (*p) != check_pub[pub_tok_read_len] ) { return -4; }
  62. pub_tok_read_len++;
  63. }
  64. }
  65. enc_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  66. dec_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  67. plain_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  68. for (n=0, p = (stop_tok+1); (*p) && ((*p) != '$'); p++, n++) {
  69. enc_str[n] = *p;
  70. }
  71. enc_str[n] = '\0';
  72. Base64decode(dec_str, enc_str);
  73. for (i=0; dec_str[i]; i++) {
  74. if (tok_secret[i]==0) { return -5; }
  75. x = (uint8_t)dec_str[i];
  76. y = (uint8_t)tok_secret[i];
  77. z = (x^y);
  78. plain_str[i] = (char)z;
  79. }
  80. plain_str[i]='\0';
  81. printf("%s\n", plain_str);
  82. if (dst_cred) {
  83. for (i=0; dec_str[i]; i++) {
  84. dst_cred[i] = dec_str[i];
  85. }
  86. dst_cred[i] = '\0';
  87. }
  88. free(enc_str);
  89. free(dec_str);
  90. free(plain_str);
  91. return 0;
  92. }
  93. // return negative on error or not found
  94. // 0 on success (found)
  95. //
  96. int fareqr_lookup_seed_secret(char *seedfn, char *pub, char *priv) {
  97. int i;
  98. FILE *fp;
  99. char buf[LINE_BUFFER_SIZE] = {0};
  100. int pos = 0, ch=0, line_no=0, src_n;
  101. char *p = NULL;
  102. char *tok0_ptr=NULL,
  103. *tok1_ptr=NULL;
  104. uint8_t z;
  105. fp = fopen(seedfn, "r");
  106. if (!fp) { perror(seedfn); return -2;}
  107. while (!feof(fp)) {
  108. ch = fgetc(fp);
  109. // process line if we reach a newline or eof
  110. //
  111. if (feof(fp) || (ch == '\n')) {
  112. // if the line is empty or a comment, skip
  113. //
  114. if ((pos==0) || (buf[0] == '#')) {
  115. }
  116. // get tokens out of line, using ' ' as the
  117. // delimeter
  118. //
  119. else {
  120. tok0_ptr = buf;
  121. tok1_ptr = strchr(buf, ' ');
  122. if (tok1_ptr) {
  123. *tok1_ptr = '\0';
  124. tok1_ptr++;
  125. // Cechk it against our supplied 'pulbic' key
  126. //
  127. if (strcmp(pub, tok0_ptr)==0) {
  128. // If we've found it, copy it over to the `priv`
  129. // above and return
  130. //
  131. for (i=0; tok1_ptr[i]; i++) {
  132. priv[i] = tok1_ptr[i];
  133. }
  134. priv[i]='\0';
  135. return 0;
  136. }
  137. }
  138. line_no++;
  139. }
  140. pos=0;
  141. buf[0]='\0';
  142. continue;
  143. }
  144. buf[pos] = ch;
  145. pos++;
  146. buf[pos] = '\0';
  147. }
  148. fclose(fp);
  149. return -1;
  150. }
  151. // to compile:
  152. // gcc -D__FAREQR_MAIN__ fareqr.c b64.c -o fareqr
  153. //
  154. #ifdef __FAREQR_MAIN__
  155. void show_help(FILE *ofp) {
  156. fprintf(ofp, "\nusage:\n\n");
  157. fprintf(ofp, " fareqr encode <pubkey> <privatekey> <str>\n");
  158. fprintf(ofp, " fareqr decode <privatekey> <encstr>\n");
  159. fprintf(ofp, " fareqr dbdecode <qrseedfile> <pubkey> <encstr>\n");
  160. fprintf(ofp, " fareqr help\n");
  161. fprintf(ofp, "\n");
  162. fprintf(ofp, "fareqr is a program to help with encoding and decoding 'fareqr' strings.\n");
  163. fprintf(ofp, "\n");
  164. fprintf(ofp, "A fareqr string is of the form:\n");
  165. fprintf(ofp, "\n");
  166. fprintf(ofp, " @<pubkey>%%<b64(xor(privkey,credential))>$\n");
  167. fprintf(ofp, "\n");
  168. fprintf(ofp, "Where `<b64(xor(privkey,credential))>` is the base64 encoded XOR of the private key\n");
  169. fprintf(ofp, "and the credential to be presented. The reasoning behind the XOR is to not allow a\n");
  170. fprintf(ofp, "snooper to get credential information if exposed to the string and the base64\n");
  171. fprintf(ofp, "encoding is to make it easily transportable.\n");
  172. fprintf(ofp, "\n");
  173. fprintf(ofp, "The <qrseedfile> is a text file of <pubkey> <privkey> pairs.\n");
  174. fprintf(ofp, "\n");
  175. fprintf(ofp, "Here is some example usage:\n");
  176. fprintf(ofp, "\n");
  177. fprintf(ofp, " $ fareqr encode 'wu9XouSh' 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' ';123456789060535?'\n");
  178. fprintf(ofp, " @wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=\n");
  179. fprintf(ofp, " $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
  180. fprintf(ofp, " ;123456789060535?\n");
  181. fprintf(ofp, " $ echo 'wu9XouSh ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' > ./qr.seed\n");
  182. fprintf(ofp, " $ fareqr dbdecode ./qr.seed 'wu9XouSh' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'\n");
  183. fprintf(ofp, " ;123456789060535?\n");
  184. fprintf(ofp, "\n");
  185. fprintf(ofp, "Where 'wu9XouSh' is the public key, 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' is the private key and\n");
  186. fprintf(ofp, "';123456789060535?' is the credential information to be encoded.\n");
  187. fprintf(ofp, "\n");
  188. fprintf(ofp, "\n");
  189. fflush(ofp);
  190. }
  191. /*
  192. *
  193. * quick test/start:
  194. *
  195. * $ fareqr encode 'wu9XouSh' 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' ';123456789060535?'
  196. * @wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=
  197. *
  198. * $ fareqr decode 'ohNgizahkephain3aosoh2AeH1aethoo4cie6oiSaezimaighai2eiVaefahfien' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'
  199. * ;123456789060535?
  200. *
  201. * $ fareqr dbdecode 'wu9XouSh' '@wu9XouSh%VFl8VF1PV19TXEBeUVxdBl4=$'
  202. * ;123456789060535?
  203. *
  204. */
  205. int main(int argc, char **argv) {
  206. int i, r;
  207. char *tok_public = NULL,
  208. *tok_secret = NULL,
  209. *tok_cred = NULL,
  210. *fareqr_str = NULL;
  211. uint8_t x,y,z;
  212. uint8_t *src_data = NULL, *dst_data = NULL;
  213. int src_data_n = 0, dst_data_n = 0;
  214. char *fn = NULL;
  215. if (argc <= 1) {
  216. show_help(stderr);
  217. exit(1);
  218. }
  219. if (strcmp(argv[1], "encode")==0) {
  220. if (argc>2) {
  221. tok_public = strdup(argv[2]);
  222. if (argc>3) {
  223. tok_secret = strdup(argv[3]);
  224. if (argc>4) {
  225. tok_cred = strdup(argv[4]);
  226. }
  227. }
  228. }
  229. if ((!tok_public) || (!tok_secret) || (!tok_cred)) {
  230. show_help(stderr);
  231. if (tok_public) { free(tok_public); }
  232. if (tok_secret) { free(tok_secret); }
  233. if (tok_cred) { free(tok_cred); }
  234. exit(2);
  235. }
  236. fareqr_str = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  237. r = fareqr_encode(tok_public, tok_secret, tok_cred, fareqr_str);
  238. if (r==0) {
  239. printf("%s\n", fareqr_str);
  240. }
  241. }
  242. else if (strcmp(argv[1], "decode")==0) {
  243. if (argc>2) {
  244. tok_secret = strdup(argv[2]);
  245. if (argc>3) {
  246. fareqr_str = strdup(argv[3]);
  247. }
  248. }
  249. r = fareqr_decode(fareqr_str, tok_public, tok_secret, NULL);
  250. if (r<0) {
  251. fprintf(stderr, "error, failed to decode qr fare string (%i)\n", r);
  252. }
  253. }
  254. else if (strcmp(argv[1], "dbdecode")==0) {
  255. if (argc>2) {
  256. fn = strdup(argv[2]);
  257. if (argc>3) {
  258. tok_public = strdup(argv[3]);
  259. if (argc>4) {
  260. fareqr_str = strdup(argv[4]);
  261. }
  262. }
  263. }
  264. tok_secret = (char *)malloc(sizeof(char)*LINE_BUFFER_SIZE);
  265. tok_secret[0] = '\0';
  266. r = fareqr_lookup_seed_secret(fn, tok_public, tok_secret);
  267. if (r<0) {
  268. fprintf(stderr, "could not find '%s' in db '%s', exiting (got %i)\n",
  269. tok_public, fn, r);
  270. }
  271. else {
  272. r = fareqr_decode(fareqr_str, tok_public, tok_secret, NULL);
  273. if (r<0) {
  274. fprintf(stderr, "error, failed to decode qr fare string (%i)\n", r);
  275. }
  276. }
  277. }
  278. else if (strcmp(argv[1], "help")==0) {
  279. show_help(stdout);
  280. exit(0);
  281. }
  282. else {
  283. fprintf(stderr, "unknown operation '%s'\n", argv[1]);
  284. show_help(stderr);
  285. exit(3);
  286. }
  287. if (tok_public) { free(tok_public); }
  288. if (tok_secret) { free(tok_secret); }
  289. if (tok_cred) { free(tok_cred); }
  290. if (fareqr_str) { free(fareqr_str); }
  291. if (src_data) { free(src_data); }
  292. if (dst_data) { free(dst_data); }
  293. if (fn) { free(fn); }
  294. }
  295. #endif