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 }