1 /*
2 * Off-the-Record Messaging Toolkit
3 * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov
4 * <otr@cypherpunks.ca>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /* system headers */
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 /* libotr headers */
25 #include "proto.h"
26
27 /* toolkit headers */
28 #include "readotr.h"
29 #include "parse.h"
30 #include "sha1hmac.h"
31
usage(const char * progname)32 static void usage(const char *progname)
33 {
34 fprintf(stderr, "Usage: %s mackey old_text new_text offset\n"
35 "Read an OTR Data Message from stdin. Even if we can't read the\n"
36 "data because we don't know either the AES key or the DH privkey,\n"
37 "but we can make a good guess that the substring \"old_text\"\n"
38 "appears at the given offset in the message, replace the old_text\n"
39 "with the new_text (which must be of the same length), recalculate\n"
40 "the MAC with the given mackey, and output the resulting Data message.\n",
41 progname);
42 exit(1);
43 }
44
main(int argc,char ** argv)45 int main(int argc, char **argv)
46 {
47 unsigned char *mackey;
48 size_t mackeylen;
49 unsigned char macval[20];
50 char *otrmsg = NULL;
51 DataMsg datamsg;
52 size_t textlen;
53 unsigned int offset;
54 const unsigned char *old_text, *new_text;
55 char *newdatamsg;
56 size_t i;
57
58 if (argc != 5) {
59 usage(argv[0]);
60 }
61
62 argv_to_buf(&mackey, &mackeylen, argv[1]);
63 if (!mackey) {
64 usage(argv[0]);
65 }
66
67 if (mackeylen != 20) {
68 fprintf(stderr, "The MAC key must be 40 hex chars long.\n");
69 usage(argv[0]);
70 }
71
72 textlen = strlen(argv[2]);
73 if (textlen != strlen(argv[3])) {
74 fprintf(stderr, "The old_text and new_text must be of the same "
75 "length.\n");
76 usage(argv[0]);
77 }
78 old_text = (const unsigned char *)argv[2];
79 new_text = (const unsigned char *)argv[3];
80
81 if (sscanf(argv[4], "%u", &offset) != 1) {
82 fprintf(stderr, "Unparseable offset given.\n");
83 usage(argv[0]);
84 }
85
86 otrmsg = readotr(stdin);
87 if (otrmsg == NULL) {
88 fprintf(stderr, "No OTR Data Message found on stdin.\n");
89 exit(1);
90 }
91
92 if (otrl_proto_message_type(otrmsg) != OTRL_MSGTYPE_DATA) {
93 fprintf(stderr, "OTR Non-Data Message found on stdin.\n");
94 exit(1);
95 }
96
97 datamsg = parse_datamsg(otrmsg);
98 free(otrmsg);
99 if (datamsg == NULL) {
100 fprintf(stderr, "Invalid OTR Data Message found on stdin.\n");
101 exit(1);
102 }
103
104 /* Check the MAC */
105 sha1hmac(macval, mackey, datamsg->macstart,
106 datamsg->macend - datamsg->macstart);
107 if (memcmp(macval, datamsg->mac, 20)) {
108 fprintf(stderr, "MAC does not verify: wrong MAC key?\n");
109 exit(1);
110 }
111
112 /* Modify the ciphertext */
113 for(i=0; i<textlen && offset+i < datamsg->encmsglen; ++i) {
114 datamsg->encmsg[offset+i] ^= (old_text[i] ^ new_text[i]);
115 }
116
117 /* Recalculate the MAC */
118 newdatamsg = remac_datamsg(datamsg, mackey);
119 printf("%s\n", newdatamsg);
120 free(newdatamsg);
121
122 free_datamsg(datamsg);
123 free(mackey);
124 fflush(stdout);
125 return 0;
126 }
127