123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- /**
- * u3-tool - U3 USB stick manager
- * Copyright (C) 2007 Daviedev, daviedev@users.sourceforge.net
- *
- * 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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include "u3_commands.h"
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include "u3_scsi.h"
- #include "u3_error.h"
- #include "md5.h"
- #ifdef WIN32
- # include <windows.h>
- # define sleep Sleep
- // Barf, winsock... NOT
- # define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
- (((uint32_t)(A) & 0x00ff0000) >> 8) | \
- (((uint32_t)(A) & 0x0000ff00) << 8) | \
- (((uint32_t)(A) & 0x000000ff) << 24))
- #else
- # include <arpa/inet.h> // for htonl()
- #endif
- #if __BYTE_ORDER != __LITTLE_ENDIAN
- # error "This tool only runs on Little Endian machines"
- #endif
- #define U3_PASSWORD_HASH_LEN 16
- /**
- * Convert textual password to hash.
- *
- * @param pass The password string, null terminated.
- * @param hash Buffer to write hash to, should be atleast
- * U3_PASSWORD_HASH_LEN long.
- */
- void u3_pass_to_hash(const char *password, uint8_t *hash) {
- unsigned int passlen;
- unsigned int unicode_passlen;
- uint8_t *unicode_pass;
- int i;
- passlen = strlen(password);
- unicode_passlen = (passlen+1)*2;
- unicode_pass = (uint8_t *) calloc(passlen+1, 2);
- for (i = 0; i < passlen + 1; i++) {
- unicode_pass[i*2] = password[i];
- }
-
- md5(unicode_pass, unicode_passlen, hash);
- memset(unicode_pass, 0xFF, unicode_passlen);
- memset(unicode_pass, 0, unicode_passlen);
- free(unicode_pass);
- }
- /**** public function ***/
- int u3_read_device_property(u3_handle_t *device, uint16_t property_id,
- uint8_t *buffer, uint16_t buffer_length)
- {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- struct _write_cmd_t {
- uint8_t scsi_opcode;
- uint16_t command;
- uint16_t id;
- uint16_t length;
- uint16_t unknown1;
- uint8_t unknown2;
- } __attribute__ ((packed)) *property_command;
- struct property_header *hdr;
- if (buffer_length < 6) {
- u3_set_error(device, "buffer supplied to "
- "u3_read_device_property() is to small");
- return U3_FAILURE;
- }
- // First read header to prevent reading to much data
- hdr = (struct property_header *) buffer;
- property_command = (struct _write_cmd_t *) &cmd;
- property_command->id = property_id;
- property_command->length = sizeof(struct property_header);
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, property_command->length,
- buffer, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Header of property 0x%.4X could not be "
- "read.", property_id);
- return U3_FAILURE;
- }
- if (hdr->length < sizeof(struct property_header)) {
- u3_set_error(device, "Header of property 0x%.4X indicates a "
- "length of smaller then the header size. (len = %u)"
- , property_id, hdr->length);
- return U3_FAILURE;
- }
- // Read full property
- if (hdr->length > buffer_length) {
- property_command->length = buffer_length;
- } else {
- property_command->length = hdr->length;
- }
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, property_command->length,
- buffer, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Property 0x%.4X could not be read.",
- property_id);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_partition(u3_handle_t *device, uint32_t cd_size) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- struct part_info data;
- struct property_03 device_properties;
- uint32_t data_size;
- // calculate data partition size
- if (cd_size != 0) {
- if (u3_partition_sector_round(device, round_up, &cd_size) != U3_SUCCESS) {
- u3_prepend_error(device, "Failed rounding partition sectors");
- return U3_FAILURE;
- }
- }
- if (u3_read_device_property(device, 3, (uint8_t *) &device_properties,
- sizeof(device_properties)) != U3_SUCCESS)
- {
- u3_prepend_error(device, "Failed reading device property 0x03");
- return U3_FAILURE;
- }
- if (device_properties.hdr.length != sizeof(device_properties)) {
- u3_set_error(device, "Unexpected device property(0x03) length"
- ", won't risk breaking device. Aborting! (len=%X)",
- device_properties.hdr.length);
- return U3_FAILURE;
- }
- if (cd_size > device_properties.device_size) {
- u3_set_error(device, "Requested CD size is to big for device");
- return U3_FAILURE;
- }
- data_size = device_properties.device_size - cd_size;
- if (u3_partition_sector_round(device, round_down, &data_size) != U3_SUCCESS) {
- u3_prepend_error(device, "Failed rounding partition sectors");
- return U3_FAILURE;
- }
-
- // fill command data
- memset(&data, 0, sizeof(data));
- if (cd_size == 0) {
- data.partition_count = 1;
- data.unknown1 = 0x02;
- data.data_size = data_size;
- data.unknown2 = 0;
- data.cd_size = 0;
- } else {
- data.partition_count = 2;
- data.unknown1 = 0x02;
- data.data_size = data_size;
- data.unknown2 = 0x103;
- data.cd_size = cd_size;
- }
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(data),
- (uint8_t *) &data, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_cd_write(u3_handle_t *device, uint32_t block_num, uint8_t *block) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01
- };
- struct _write_cmd_t {
- uint8_t scsi_opcode;
- uint16_t command;
- uint8_t unknown1;
- uint32_t block_num;
- uint32_t unknown2;
- } __attribute__ ((packed)) *write_command;
- // fill command data
- write_command = (struct _write_cmd_t *) &cmd;
- write_command->block_num = htonl(block_num);
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, 2048,
- block, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_partition_sector_round(u3_handle_t *device,
- enum round_dir direction, uint32_t *size)
- {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint32_t rounded_size;
-
- // fill command data
- *((uint32_t *)(cmd+4)) = *size;
- cmd[8] = direction;
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, sizeof(rounded_size),
- (uint8_t *) &rounded_size, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device,
- "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- *size = rounded_size;
- return U3_SUCCESS;
- }
- int u3_security_sector_round(u3_handle_t *device,
- enum round_dir direction, uint32_t *size)
- {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint32_t rounded_size;
-
- // fill command data
- *((uint32_t *)(cmd+4)) = *size;
- cmd[8] = direction;
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, sizeof(rounded_size),
- (uint8_t *) &rounded_size, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device,
- "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- *size = rounded_size;
- return U3_SUCCESS;
- }
- int u3_partition_info(u3_handle_t *device, struct part_info *info) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- memset(info, 0, sizeof(struct part_info));
-
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, 9,
- (uint8_t *)info, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- //TODO: Find out if it is possible to define more then 2 partition. if so, make
- //this more dynamic
- if (info->partition_count == 2) {
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, 16,
- (uint8_t *)info, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_data_partition_info(u3_handle_t *device, struct dpart_info *info) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- memset(info, 0, sizeof(struct dpart_info));
-
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, sizeof(struct dpart_info),
- (uint8_t *)info, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_chip_info(u3_handle_t *device, struct chip_info *info) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- memset(info, 0, sizeof(struct chip_info));
-
- if (u3_send_cmd(device, cmd, U3_DATA_FROM_DEV, sizeof(struct chip_info),
- (uint8_t *)info, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_reset(u3_handle_t *device) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint8_t data[12] = { // the magic numbers
- 0x50, 0x00, 0x00, 0x00, 0x40, 0x9c, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00
- };
-
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(data),
- data, &status) != U3_SUCCESS)
- {
- return U3_FAILURE;
- }
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
-
- sleep(2); // wait for device to reset
- // u3_reopen(device);
- return U3_SUCCESS;
- }
- int u3_enable_security(u3_handle_t *device, const char *password) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- struct {
- uint32_t size;
- uint8_t hash[U3_PASSWORD_HASH_LEN];
- } __attribute__ ((packed)) data;
- struct dpart_info dp_info;
- uint32_t secure_zone_size;
- // determine size
- //TODO: allow user to determine secure zone size... However currently we don't
- // understand why disable security only works on a fully secured partition...
- if (u3_data_partition_info(device, &dp_info) != U3_SUCCESS) {
- u3_prepend_error(device, "Failed reading data partition info");
- return U3_FAILURE;
- }
- secure_zone_size = dp_info.total_size;
- if (secure_zone_size != 0) {
- if (u3_security_sector_round(device, round_up,
- &secure_zone_size) != U3_SUCCESS)
- {
- u3_prepend_error(device,
- "Failed rounding secure zone sectors");
- return U3_FAILURE;
- }
- }
- // fill command data
- data.size = secure_zone_size;
- u3_pass_to_hash(password, data.hash);
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(data),
- (uint8_t *) &data, &status) != U3_SUCCESS)
- {
- memset(&data, 0, sizeof(data));
- return U3_FAILURE;
- }
- memset(&data, 0, sizeof(data));
- if (status != 0) {
- u3_set_error(device, "Device reported command failed: status %d", status);
- return U3_FAILURE;
- }
- return U3_SUCCESS;
- }
- int u3_disable_security(u3_handle_t *device, const char *password,
- int * result)
- {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint8_t passhash_buf[U3_PASSWORD_HASH_LEN];
- *result = 0;
- u3_pass_to_hash(password, passhash_buf);
-
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(passhash_buf),
- passhash_buf, &status) != U3_SUCCESS)
- {
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_FAILURE;
- }
- if (status == 0) {
- *result = 1;
- }
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_SUCCESS;
- }
- int u3_unlock(u3_handle_t *device, const char *password, int *result) {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint8_t passhash_buf[U3_PASSWORD_HASH_LEN];
- *result = 0;
- u3_pass_to_hash(password, passhash_buf);
-
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(passhash_buf),
- passhash_buf, &status) != U3_SUCCESS)
- {
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_FAILURE;
- }
- if (status == 0) {
- *result = 1;
- }
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_SUCCESS;
- }
- int u3_change_password(u3_handle_t *device, const char *old_password,
- const char *new_password, int *result)
- {
- uint8_t status;
- uint8_t cmd[U3_CMD_LEN] = {
- 0xff, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- uint8_t passhash_buf[U3_PASSWORD_HASH_LEN * 2];
- *result = 0;
- u3_pass_to_hash(old_password, passhash_buf);
- u3_pass_to_hash(new_password, passhash_buf+U3_PASSWORD_HASH_LEN);
-
- if (u3_send_cmd(device, cmd, U3_DATA_TO_DEV, sizeof(passhash_buf),
- (uint8_t *) passhash_buf, &status) != U3_SUCCESS)
- {
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_FAILURE;
- }
- if (status == 0) {
- *result = 1;
- }
- memset(passhash_buf, 0, sizeof(passhash_buf));
- return U3_SUCCESS;
- }
|