Amaury Pouly | 9fe029b | 2011-10-29 14:22:17 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 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 | |
| 29 | static enum crypto_method_t cur_method = CRYPTO_NONE; |
| 30 | static byte key[16]; |
| 31 | static uint16_t usb_vid, usb_pid; |
| 32 | |
| 33 | void 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 | |
| 53 | int 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 | |
| 177 | int 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 | } |