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