crypto-losetup.c


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
}