blob: 9f4bfff9ab77dc41d75168f120da7a6066d8755b [file] [log] [blame]
wkj7d3bbe12004-04-21 01:21:40 +00001/* 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
7With CBC, if the first plaintext block is 0, the first ciphertext block is
8E(IV). Using the overflow technique adopted for compatibility with cryptolib
9makes the last cipertext block decryptable. Hence the random prefix to file.
10*/
11#include <u.h>
12#include <libc.h>
13#include <bio.h>
14#include <mp.h>
15#include <libsec.h>
16
17enum{ CHK = 16, BUF = 4096 };
18
19uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
20Biobuf bin;
21Biobuf bout;
22
23void
24safewrite(uchar *buf, int n)
25{
26 int i = Bwrite(&bout, buf, n);
27
28 if(i == n)
29 return;
30 fprint(2, "write error\n");
31 exits("write error");
32}
33
34void
35saferead(uchar *buf, int n)
36{
37 int i = Bread(&bin, buf, n);
38
39 if(i == n)
40 return;
41 fprint(2, "read error\n");
42 exits("read error");
43}
44
45int
46main(int argc, char **argv)
47{
48 int encrypt = 0; /* 0=decrypt, 1=encrypt */
49 int n, nkey;
50 char *hex, *msg = nil;
51 uchar key[AESmaxkey], key2[MD5dlen];
52 uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
53 AESstate aes;
54 DigestState *dstate;
55
56 if(argc!=2 || argv[1][0]!='-'){
57 fprint(2,"usage: HEX=key %s -d < cipher.aes > clear.txt\n", argv[0]);
58 fprint(2," or: HEX=key %s -e < clear.txt > cipher.aes\n", argv[0]);
59 exits("usage");
60 }
61 if(argv[1][1] == 'e')
62 encrypt = 1;
63 Binit(&bin, 0, OREAD);
64 Binit(&bout, 1, OWRITE);
65
66 if((hex = getenv("HEX")) == nil)
67 hex = getpass("enter key: ");
68 nkey = 0;
69 if(hex != nil)
70 nkey = strlen(hex);
71 if(nkey == 0 || (nkey&1) || nkey>2*AESmaxkey){
72 fprint(2,"key should be 32 hex digits\n");
73 exits("key");
74 }
75 nkey = dec16(key, sizeof key, hex, nkey);
76 md5(key, nkey, key2, 0); /* so even if HMAC_SHA1 is broken, encryption key is protected */
77
78 if(encrypt){
79 safewrite(v2hdr, AESbsize);
80 genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
81 setupAESstate(&aes, key, nkey, buf); /* use first AESbsize bytes as IV */
82 aesCBCencrypt(buf+AESbsize, AESbsize, &aes); /* use second AESbsize bytes as initial plaintext */
83 safewrite(buf, 2*AESbsize);
84 dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
85 while(1){
86 n = Bread(&bin, buf, BUF);
87 if(n < 0){
88 msg = "read error";
89 goto Exit;
90 }
91 aesCBCencrypt(buf, n, &aes);
92 safewrite(buf, n);
93 dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
94 if(n < BUF)
95 break; /* EOF */
96 }
97 hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
98 safewrite(buf, SHA1dlen);
99 }else{ /* decrypt */
100 Bread(&bin, buf, AESbsize);
101 if(memcmp(buf, v2hdr, AESbsize) == 0){
102 saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */
103 setupAESstate(&aes, key, nkey, buf);
104 dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
105 aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
106 saferead(buf, SHA1dlen);
107 while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
108 dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
109 aesCBCdecrypt(buf, n, &aes);
110 safewrite(buf, n);
111 memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
112 }
113 hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
114 if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0){
115 msg = "decrypted file failed to authenticate!";
116 goto Exit;
117 }
118 }else{ /* compatibility with past mistake */
119 // if file was encrypted with bad aescbc use this:
120 // memset(key, 0, AESmaxkey);
121 // else assume we're decrypting secstore files
122 setupAESstate(&aes, key, 0, buf);
123 saferead(buf, CHK);
124 aesCBCdecrypt(buf, CHK, &aes);
125 while((n = Bread(&bin, buf+CHK, BUF)) > 0){
126 aesCBCdecrypt(buf+CHK, n, &aes);
127 safewrite(buf, n);
128 memmove(buf, buf+n, CHK);
129 }
130 if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0){
131 msg = "decrypted file failed to authenticate";
132 goto Exit;
133 }
134 }
135 }
136 Exit:
137 memset(key, 0, sizeof(key));
138 memset(key2, 0, sizeof(key2));
139 memset(buf, 0, sizeof(buf));
140 if(msg != nil)
141 fprint(2, "%s\n", msg);
142 exits(msg);
143 return 1; /* gcc */
144}