xref: /plan9/sys/src/cmd/auth/secstore/aescbc.c (revision eed6406f36d695b1749e6b99b0ebfb624403dfc7)
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