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 "sesskeys.h"
31 #include "sha1hmac.h"
32 #include "ctrmode.h"
33 
usage(const char * progname)34 static void usage(const char *progname)
35 {
36     fprintf(stderr, "Usage: %s aeskey [new_message]\n"
37 "Read an OTR Data Message from stdin.  Use the given AES key to\n"
38 "verify its MAC and decrypt the message to stdout.  If new_message\n"
39 "is given, output a new OTR Data Message with the same fields as the\n"
40 "original, but with the message replaced by new_message\n", progname);
41     exit(1);
42 }
43 
main(int argc,char ** argv)44 int main(int argc, char **argv)
45 {
46     unsigned char *aeskey;
47     unsigned char mackey[20];
48     unsigned char macval[20];
49     size_t aeskeylen;
50     unsigned char *plaintext, *ciphertext;
51     char *otrmsg = NULL;
52     DataMsg datamsg;
53 
54     if (argc != 2 && argc != 3) {
55 	usage(argv[0]);
56     }
57 
58     argv_to_buf(&aeskey, &aeskeylen, argv[1]);
59     if (!aeskey) {
60 	usage(argv[0]);
61     }
62 
63     if (aeskeylen != 16) {
64 	fprintf(stderr, "The AES key must be 32 hex chars long.\n");
65 	usage(argv[0]);
66     }
67 
68     otrmsg = readotr(stdin);
69     if (otrmsg == NULL) {
70 	fprintf(stderr, "No OTR Data Message found on stdin.\n");
71 	exit(1);
72     }
73 
74     if (otrl_proto_message_type(otrmsg) != OTRL_MSGTYPE_DATA) {
75 	fprintf(stderr, "OTR Non-Data Message found on stdin.\n");
76 	exit(1);
77     }
78 
79     datamsg = parse_datamsg(otrmsg);
80     free(otrmsg);
81     if (datamsg == NULL) {
82 	fprintf(stderr, "Invalid OTR Data Message found on stdin.\n");
83 	exit(1);
84     }
85 
86     /* Create the MAC key */
87     sesskeys_make_mac(mackey, aeskey);
88 
89     /* Check the MAC */
90     sha1hmac(macval, mackey, datamsg->macstart,
91 	    datamsg->macend - datamsg->macstart);
92     if (memcmp(macval, datamsg->mac, 20)) {
93 	fprintf(stderr, "MAC does not verify: wrong AES key?\n");
94     } else {
95 	/* Decrypt the message */
96 	plaintext = malloc(datamsg->encmsglen+1);
97 	if (!plaintext) {
98 	    fprintf(stderr, "Out of memory!\n");
99 	    exit(1);
100 	}
101 	aes_ctr_crypt(plaintext, datamsg->encmsg, datamsg->encmsglen,
102 		aeskey, datamsg->ctr);
103 	plaintext[datamsg->encmsglen] = '\0';
104 	printf("Plaintext: ``%s''\n", plaintext);
105 	free(plaintext);
106     }
107 
108     /* Do we want to forge a message? */
109     if (argv[2] != NULL) {
110 	char *newdatamsg;
111 	size_t newlen = strlen(argv[2]);
112 	ciphertext = malloc(newlen);
113 	if (!ciphertext && newlen > 0) {
114 	    fprintf(stderr, "Out of memory!\n");
115 	    exit(1);
116 	}
117 	aes_ctr_crypt(ciphertext, (const unsigned char *)argv[2], newlen,
118 		aeskey, datamsg->ctr);
119 	free(datamsg->encmsg);
120 	datamsg->encmsg = ciphertext;
121 	datamsg->encmsglen = newlen;
122 
123 	newdatamsg = remac_datamsg(datamsg, mackey);
124 
125 	printf("%s\n", newdatamsg);
126 	free(newdatamsg);
127     }
128 
129     free_datamsg(datamsg);
130     free(aeskey);
131     fflush(stdout);
132     return 0;
133 }
134