Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* 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
*/
7
#include <u.h>
8
#include <libc.h>
9
#include <bio.h>
10
#include <mp.h>
11
#include <libsec.h>
12
#include <authsrv.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
	if(Bwrite(&bout, buf, n) != n)
26
		sysfatal("write error");
27
}
28
 
29
void
30
saferead(uchar *buf, int n)
31
{
32
	if(Bread(&bin, buf, n) != n)
33
		sysfatal("read error");
34
}
35
 
36
int
37
main(int argc, char **argv)
38
{
39
	int encrypt = 0;  /* 0=decrypt, 1=encrypt */
40
	int n, nkey, pass_stdin = 0, pass_nvram = 0;
41
	char *pass;
42
	uchar key[AESmaxkey], key2[SHA1dlen];
43
	uchar buf[BUF+SHA1dlen];    /* assumption: CHK <= SHA1dlen */
44
	AESstate aes;
45
	DigestState *dstate;
46
	Nvrsafe nvr;
47
 
48
	ARGBEGIN{
49
	case 'e':
50
		encrypt = 1;
51
		break;
52
	case 'i':
53
		pass_stdin = 1;
54
		break;
55
	case 'n':
56
		pass_nvram = 1;
57
		break;
58
	}ARGEND;
59
	if(argc!=0){
60
		fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0);
61
		fprint(2,"   or: %s -e < clear.txt > cipher.aes\n", argv0);
62
		exits("usage");
63
	}
64
	Binit(&bin, 0, OREAD);
65
	Binit(&bout, 1, OWRITE);
66
 
67
	if(pass_stdin){
68
		n = readn(3, buf, (sizeof buf)-1);
69
		if(n < 1)
70
			exits("usage: echo password |[3=1] auth/aescbc -i ...");
71
		buf[n] = 0;
72
		while(buf[n-1] == '\n')
73
			buf[--n] = 0;
74
	}else if(pass_nvram){
75
		if(readnvram(&nvr, 0) < 0)
76
			exits("readnvram: %r");
77
		strecpy((char*)buf, (char*)buf+sizeof buf, (char*)nvr.config);
78
		n = strlen((char*)buf);
79
	}else{
80
		pass = getpassm("aescbc key:");
81
		n = strlen(pass);
82
		if(n >= BUF)
83
			exits("key too long");
84
		strcpy((char*)buf, pass);
85
		memset(pass, 0, n);
86
		free(pass);
87
	}
88
	if(n <= 0)
89
		sysfatal("no key");
90
	dstate = sha1((uchar*)"aescbc file", 11, nil, nil);
91
	sha1(buf, n, key2, dstate);
92
	memcpy(key, key2, 16);
93
	nkey = 16;
94
	md5(key, nkey, key2, 0);  /* so even if HMAC_SHA1 is broken, encryption key is protected */
95
 
96
	if(encrypt){
97
		safewrite(v2hdr, AESbsize);
98
		genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
99
		setupAESstate(&aes, key, nkey, buf);  /* use first AESbsize bytes as IV */
100
		aesCBCencrypt(buf+AESbsize, AESbsize, &aes);  /* use second AESbsize bytes as initial plaintext */
101
		safewrite(buf, 2*AESbsize);
102
		dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
103
		for(;;){
104
			n = Bread(&bin, buf, BUF);
105
			if(n < 0)
106
				sysfatal("read error");
107
			aesCBCencrypt(buf, n, &aes);
108
			safewrite(buf, n);
109
			dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
110
			if(n < BUF)
111
				break; /* EOF */
112
		}
113
		hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
114
		safewrite(buf, SHA1dlen);
115
	}else{ /* decrypt */
116
		saferead(buf, AESbsize);
117
		if(memcmp(buf, v2hdr, AESbsize) == 0){
118
			saferead(buf, 2*AESbsize);  /* read IV and random initial plaintext */
119
			setupAESstate(&aes, key, nkey, buf);
120
			dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
121
			aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
122
			saferead(buf, SHA1dlen);
123
			while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
124
				dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
125
				aesCBCdecrypt(buf, n, &aes);
126
				safewrite(buf, n);
127
				memmove(buf, buf+n, SHA1dlen);  /* these bytes are not yet decrypted */
128
			}
129
			hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
130
			if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0)
131
				sysfatal("decrypted file failed to authenticate");
132
		}else{ /* compatibility with past mistake */
133
			// if file was encrypted with bad aescbc use this:
134
			//         memset(key, 0, AESmaxkey);
135
			//    else assume we're decrypting secstore files
136
			setupAESstate(&aes, key, AESbsize, buf);
137
			saferead(buf, CHK);
138
			aesCBCdecrypt(buf, CHK, &aes);
139
			while((n = Bread(&bin, buf+CHK, BUF)) > 0){
140
				aesCBCdecrypt(buf+CHK, n, &aes);
141
				safewrite(buf, n);
142
				memmove(buf, buf+n, CHK);
143
			}
144
			if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0)
145
				sysfatal("decrypted file failed to authenticate");
146
		}
147
	}
148
	exits("");
149
	return 1;  /* keep  other compilers happy */
150
}