1 /* encrypt file by writing
3 16byte initialization vector,
4 AES-CBC(key, random | file),
5 HMAC_SHA1(md5(key), AES-CBC(random | file))
7 With CBC, if the first plaintext block is 0, the first ciphertext block is
8 E(IV). Using the overflow technique adopted for compatibility with cryptolib
9 makes the last cipertext block decryptable. Hence the random prefix to file.
17 enum{ CHK = 16, BUF = 4096 };
19 uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
24 safewrite(uchar *buf, int n)
26 int i = Bwrite(&bout, buf, n);
30 fprint(2, "write error\n");
35 saferead(uchar *buf, int n)
37 int i = Bread(&bin, buf, n);
41 fprint(2, "read error\n");
46 main(int argc, char **argv)
48 int encrypt = 0; /* 0=decrypt, 1=encrypt */
50 char *hex, *msg = nil;
51 uchar key[AESmaxkey], key2[MD5dlen];
52 uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
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]);
63 Binit(&bin, 0, OREAD);
64 Binit(&bout, 1, OWRITE);
66 if((hex = getenv("HEX")) == nil)
67 hex = getpass("enter key: ");
71 if(nkey == 0 || (nkey&1) || nkey>2*AESmaxkey){
72 fprint(2,"key should be 32 hex digits\n");
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 */
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);
86 n = Bread(&bin, buf, BUF);
91 aesCBCencrypt(buf, n, &aes);
93 dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
97 hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
98 safewrite(buf, SHA1dlen);
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);
111 memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
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!";
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);
124 aesCBCdecrypt(buf, CHK, &aes);
125 while((n = Bread(&bin, buf+CHK, BUF)) > 0){
126 aesCBCdecrypt(buf+CHK, n, &aes);
128 memmove(buf, buf+n, CHK);
130 if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0){
131 msg = "decrypted file failed to authenticate";
137 memset(key, 0, sizeof(key));
138 memset(key2, 0, sizeof(key2));
139 memset(buf, 0, sizeof(buf));
141 fprint(2, "%s\n", msg);