]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/cryptsetup.c
rio: fix goodrect() bug (thanks mike)
[plan9front.git] / sys / src / cmd / disk / cryptsetup.c
1 // Original Author Taru Karttunen <taruti@taruti.net>
2 // This file can be used as both Public Domain or Creative Commons CC0.
3 #include <u.h>
4 #include <libc.h>
5 #include <libsec.h>
6 #include <authsrv.h>
7
8 typedef struct {
9         uchar Salt[16];
10         uchar Key[32];
11 } Slot;
12
13 typedef struct {
14         uchar Master[32];
15         Slot Slots[8];
16         AESstate C1, C2;
17 } XtsState;
18
19 uchar zeros[16] = {0};
20 uchar buf[64*1024];
21 AESstate cbc;
22 XtsState s;
23
24 void 
25 setupkey(char *pass, uchar salt[16], AESstate *aes)
26 {
27         uchar tkey[32];
28
29         pbkdf2_x((uchar*)pass, strlen(pass), salt, 16, 9999, tkey, 32, hmac_sha1, SHA1dlen);
30         setupAESstate(aes, tkey, 16, zeros);
31         memset(tkey, 0, sizeof(tkey));
32 }
33
34 void
35 freepass(char *pass)
36 {
37         if(pass != nil){
38                 memset(pass, 0, strlen(pass));
39                 free(pass);
40         }
41 }
42
43 void
44 cformat(char *files[])
45 {
46         char *pass, *tmp;
47         int fd, i, j;
48
49         pass = nil;
50         do {
51                 freepass(pass);
52                 pass = readcons("Password", nil, 1);
53                 if(pass == nil || pass[0] == 0)
54                         sysfatal("input aborted");
55                 tmp = readcons("Confirm", nil, 1);
56                 if(tmp == nil || tmp[0] == 0)
57                         sysfatal("input aborted");
58                 i = strcmp(pass, tmp);
59                 freepass(tmp);
60         } while(i != 0);
61
62         for(;*files != nil; files++) {
63                 genrandom((uchar*)&s, sizeof(s));
64                 setupkey(pass, s.Slots[0].Salt, &cbc);
65                 memcpy(s.Slots[0].Key, s.Master, 32);
66                 aesCBCencrypt(s.Slots[0].Key, 32, &cbc);
67
68                 genrandom(buf, 16*4096);
69                 for(i=0; i<16; i++)
70                         for(j=0; j<8; j++) {
71                                 buf[(4096*i)+(4*j)+1] = s.Slots[j].Salt[i];
72                                 buf[(4096*i)+(4*j)+2] = s.Slots[j].Key[i];
73                                 buf[(4096*i)+(4*j)+3] = s.Slots[j].Key[i+16];
74                         }
75
76                 if((fd = open(*files, OWRITE)) < 0)
77                         sysfatal("open disk: %r");
78         
79                 /* make the pad for checking crypto */
80                 for(i=0; i<8; i++)
81                         buf[(64*1024)-8+i] = ~buf[(64*1024)-16+i];
82
83                 setupAESstate(&cbc, s.Master, 16, zeros);
84                 aes_encrypt(cbc.ekey, cbc.rounds, &buf[(64*1024)-16], &buf[(64*1024)-16]);
85
86                 if(write(fd, buf, 64*1024) != 64*1024)
87                         sysfatal("writing disk: %r");
88         }
89 }
90
91 void
92 copen(char *files[], int ctl)
93 {
94         char *pass, *name;
95         uchar cbuf[16];
96         int fd, i, j;
97
98         pass = nil;
99         for(;*files != nil; files++) {
100                 memset(&s, 0, sizeof(s));
101                 if((fd = open(*files, OREAD)) < 0)
102                         sysfatal("open disk: %r");
103         
104                 if(read(fd, buf, 1024*64) != 1024*64) 
105                         sysfatal("read disk: %r");
106         
107         retrypass:
108                 for(i=0; i<16; i++)
109                         for(j=0; j<8; j++) {
110                                 s.Slots[j].Salt[i] = buf[(4096*i)+(4*j)+1];
111                                 s.Slots[j].Key[i] = buf[(4096*i)+(4*j)+2];
112                                 s.Slots[j].Key[i+16] = buf[(4096*i)+(4*j)+3];
113                         }
114
115                 if(pass == nil){
116                         pass = readcons("Password", nil, 1);
117                         if(pass == nil || pass[0] == 0)
118                                 sysfatal("input aborted");
119                 }
120
121                 setupkey(pass, s.Slots[0].Salt, &cbc);
122                 memcpy(s.Master, s.Slots[0].Key, 32);
123                 aesCBCdecrypt(s.Master, 32, &cbc);
124                 setupAESstate(&cbc, s.Master, 16, zeros);
125
126                 memcpy(cbuf, &buf[(64*1024)-16], 16);
127                 aes_decrypt(cbc.dkey, cbc.rounds, cbuf, cbuf);
128
129                 /* make the pad for checking crypto */
130                 for(i=0; i<8; i++)
131                         if((cbuf[i] ^ cbuf[i+8]) != 255) {
132                                 freepass(pass);
133                                 pass = nil;
134                                 fprint(2, "wrong key\n");
135                                 goto retrypass;
136                         }
137
138                 fd2path(fd, (char*)buf, sizeof(buf));
139                 close(fd);
140
141                 if((name = strrchr(*files, '/')) != nil)
142                         name++;
143                 else
144                         name = *files;
145
146                 if(fprint(ctl, "crypt %q %q %.32H\n", name, (char*)buf, s.Master) < 0)
147                         sysfatal("write: %r");
148         }
149 }
150
151 void 
152 usage(void)
153 {
154         print("usage:\n"
155                 "%s -f files\t\t# Format file or device\n"
156                 "%s -o files\t\t# Print commandline for open\n"
157                 "%s -i files\t\t# Install (open) files\n",
158                 argv0, argv0, argv0);
159         exits("usage");
160 }
161
162 void
163 main(int argc, char *argv[])
164 {
165         enum {
166                 NoMode,
167                 Format,
168                 Open,
169                 Install,
170         };
171         int mode, ctl;
172
173         quotefmtinstall();
174         fmtinstall('H', encodefmt);
175
176         ctl = 1;
177         mode = NoMode;
178
179         ARGBEGIN {
180         default:
181                 usage();
182         case 'f':
183                 mode = Format;
184                 break;
185         case 'o':
186                 mode = Open;
187                 break;
188         case 'i':
189                 mode = Install;
190                 break;
191         } ARGEND;
192
193         if(argc < 0)
194                 usage();
195
196         switch(mode){
197         default:
198                 usage();
199         case Format:
200                 cformat(argv);
201                 break;
202         case Install:
203                 if((ctl = open("/dev/fs/ctl", OWRITE)) < 0)
204                         sysfatal("open ctl: %r");
205                 /* no break */
206         case Open:
207                 copen(argv, ctl);
208                 break;
209         }
210
211         exits(nil);
212 }