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