1 /*
2 encrypt file by writing
3 	v2hdr,
4 	16byte initialization vector,
5 	AES-CBC(key, random | file),
6 HMAC_SHA1(md5(key), AES-CBC(random | file))
7 */
8 #include <u.h>
9 #include <libc.h>
10 #include <bio.h>
11 #include <mp.h>
12 #include <libsec.h>
13 
14 extern char* getpassm(char*);
15 
16 enum{ CHK = 16, BUF = 4096 };
17 
18 uchar v2hdr[AESbsize+1] = "AES CBC SHA1  2\n";
19 Biobuf bin;
20 Biobuf bout;
21 
22 void
safewrite(uchar * buf,int n)23 safewrite(uchar *buf, int n)
24 {
25 	int i = Bwrite(&bout, buf, n);
26 
27 	if(i == n)
28 		return;
29 	fprint(2, "write error\n");
30 	exits("write error");
31 }
32 
33 void
saferead(uchar * buf,int n)34 saferead(uchar *buf, int n)
35 {
36 	int i = Bread(&bin, buf, n);
37 
38 	if(i == n)
39 		return;
40 	fprint(2, "read error\n");
41 	exits("read error");
42 }
43 
44 uchar *copy;
45 int ncopy;
46 
47 void
safecopy(uchar * buf,int n)48 safecopy(uchar *buf, int n)
49 {
50 	copy = realloc(copy, ncopy+n);
51 	if(copy == nil) {
52 		fprint(2, "out of memory\n");
53 		exits("memory");
54 	}
55 	memmove(copy+ncopy, buf, n);
56 	ncopy += n;
57 }
58 
59 int
main(int argc,char ** argv)60 main(int argc, char **argv)
61 {
62 	int encrypt = 0;  /* 0=decrypt, 1=encrypt */
63 	int n, nkey, pass_stdin = 0;
64 	char *pass;
65 	uchar key[AESmaxkey], key2[SHA1dlen];
66 	uchar buf[BUF+SHA1dlen];    /* assumption: CHK <= SHA1dlen */
67 	AESstate aes;
68 	DigestState *dstate;
69 
70 	ARGBEGIN{
71 	case 'e':
72 		encrypt = 1;
73 		break;
74 	case 'i':
75 		pass_stdin = 1;
76 		break;
77 	}ARGEND;
78 	if(argc!=0){
79 		fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0);
80 		fprint(2,"   or: %s -e < clear.txt > cipher.aes\n", argv0);
81 		exits("usage");
82 	}
83 	Binit(&bin, 0, OREAD);
84 	Binit(&bout, 1, OWRITE);
85 
86 	if(pass_stdin){
87 		n = readn(3, buf, (sizeof buf)-1);
88 		if(n < 1)
89 			exits("usage: echo password |[3=1] auth/aescbc -i ...");
90 		buf[n] = 0;
91 		while(buf[n-1] == '\n')
92 			buf[--n] = 0;
93 	}else{
94 		pass = readcons("aescbc password", nil, 1);
95 		if(pass == nil)
96 			exits("readcons");
97 		n = strlen(pass);
98 		if(n >= BUF)
99 			exits("key too long");
100 		strcpy((char*)buf, pass);
101 		memset(pass, 0, n);
102 		free(pass);
103 	}
104 	if(n <= 0){
105 		fprint(2,"no key\n");
106 		exits("key");
107 	}
108 	dstate = sha1((uchar*)"aescbc file", 11, nil, nil);
109 	sha1(buf, n, key2, dstate);
110 	memcpy(key, key2, 16);
111 	nkey = 16;
112 	md5(key, nkey, key2, 0);  /* so even if HMAC_SHA1 is broken, encryption key is protected */
113 
114 	if(encrypt){
115 		safewrite(v2hdr, AESbsize);
116 		genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
117 		setupAESstate(&aes, key, nkey, buf);  /* use first AESbsize bytes as IV */
118 		aesCBCencrypt(buf+AESbsize, AESbsize, &aes);  /* use second AESbsize bytes as initial plaintext */
119 		safewrite(buf, 2*AESbsize);
120 		dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
121 		for(;;){
122 			n = Bread(&bin, buf, BUF);
123 			if(n < 0){
124 				fprint(2,"read error\n");
125 				exits("read error");
126 			}
127 			aesCBCencrypt(buf, n, &aes);
128 			safewrite(buf, n);
129 			dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
130 			if(n < BUF)
131 				break; /* EOF */
132 		}
133 		hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
134 		safewrite(buf, SHA1dlen);
135 	}else{ /* decrypt */
136 		saferead(buf, AESbsize);
137 		if(memcmp(buf, v2hdr, AESbsize) != 0){
138 			fprint(2, "not an aescbc file\n");
139 			exits("aescbc file");
140 		}
141 		saferead(buf, 2*AESbsize);  /* read IV and random initial plaintext */
142 		setupAESstate(&aes, key, nkey, buf);
143 		dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
144 		aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
145 		saferead(buf, SHA1dlen);
146 		while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
147 			dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
148 			aesCBCdecrypt(buf, n, &aes);
149 			safecopy(buf, n);
150 			memmove(buf, buf+n, SHA1dlen);  /* these bytes are not yet decrypted */
151 		}
152 		hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
153 		if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0){
154 			fprint(2,"decrypted file failed to authenticate\n");
155 			exits("decrypted file failed to authenticate");
156 		}
157 		safewrite(copy, ncopy);
158 	}
159 	exits("");
160 	return 1;	/* gcc */
161 }
162