13ff48bf5SDavid du Colombier /* encrypt file by writing
23ff48bf5SDavid du Colombier v2hdr,
33ff48bf5SDavid du Colombier 16byte initialization vector,
43ff48bf5SDavid du Colombier AES-CBC(key, random | file),
53ff48bf5SDavid du Colombier HMAC_SHA1(md5(key), AES-CBC(random | file))
63ff48bf5SDavid du Colombier */
79a747e4fSDavid du Colombier #include <u.h>
89a747e4fSDavid du Colombier #include <libc.h>
99a747e4fSDavid du Colombier #include <bio.h>
109a747e4fSDavid du Colombier #include <mp.h>
119a747e4fSDavid du Colombier #include <libsec.h>
125f6b17bbSDavid du Colombier #include <authsrv.h>
139a747e4fSDavid du Colombier
14c65b13b8SDavid du Colombier extern char* getpassm(char*);
15d9306527SDavid du Colombier
169a747e4fSDavid du Colombier enum{ CHK = 16, BUF = 4096 };
179a747e4fSDavid du Colombier
183ff48bf5SDavid du Colombier uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
199a747e4fSDavid du Colombier Biobuf bin;
209a747e4fSDavid du Colombier Biobuf bout;
219a747e4fSDavid du Colombier
229a747e4fSDavid du Colombier void
safewrite(uchar * buf,int n)239a747e4fSDavid du Colombier safewrite(uchar *buf, int n)
249a747e4fSDavid du Colombier {
25d854de59SDavid du Colombier if(Bwrite(&bout, buf, n) != n)
26d854de59SDavid du Colombier sysfatal("write error");
279a747e4fSDavid du Colombier }
289a747e4fSDavid du Colombier
299a747e4fSDavid du Colombier void
saferead(uchar * buf,int n)303ff48bf5SDavid du Colombier saferead(uchar *buf, int n)
313ff48bf5SDavid du Colombier {
32d854de59SDavid du Colombier if(Bread(&bin, buf, n) != n)
33d854de59SDavid du Colombier sysfatal("read error");
343ff48bf5SDavid du Colombier }
353ff48bf5SDavid du Colombier
36b27b55e2SDavid du Colombier int
main(int argc,char ** argv)379a747e4fSDavid du Colombier main(int argc, char **argv)
389a747e4fSDavid du Colombier {
399a747e4fSDavid du Colombier int encrypt = 0; /* 0=decrypt, 1=encrypt */
405f6b17bbSDavid du Colombier int n, nkey, pass_stdin = 0, pass_nvram = 0;
41b27b55e2SDavid du Colombier char *pass;
42d9306527SDavid du Colombier uchar key[AESmaxkey], key2[SHA1dlen];
433ff48bf5SDavid du Colombier uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
449a747e4fSDavid du Colombier AESstate aes;
453ff48bf5SDavid du Colombier DigestState *dstate;
465f6b17bbSDavid du Colombier Nvrsafe nvr;
479a747e4fSDavid du Colombier
48d9306527SDavid du Colombier ARGBEGIN{
49d9306527SDavid du Colombier case 'e':
50d9306527SDavid du Colombier encrypt = 1;
51d9306527SDavid du Colombier break;
52d9306527SDavid du Colombier case 'i':
53d9306527SDavid du Colombier pass_stdin = 1;
54d9306527SDavid du Colombier break;
555f6b17bbSDavid du Colombier case 'n':
565f6b17bbSDavid du Colombier pass_nvram = 1;
575f6b17bbSDavid du Colombier break;
58d9306527SDavid du Colombier }ARGEND;
59d9306527SDavid du Colombier if(argc!=0){
605f6b17bbSDavid du Colombier fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0);
615f6b17bbSDavid du Colombier fprint(2," or: %s -e < clear.txt > cipher.aes\n", argv0);
629a747e4fSDavid du Colombier exits("usage");
639a747e4fSDavid du Colombier }
649a747e4fSDavid du Colombier Binit(&bin, 0, OREAD);
659a747e4fSDavid du Colombier Binit(&bout, 1, OWRITE);
669a747e4fSDavid du Colombier
67d9306527SDavid du Colombier if(pass_stdin){
68d9306527SDavid du Colombier n = readn(3, buf, (sizeof buf)-1);
69d9306527SDavid du Colombier if(n < 1)
70d9306527SDavid du Colombier exits("usage: echo password |[3=1] auth/aescbc -i ...");
71d9306527SDavid du Colombier buf[n] = 0;
72d9306527SDavid du Colombier while(buf[n-1] == '\n')
73d9306527SDavid du Colombier buf[--n] = 0;
745f6b17bbSDavid du Colombier }else if(pass_nvram){
755f6b17bbSDavid du Colombier if(readnvram(&nvr, 0) < 0)
765f6b17bbSDavid du Colombier exits("readnvram: %r");
775f6b17bbSDavid du Colombier strecpy((char*)buf, (char*)buf+sizeof buf, (char*)nvr.config);
785f6b17bbSDavid du Colombier n = strlen((char*)buf);
79d9306527SDavid du Colombier }else{
80c65b13b8SDavid du Colombier pass = getpassm("aescbc key:");
81b27b55e2SDavid du Colombier n = strlen(pass);
82b27b55e2SDavid du Colombier if(n >= BUF)
83b27b55e2SDavid du Colombier exits("key too long");
84b27b55e2SDavid du Colombier strcpy((char*)buf, pass);
85b27b55e2SDavid du Colombier memset(pass, 0, n);
86b27b55e2SDavid du Colombier free(pass);
87d9306527SDavid du Colombier }
88d854de59SDavid du Colombier if(n <= 0)
89d854de59SDavid du Colombier sysfatal("no key");
90d9306527SDavid du Colombier dstate = sha1((uchar*)"aescbc file", 11, nil, nil);
91d9306527SDavid du Colombier sha1(buf, n, key2, dstate);
92d9306527SDavid du Colombier memcpy(key, key2, 16);
93d9306527SDavid du Colombier nkey = 16;
943ff48bf5SDavid du Colombier md5(key, nkey, key2, 0); /* so even if HMAC_SHA1 is broken, encryption key is protected */
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier if(encrypt){
973ff48bf5SDavid du Colombier safewrite(v2hdr, AESbsize);
983ff48bf5SDavid du Colombier genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
993ff48bf5SDavid du Colombier setupAESstate(&aes, key, nkey, buf); /* use first AESbsize bytes as IV */
1003ff48bf5SDavid du Colombier aesCBCencrypt(buf+AESbsize, AESbsize, &aes); /* use second AESbsize bytes as initial plaintext */
1013ff48bf5SDavid du Colombier safewrite(buf, 2*AESbsize);
1023ff48bf5SDavid du Colombier dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
103*eed6406fSDavid du Colombier for(;;){
1049a747e4fSDavid du Colombier n = Bread(&bin, buf, BUF);
105d854de59SDavid du Colombier if(n < 0)
106d854de59SDavid du Colombier sysfatal("read error");
1079a747e4fSDavid du Colombier aesCBCencrypt(buf, n, &aes);
1089a747e4fSDavid du Colombier safewrite(buf, n);
1093ff48bf5SDavid du Colombier dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
1103ff48bf5SDavid du Colombier if(n < BUF)
1113ff48bf5SDavid du Colombier break; /* EOF */
1129a747e4fSDavid du Colombier }
1133ff48bf5SDavid du Colombier hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
1143ff48bf5SDavid du Colombier safewrite(buf, SHA1dlen);
1153ff48bf5SDavid du Colombier }else{ /* decrypt */
116d9306527SDavid du Colombier saferead(buf, AESbsize);
1173ff48bf5SDavid du Colombier if(memcmp(buf, v2hdr, AESbsize) == 0){
1183ff48bf5SDavid du Colombier saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */
1199a747e4fSDavid du Colombier setupAESstate(&aes, key, nkey, buf);
1203ff48bf5SDavid du Colombier dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
1213ff48bf5SDavid du Colombier aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
1223ff48bf5SDavid du Colombier saferead(buf, SHA1dlen);
1233ff48bf5SDavid du Colombier while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
1243ff48bf5SDavid du Colombier dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
1259a747e4fSDavid du Colombier aesCBCdecrypt(buf, n, &aes);
1263ff48bf5SDavid du Colombier safewrite(buf, n);
1273ff48bf5SDavid du Colombier memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
1283ff48bf5SDavid du Colombier }
1293ff48bf5SDavid du Colombier hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
130d854de59SDavid du Colombier if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0)
131d854de59SDavid du Colombier sysfatal("decrypted file failed to authenticate");
1323ff48bf5SDavid du Colombier }else{ /* compatibility with past mistake */
1333ff48bf5SDavid du Colombier // if file was encrypted with bad aescbc use this:
1343ff48bf5SDavid du Colombier // memset(key, 0, AESmaxkey);
1353ff48bf5SDavid du Colombier // else assume we're decrypting secstore files
136d9306527SDavid du Colombier setupAESstate(&aes, key, AESbsize, buf);
1373ff48bf5SDavid du Colombier saferead(buf, CHK);
1383ff48bf5SDavid du Colombier aesCBCdecrypt(buf, CHK, &aes);
1399a747e4fSDavid du Colombier while((n = Bread(&bin, buf+CHK, BUF)) > 0){
1409a747e4fSDavid du Colombier aesCBCdecrypt(buf+CHK, n, &aes);
1419a747e4fSDavid du Colombier safewrite(buf, n);
1429a747e4fSDavid du Colombier memmove(buf, buf+n, CHK);
1439a747e4fSDavid du Colombier }
144d854de59SDavid du Colombier if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0)
145d854de59SDavid du Colombier sysfatal("decrypted file failed to authenticate");
1469a747e4fSDavid du Colombier }
1473ff48bf5SDavid du Colombier }
1489a747e4fSDavid du Colombier exits("");
149b27b55e2SDavid du Colombier return 1; /* keep other compilers happy */
1509a747e4fSDavid du Colombier }
151