Blob


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>
14 extern char* getpassm(char*);
16 enum{ CHK = 16, BUF = 4096 };
18 uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
19 Biobuf bin;
20 Biobuf bout;
22 void
23 safewrite(uchar *buf, int n)
24 {
25 int i = Bwrite(&bout, buf, n);
27 if(i == n)
28 return;
29 fprint(2, "write error\n");
30 exits("write error");
31 }
33 void
34 saferead(uchar *buf, int n)
35 {
36 int i = Bread(&bin, buf, n);
38 if(i == n)
39 return;
40 fprint(2, "read error\n");
41 exits("read error");
42 }
44 uchar *copy;
45 int ncopy;
47 void
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 }
59 int
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;
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);
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);
104 if(n <= 0){
105 fprint(2,"no key\n");
106 exits("key");
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 */
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");
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 */
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");
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 */
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");
157 safewrite(copy, ncopy);
159 exits("");
160 return 1; /* gcc */