/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2010 Amaury Pouly * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "crypto.h" #include #include #ifdef CRYPTO_LIBUSB #include "libusb.h" #endif #include "misc.h" static enum crypto_method_t cur_method = CRYPTO_NONE; static byte key[16]; static uint16_t usb_vid, usb_pid; void crypto_setup(enum crypto_method_t method, void *param) { cur_method = method; switch(method) { case CRYPTO_KEY: memcpy(key, param, sizeof(key)); break; case CRYPTO_USBOTP: { uint32_t value = *(uint32_t *)param; usb_vid = value >> 16; usb_pid = value & 0xffff; break; } default: break; } } int crypto_apply( byte *in_data, /* Input data */ byte *out_data, /* Output data (or NULL) */ int nr_blocks, /* Number of blocks (one block=16 bytes) */ byte iv[16], /* Key */ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ int encrypt) { if(cur_method == CRYPTO_KEY) { cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt); return CRYPTO_ERROR_SUCCESS; } #ifdef CRYPTO_LIBUSB else if(cur_method == CRYPTO_USBOTP) { if(out_cbc_mac && !encrypt) memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16); libusb_device_handle *handle = NULL; libusb_context *ctx; /* init library */ libusb_init(&ctx); libusb_set_debug(NULL,3); /* open device */ handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid); if(handle == NULL) { printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid); return CRYPTO_ERROR_NODEVICE; } /* get device pointer */ libusb_device *mydev = libusb_get_device(handle); if(g_debug) printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev), libusb_get_device_address(mydev)); int config_id; /* explore configuration */ libusb_get_configuration(handle, &config_id); struct libusb_config_descriptor *config; libusb_get_active_config_descriptor(mydev, &config); if(g_debug) { printf("usbotp: configuration: %d\n", config_id); printf("usbotp: interfaces: %d\n", config->bNumInterfaces); } const struct libusb_endpoint_descriptor *endp = NULL; int intf, intf_alt; for(intf = 0; intf < config->bNumInterfaces; intf++) for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++) for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++) { endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep]; if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT && (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) goto Lfound; } libusb_close(handle); printf("usbotp: No suitable endpoint found\n"); return CRYPTO_ERROR_BADENDP; if(g_debug) { printf("usbotp: use interface %d, alt %d\n", intf, intf_alt); printf("usbotp: use endpoint %d\n", endp->bEndpointAddress); } Lfound: if(libusb_claim_interface(handle, intf) != 0) { if(g_debug) printf("usbotp: claim error\n"); return CRYPTO_ERROR_CLAIMFAIL; } int buffer_size = 16 + 16 * nr_blocks; unsigned char *buffer = xmalloc(buffer_size); memcpy(buffer, iv, 16); memcpy(buffer + 16, in_data, 16 * nr_blocks); int ret = libusb_control_transfer(handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000); if(ret < 0) { if(g_debug) printf("usbotp: control transfer failed: %d\n", ret); libusb_release_interface(handle, intf); libusb_close(handle); return CRYPTO_ERROR_DEVREJECT; } int recv_size; ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer, buffer_size, &recv_size, 1000); libusb_release_interface(handle, intf); libusb_close(handle); if(ret < 0) { if(g_debug) printf("usbotp: interrupt transfer failed: %d\n", ret); return CRYPTO_ERROR_DEVSILENT; } if(recv_size != buffer_size) { if(g_debug) printf("usbotp: device returned %d bytes, expected %d\n", recv_size, buffer_size); return CRYPTO_ERROR_DEVERR; } if(out_data) memcpy(out_data, buffer + 16, 16 * nr_blocks); if(out_cbc_mac && encrypt) memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16); return CRYPTO_ERROR_SUCCESS; } #endif else return CRYPTO_ERROR_BADSETUP; } int crypto_cbc( byte *in_data, /* Input data */ byte *out_data, /* Output data (or NULL) */ int nr_blocks, /* Number of blocks (one block=16 bytes) */ struct crypto_key_t *key, /* Key */ byte iv[16], /* IV */ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ int encrypt) { crypto_setup(key->method, (void *)key->u.param); return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt); }