Blob


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>
13 extern char* getpassm(char*);
15 enum{ CHK = 16, BUF = 4096 };
17 uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
18 Biobuf bin;
19 Biobuf bout;
21 void
22 safewrite(uchar *buf, int n)
23 {
24 int i = Bwrite(&bout, buf, n);
26 if(i == n)
27 return;
28 fprint(2, "write error\n");
29 exits("write error");
30 }
32 void
33 saferead(uchar *buf, int n)
34 {
35 int i = Bread(&bin, buf, n);
37 if(i == n)
38 return;
39 fprint(2, "read error\n");
40 exits("read error");
41 }
43 int
44 main(int argc, char **argv)
45 {
46 int encrypt = 0; /* 0=decrypt, 1=encrypt */
47 int n, nkey, pass_stdin = 0;
48 char *pass;
49 uchar key[AESmaxkey], key2[SHA1dlen];
50 uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
51 AESstate aes;
52 DigestState *dstate;
54 ARGBEGIN{
55 case 'e':
56 encrypt = 1;
57 break;
58 case 'i':
59 pass_stdin = 1;
60 break;
61 }ARGEND;
62 if(argc!=0){
63 fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0);
64 fprint(2," or: %s -e < clear.txt > cipher.aes\n", argv0);
65 exits("usage");
66 }
67 Binit(&bin, 0, OREAD);
68 Binit(&bout, 1, OWRITE);
70 if(pass_stdin){
71 n = readn(3, buf, (sizeof buf)-1);
72 if(n < 1)
73 exits("usage: echo password |[3=1] auth/aescbc -i ...");
74 buf[n] = 0;
75 while(buf[n-1] == '\n')
76 buf[--n] = 0;
77 }else{
78 pass = getpassm("aescbc key:");
79 n = strlen(pass);
80 if(n >= BUF)
81 exits("key too long");
82 strcpy((char*)buf, pass);
83 memset(pass, 0, n);
84 free(pass);
85 }
86 if(n <= 0){
87 fprint(2,"no key\n");
88 exits("key");
89 }
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 */
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 while(1){
104 n = Bread(&bin, buf, BUF);
105 if(n < 0){
106 fprint(2,"read error\n");
107 exits("read error");
109 aesCBCencrypt(buf, n, &aes);
110 safewrite(buf, n);
111 dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
112 if(n < BUF)
113 break; /* EOF */
115 hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
116 safewrite(buf, SHA1dlen);
117 }else{ /* decrypt */
118 saferead(buf, AESbsize);
119 if(memcmp(buf, v2hdr, AESbsize) == 0){
120 saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */
121 setupAESstate(&aes, key, nkey, buf);
122 dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
123 aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
124 saferead(buf, SHA1dlen);
125 while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
126 dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
127 aesCBCdecrypt(buf, n, &aes);
128 safewrite(buf, n);
129 memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
131 hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
132 if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0){
133 fprint(2,"decrypted file failed to authenticate\n");
134 exits("decrypted file failed to authenticate");
136 }else{ /* compatibility with past mistake */
137 // if file was encrypted with bad aescbc use this:
138 // memset(key, 0, AESmaxkey);
139 // else assume we're decrypting secstore files
140 setupAESstate(&aes, key, AESbsize, buf);
141 saferead(buf, CHK);
142 aesCBCdecrypt(buf, CHK, &aes);
143 while((n = Bread(&bin, buf+CHK, BUF)) > 0){
144 aesCBCdecrypt(buf+CHK, n, &aes);
145 safewrite(buf, n);
146 memmove(buf, buf+n, CHK);
148 if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0){
149 fprint(2,"decrypted file failed to authenticate\n");
150 exits("decrypted file failed to authenticate");
154 exits("");
155 return 1; /* gcc */