blob: d4afc6c81660aa5000cc7e3032cb5f38f6d8b6c4 [file] [log] [blame]
Amaury Pouly9fe029b2011-10-29 14:22:17 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "crypto.h"
22#include <stdio.h>
23#include <stdbool.h>
24#ifdef CRYPTO_LIBUSB
25#include "libusb.h"
26#endif
27#include "misc.h"
28
29static enum crypto_method_t cur_method = CRYPTO_NONE;
30static byte key[16];
31static uint16_t usb_vid, usb_pid;
32
33void crypto_setup(enum crypto_method_t method, void *param)
34{
35 cur_method = method;
36 switch(method)
37 {
38 case CRYPTO_KEY:
39 memcpy(key, param, sizeof(key));
40 break;
41 case CRYPTO_USBOTP:
42 {
43 uint32_t value = *(uint32_t *)param;
44 usb_vid = value >> 16;
45 usb_pid = value & 0xffff;
46 break;
47 }
48 default:
49 break;
50 }
51}
52
53int crypto_apply(
54 byte *in_data, /* Input data */
55 byte *out_data, /* Output data (or NULL) */
56 int nr_blocks, /* Number of blocks (one block=16 bytes) */
57 byte iv[16], /* Key */
58 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
59 int encrypt)
60{
61 if(cur_method == CRYPTO_KEY)
62 {
63 cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt);
64 return CRYPTO_ERROR_SUCCESS;
65 }
66 #ifdef CRYPTO_LIBUSB
67 else if(cur_method == CRYPTO_USBOTP)
68 {
69 if(out_cbc_mac && !encrypt)
70 memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16);
71
72 libusb_device_handle *handle = NULL;
73 libusb_context *ctx;
74 /* init library */
75 libusb_init(&ctx);
76 libusb_set_debug(NULL,3);
77 /* open device */
78 handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid);
79 if(handle == NULL)
80 {
81 printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid);
82 return CRYPTO_ERROR_NODEVICE;
83 }
84 /* get device pointer */
85 libusb_device *mydev = libusb_get_device(handle);
86 if(g_debug)
87 printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev),
88 libusb_get_device_address(mydev));
89 int config_id;
90 /* explore configuration */
91 libusb_get_configuration(handle, &config_id);
92 struct libusb_config_descriptor *config;
93 libusb_get_active_config_descriptor(mydev, &config);
94
95 if(g_debug)
96 {
97 printf("usbotp: configuration: %d\n", config_id);
98 printf("usbotp: interfaces: %d\n", config->bNumInterfaces);
99 }
100
101 const struct libusb_endpoint_descriptor *endp = NULL;
102 int intf, intf_alt;
103 for(intf = 0; intf < config->bNumInterfaces; intf++)
104 for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++)
105 for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++)
106 {
107 endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep];
108 if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
109 (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
110 goto Lfound;
111 }
112 libusb_close(handle);
113 printf("usbotp: No suitable endpoint found\n");
114 return CRYPTO_ERROR_BADENDP;
115
116 if(g_debug)
117 {
118 printf("usbotp: use interface %d, alt %d\n", intf, intf_alt);
119 printf("usbotp: use endpoint %d\n", endp->bEndpointAddress);
120 }
121 Lfound:
122 if(libusb_claim_interface(handle, intf) != 0)
123 {
124 if(g_debug)
125 printf("usbotp: claim error\n");
126 return CRYPTO_ERROR_CLAIMFAIL;
127 }
128
129 int buffer_size = 16 + 16 * nr_blocks;
130 unsigned char *buffer = xmalloc(buffer_size);
131 memcpy(buffer, iv, 16);
132 memcpy(buffer + 16, in_data, 16 * nr_blocks);
133 int ret = libusb_control_transfer(handle,
134 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
135 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000);
136 if(ret < 0)
137 {
138 if(g_debug)
139 printf("usbotp: control transfer failed: %d\n", ret);
140 libusb_release_interface(handle, intf);
141 libusb_close(handle);
142 return CRYPTO_ERROR_DEVREJECT;
143 }
144
145 int recv_size;
146 ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer,
147 buffer_size, &recv_size, 1000);
148 libusb_release_interface(handle, intf);
149 libusb_close(handle);
150
151 if(ret < 0)
152 {
153 if(g_debug)
154 printf("usbotp: interrupt transfer failed: %d\n", ret);
155 return CRYPTO_ERROR_DEVSILENT;
156 }
157 if(recv_size != buffer_size)
158 {
159 if(g_debug)
160 printf("usbotp: device returned %d bytes, expected %d\n", recv_size,
161 buffer_size);
162 return CRYPTO_ERROR_DEVERR;
163 }
164
165 if(out_data)
166 memcpy(out_data, buffer + 16, 16 * nr_blocks);
167 if(out_cbc_mac && encrypt)
168 memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16);
169
170 return CRYPTO_ERROR_SUCCESS;
171 }
172 #endif
173 else
174 return CRYPTO_ERROR_BADSETUP;
175}
176
177int crypto_cbc(
178 byte *in_data, /* Input data */
179 byte *out_data, /* Output data (or NULL) */
180 int nr_blocks, /* Number of blocks (one block=16 bytes) */
181 struct crypto_key_t *key, /* Key */
182 byte iv[16], /* IV */
183 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
184 int encrypt)
185{
186 crypto_setup(key->method, (void *)key->u.param);
187 return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt);
188}