9fe029b12a
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30849 a1c6a512-1295-4272-9138-f99709370657
188 lines
6.5 KiB
C
188 lines
6.5 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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 <stdio.h>
|
|
#include <stdbool.h>
|
|
#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);
|
|
}
|