plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

aescbc.c (3778B)


      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>
     13 
     14 extern char* getpassm(char*);
     15 
     16 enum{ CHK = 16, BUF = 4096 };
     17 
     18 uchar v2hdr[AESbsize+1] = "AES CBC SHA1  2\n";
     19 Biobuf bin;
     20 Biobuf bout;
     21 
     22 void
     23 safewrite(uchar *buf, int n)
     24 {
     25 	int i = Bwrite(&bout, buf, n);
     26 
     27 	if(i == n)
     28 		return;
     29 	fprint(2, "write error\n");
     30 	exits("write error");
     31 }
     32 
     33 void
     34 saferead(uchar *buf, int n)
     35 {
     36 	int i = Bread(&bin, buf, n);
     37 
     38 	if(i == n)
     39 		return;
     40 	fprint(2, "read error\n");
     41 	exits("read error");
     42 }
     43 
     44 uchar *copy;
     45 int ncopy;
     46 
     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 }
     58 
     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;
     69 
     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);
     85 
     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);
    103 	}
    104 	if(n <= 0){
    105 		fprint(2,"no key\n");
    106 		exits("key");
    107 	}
    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 */
    113 
    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");
    126 			}
    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 */
    132 		}
    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");
    140 		}
    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 */
    151 		}
    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");
    156 		}
    157 		safewrite(copy, ncopy);
    158 	}
    159 	exits("");
    160 	return 1;	/* gcc */
    161 }