1 | /*
|
2 | * crypto-losetup.c
|
3 | * Simplified version of losetup designed specifically for use with cryptoloop
|
4 | * Usage: crypto-losetup [-c cipher] [-r] <loopdev> <file> <key>
|
5 | * -c <cipher> set cipher (default aes-cbc)
|
6 | * -r open file read-only
|
7 | */
|
8 | #include <stdio.h>
|
9 | #include <stdlib.h>
|
10 | #include <stdbool.h>
|
11 | #include <string.h>
|
12 | #include <unistd.h>
|
13 | #include <fcntl.h>
|
14 | #include <linux/loop.h>
|
15 | #include <sys/ioctl.h>
|
16 | #include <getopt.h>
|
17 |
|
18 | static bool parse_hex_nibble(const char c, unsigned char *result)
|
19 | {
|
20 | if ((c >= '0') && (c <= '9'))
|
21 | *result = c - '0';
|
22 | else if ((c >= 'a') && (c <= 'f'))
|
23 | *result = c - 'a' + 10;
|
24 | else if ((c >= 'A') && (c <= 'F'))
|
25 | *result = c - 'A' + 10;
|
26 | else
|
27 | return false;
|
28 | return true;
|
29 | }
|
30 |
|
31 | static bool parse_keystring(const char *hex_string, unsigned char *key, unsigned int key_len)
|
32 | {
|
33 | unsigned char hi, lo;
|
34 | unsigned int i;
|
35 |
|
36 | for (i = 0; i < key_len; i++)
|
37 | {
|
38 | if (!parse_hex_nibble(hex_string[2*i], &hi)
|
39 | || !parse_hex_nibble(hex_string[2*i+1], &lo))
|
40 | return false;
|
41 |
|
42 | key[i] = (hi<<4)|lo;
|
43 | }
|
44 | return true;
|
45 | }
|
46 |
|
47 | static bool setup_loopdev(const char *loopdev, const char *file, bool readonly, const char *cipher, unsigned char *key, unsigned int keylen)
|
48 | {
|
49 | struct loop_info64 li;
|
50 | int loopfd, fd;
|
51 | bool ret = false;
|
52 |
|
53 | if (keylen > sizeof(li.lo_encrypt_key))
|
54 | {
|
55 | fprintf(stderr, "key too long (max %lu bytes)\n", sizeof(li.lo_encrypt_key));
|
56 | goto out_noclose2;
|
57 | }
|
58 |
|
59 | fd = open(file, readonly ? O_RDONLY : O_RDWR);
|
60 | if (fd == -1)
|
61 | {
|
62 | perror(file);
|
63 | goto out_noclose2;
|
64 | }
|
65 |
|
66 | loopfd = open(loopdev, O_RDWR);
|
67 | if (loopfd == -1)
|
68 | {
|
69 | perror(loopdev);
|
70 | goto out_noclose1;
|
71 | }
|
72 |
|
73 | if (ioctl(loopfd, LOOP_SET_FD, fd) == -1)
|
74 | {
|
75 | perror("LOOP_SET_FD");
|
76 | goto out;
|
77 | }
|
78 |
|
79 | memset(&li, 0, sizeof(li));
|
80 | strncpy((char *)li.lo_file_name, file, sizeof(li.lo_file_name));
|
81 | li.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
|
82 | strncpy((char *)li.lo_crypt_name, cipher, sizeof(li.lo_crypt_name));
|
83 | li.lo_encrypt_key_size = keylen;
|
84 | memcpy(li.lo_encrypt_key, key, keylen);
|
85 | if (ioctl(loopfd, LOOP_SET_STATUS64, &li) == -1)
|
86 | {
|
87 | perror("LOOP_SET_STATUS64");
|
88 | ioctl(loopfd, LOOP_CLR_FD);
|
89 | goto out;
|
90 | }
|
91 |
|
92 | ret = true;
|
93 | out:
|
94 | close(loopfd);
|
95 | out_noclose1:
|
96 | close(fd);
|
97 | out_noclose2:
|
98 | return ret;
|
99 | }
|
100 |
|
101 | int main(int argc, char *argv[])
|
102 | {
|
103 | const char *loopdev, *file;
|
104 | const char *cipher = "aes-cbc";
|
105 | const char *keystring = NULL;
|
106 | unsigned char *key;
|
107 | unsigned int keylen;
|
108 | bool readonly = false;
|
109 | int c, ret;
|
110 |
|
111 | while ((c = getopt(argc, argv, "c:rh?")) != -1)
|
112 | {
|
113 | switch (c)
|
114 | {
|
115 | case 'c':
|
116 | cipher = optarg;
|
117 | break;
|
118 | case 'r':
|
119 | readonly = true;
|
120 | break;
|
121 | default:
|
122 | goto usage;
|
123 | }
|
124 | }
|
125 |
|
126 | if (argc-optind != 3)
|
127 | goto usage;
|
128 |
|
129 | loopdev = argv[optind];
|
130 | file = argv[optind+1];
|
131 | keystring = argv[optind+2];
|
132 |
|
133 | keylen = strlen(keystring)/2;
|
134 | key = malloc(keylen);
|
135 | if (!key)
|
136 | {
|
137 | fprintf(stderr, "malloc failed\n");
|
138 | return 1;
|
139 | }
|
140 | if (!parse_keystring(keystring, key, keylen))
|
141 | {
|
142 | fprintf(stderr, "failed to parse key\n");
|
143 | free(key);
|
144 | return 1;
|
145 | }
|
146 |
|
147 | ret = setup_loopdev(loopdev, file, readonly, cipher, key, keylen) ? 0 : 1;
|
148 | free(key);
|
149 | return ret;
|
150 |
|
151 | usage:
|
152 | fprintf(stderr, "usage: %s [-c cipher] [-r] <loopdev> <file> <key>\n", argv[0]);
|
153 | return 1;
|
154 | }
|