2011-11-21 84 views
2

我想利用在我的熔絲文件系統中使用ioctl的LTO5設備的硬件加密。它應該很簡單,用cdb設置一個io_hdr:Linux 2.6.18 SCSI SPIN和SPOUT SG_IO ioctl的sg LTO5設備

0xB5, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00 

並按照所選算法提供關鍵頁面。當我執行SG_IO ioctl時,我得到一個返回0的SCSI全部爲0的意義。

現在,這裏是它變得奇怪。寫入設備的數據永遠不會被加密。我將磁帶切換到另一個驅動器並進行SCSI讀取,數據全部以明文顯示。

因此,下一步是執行一個SCSI SPIN命令來查看SPOUT命令是否被使用,即使所有的返回都說明了它。緊隨SPOUT後我送了SPIN的安全狀態頁(0×20):

0xA2, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00 

再次,從SG_IO IOCTL的返回值爲0,並全部爲零的感覺。不過,我找回的頁面是我放入驅動器的SPOUT關鍵頁面。我相信這不是從硬盤驅動器出來的,因爲它有我發送的密鑰,這絕對是一個SCSI規範不。順便說一句,對於這兩個SCSI命令我都使用一個完全不同的緩衝區,爲了好的措施,將SPIN頁面的memset設置爲零。 sg驅動程序提供這些數據以響應SPIN。

任何人都可以對此行爲有所瞭解嗎?

的Linux archive.xxxxx.xxx 2.6.18-274.7.1.el5#1 SMP週四年10月20 16點21分01秒EDT 2011 x86_64的x86_64的x86_64的GNU/Linux的

sg3_utils-庫-1.25-5。 EL5

SGPIO-1.2.0_10-2.el5

MT-ST-0.9b-2.2.2

我發送IOCTL命令到/ dev/SG5:

[[email protected] bin]# sg_inq /dev/sg5 
standard INQUIRY: 
    PQual=0 Device_type=1 RMB=1 version=0x06 [SPC-4] 
    [AERC=0] [TrmTsk=0] NormACA=0 HiSUP=0 Resp_data_format=2 
    SCCS=0 ACC=0 TPGS=0 3PC=0 Protect=1 BQue=0 
    EncServ=0 MultiP=1 (VS=0) [MChngr=0] [ACKREQQ=0] Addr16=0 
    [RelAdr=0] WBus16=0 Sync=0 Linked=0 [TranDis=0] CmdQue=1 
    [SPI: Clocking=0x0 QAS=0 IUS=0] 
    length=70 (0x46) Peripheral device type: tape 
Vendor identification: IBM  
Product identification: ULTRIUM-HH5  
Product revision level: BAKG 
Unit serial number: 106xxxxxxxxxx 

我發現Linux ioctl系統調用正在返回在sg_io_hdr_t的host_status成員中的主機適配器中檢測到的SG_ERR_DID_ERROR [0x07]內部錯誤。

的setltokey.c代碼也在於此:http://www.circlesoft.com/setltokey.c

/* 
    setLTO4key: Set LTO4 Encryption Key 

    Copyright (c) 2008 Andrew Schretter <[email protected]> 
    Provided under GPL license 

    added clear encryption, 
    sense key and 
    error printouts - Gerard J. Cerchio <[email protected]> 
*/ 

#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <scsi/sg.h> 
#include <scsi/scsi.h> 
#include <ctype.h> 
#include <sys/ioctl.h> 
#include <unistd.h> 

#define SENSE_BUFF_LEN 96   /* from lto spec */ 

/* 
* here is a sample key - create a file with these HEX digits: 
    4418AFCD046F2535B2E996123CE7DE3D418A15915A091C4BA12BDC85D4069A77 
*/ 

/* 
* A good sg_io_hdr_t reference: http://tldp.org/HOWTO/SCSI-Generic-HOWTO/sg_io_hdr_t.html 
*/ 

/* Print a hexadecimal dump of a block of data */ 
void hexdump(void *data, int size) 
{ 
    unsigned char *p = data; 
    unsigned char c; 
    int n; 
    char bytestr[4] = {0}; 
    char addrstr[10] = {0}; 
    char hexstr[ 16*3 + 5] = {0}; 
    char charstr[16*1 + 5] = {0}; 
    for(n=1;n<=size;n++) { 
     if (n%16 == 1) { 
      /* store address for this line */ 
      snprintf(addrstr, sizeof(addrstr), "%.4x", 
       ((unsigned int)p-(unsigned int)data)); 
     } 

     c = *p; 
     if (isalnum(c) == 0) { 
      c = '.'; 
     } 

     /* store hex str (for left side) */ 
     snprintf(bytestr, sizeof(bytestr), "%02X ", *p); 
     strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); 

     /* store char str (for right side) */ 
     snprintf(bytestr, sizeof(bytestr), "%c", c); 
     strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); 

     if(n%16 == 0) { 
      /* line completed */ 
      printf(" [%4.4s] %-49.49s %s\n", addrstr, hexstr, charstr); 
      hexstr[0] = 0; 
      charstr[0] = 0; 
     } else if(n%8 == 0) { 
      /* half line: add whitespaces */ 
      strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); 
     } 
     p++; /* next byte */ 
    } 

    if (strlen(hexstr) > 0) { 
     /* print rest of buffer if not empty */ 
     printf(" [%4.4s] %-49.49s %s\n", addrstr, hexstr, charstr); 
    } 
} 

/* Send a SCSI command block and display the result. */ 
void do_read_command(int fd, char *desc, unsigned char *cmd, int len) 
{ 
     unsigned char sense[SENSE_BUFF_LEN]; 
     memset(sense, 0, SENSE_BUFF_LEN); 

     sg_io_hdr_t io; 
     unsigned char buf[512]; 

     memset(buf, 0, sizeof(buf)); 

     memset(&io, 0, sizeof(io)); 
     io.interface_id = 'S'; 
     io.cmd_len = len; 
     io.mx_sb_len = 0; 
     io.dxfer_direction = SG_DXFER_FROM_DEV; 
     io.dxfer_len = sizeof(buf); 
     io.dxferp = buf; 
     io.cmdp = cmd; 

     printf("Command: %s\n", desc); 
     hexdump(cmd, len); 

     if (ioctl(fd, SG_IO, &io) < 0) { 
       printf("Error: %s\n", strerror(errno)); 
       return; 
     } 

     if (io.sb_len_wr){ 
      printf("Sense\n"); 
      hexdump(sense, SENSE_BUFF_LEN); 
     } 
     else 
      printf("No Sense\n"); 

     if ((io.info & SG_INFO_OK_MASK) != SG_INFO_OK) { 
      printf("Failed with info 0x%02x mask status 0x%02x msg status 0x%02x host status 0x%02x driver status 0x%02x\n", io.info, io.masked_status, io.msg_status, io.host_status, io.driver_status); 
      return; 
     } 

     len = io.dxfer_len - io.resid; 
     printf("Response: %d %s\n", len, (len == 1) ? "byte" : "bytes"); 
     hexdump(buf, len); 
} 

void do_write_command(int fd, char *desc, unsigned char *cmd, int len, char *data_desc, unsigned char *data, int datalen) 
{ 
     unsigned char sense[SENSE_BUFF_LEN]; 
     memset(sense, 0, SENSE_BUFF_LEN); 

     sg_io_hdr_t io; 
     memset(&io, 0, sizeof(io)); 
     io.interface_id = 'S'; 
     io.cmd_len = len; 
     io.mx_sb_len = SENSE_BUFF_LEN; 
     io.dxfer_direction = SG_DXFER_TO_DEV; 
     io.dxfer_len = datalen; 
     io.dxferp = data; 
     io.cmdp = cmd; 
     io.sbp = sense; 

     printf("Command: %s\n", desc); 
     hexdump(cmd, len); 
     printf("Data: %s\n", data_desc); 
     hexdump(data, datalen); 

     if (ioctl(fd, SG_IO, &io) < 0) { 
       printf("Error: %s\n", strerror(errno)); 
       return; 
     } 

     if (io.sb_len_wr){ 
      printf("Sense\n"); 
      hexdump(sense, SENSE_BUFF_LEN); 
     } 
     else 
      printf("No Sense\n"); 

     if ((io.info & SG_INFO_OK_MASK) != SG_INFO_OK) { 
      printf("Failed with info 0x%02x mask status 0x%02x msg status 0x%02x host status 0x%02x driver status 0x%02x\n", io.info, io.masked_status, io.msg_status, io.host_status, io.driver_status); 
       return; 
     } 

     len = io.dxfer_len - io.resid; 
     printf("Response: %d %s\n", len, (len == 1) ? "byte" : "bytes"); 

     //hexdump(buf, len); 
} 

struct { 
     char *description; 
     int len; 
     unsigned char cmd[16]; 
} commands[] = { 
     { "SCSI Inquiry", 6, 
      { 0x12, 0x00, 0x00, 0x00, 0xFF, 0x00 } }, 
     { "SCSI SPOUT Set Encryption Key", 12, 
      { 0xb5, 0x20, 0x00, 0x10, 0x00, 0x00, 
      0x00, 0x00, 0x00, 0x34, 0x00, 0x00 } }, 
     { "SCSI SPIN Read Status", 12, 
      { 0xa2, 0x20, 0x00, 0x20, 0x00, 0x00, 
      0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } }, 
     { NULL, 0, { 0 } }, 
}; 

struct { 
     char *description; 
     int len; 
     unsigned char cmd[64]; 
} data[] = { 
     { "SCSI SPOUT Send Encryption Key Page", 52, 
      { 0x00, 0x10, 0x00, 0x30, 0x40, 0x00, 
      0x02, 0x03, 0x01, 0x00, 
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
      0x00, 0x20, 
      } }, 
     { "SCSI SPOUT Clear Encryption Mode Page", 52, 
      { 0x00, 0x10, 0x00, 0x30, 0x40, 0x00, 
      0x00, 0x00, 0x01, 0x00, 
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
      0x00, 0x20, 
      } }, 
     { NULL, 0, { 0 } }, 
}; 

int main(int argc, char **argv) 
{ 
     FILE *fd2; 
     int fd; 
     int i = 0; 

     if (argc < 2) { 
       fprintf(stderr, "usage: %s /dev/sda < <keyfile.txt> | clear >\n", *argv); 
       return 1; 
     } 

     if ((fd = open(argv[1], O_RDWR)) < 0) { 
       perror(argv[1]); 
       return 1; 
     } 

     if ((ioctl(fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000)) { 
       fprintf(stderr,"%s is not a sg device\n", argv[1]); 
       close(fd); 
       return 1; 
     } 

     printf("Opened %s\n", argv[1]); 
     /* Send query command */ 
     do_read_command(fd, commands[0].description, commands[0].cmd, commands[0].len); 

     if(argc > 2) { 

     if (strcasecmp(argv[2], "clear") == 0) { 
      do_write_command(fd, commands[1].description, commands[1].cmd, commands[1].len, data[1].description, data[1].cmd, data[1].len); 

     } 
     else 
     { 
      if ((fd2 = fopen(argv[2], "r")) < 0) { 
       perror(argv[2]); 
       return 1; 
       } 

      for (i = 0; i < 32; i++) { 
       if(fscanf(fd2, "%2x ", (unsigned int *) &data[0].cmd[i + 20]) != 1) { 
        fprintf(stderr, "Keyfile Error reading %s\n", argv[2]); 
        return 1; 
        } 
       } 
      fclose(fd2); 
      /* Set Encryption key*/ 
      do_write_command(fd, commands[1].description, commands[1].cmd, commands[1].len, data[0].description, data[0].cmd, data[0].len); 
      } 
     } 

     /* Query encryption status */ 
     do_read_command(fd, commands[2].description, commands[2].cmd, commands[2].len); 
     close(fd); 
     return 0; 
} 
+1

StackOverflow用於編程問題。這屬於超級用戶。請閱讀常見問題解答:http://stackoverflow.com/faq – Polynomial

+0

這是在特定設備上使用Linux調用ioctl的編程問題。 – gjpc

回答

0

我發現了這個問題。 Dell PowerEdge R410內置的LSI 6Gb SAS SCSI HBA與微軟的ULTRIUM-HH5 LTO5磁帶機不兼容。

HBA在SPIN和SPOUT命令上都失敗。我們認爲它是我們使用的RedHat版本,比Paul的Ubuntu 10.04更早。我們使用我們的文件系統的內置設施執行密碼學,並決定在能夠升級到更新的RedHat時重新訪問該問題。

在驗證過程中發現顯示塞不兼容。當我們將過期的清潔盒裝入任何驅動器時,LSI HBA正在爲Qualstar RLS-8560磁帶庫生成額外的SCSI MOVE MEDIA命令。這個錯誤表現爲偶爾的感應鑰匙2 ASC 3B ASQ 90返回到主機的單個SCSI MOVE MEDIA命令。

解決方案是安裝經認證與IBM驅動器兼容的ATTO ExpressSAS H680 6Gb/s SAS/SATA HBA,PCIe 2.0,8端口外部SCSI適配器。

1

gjpc我試圖完成同樣的事情,你必須在這個問題上有何進展?

更新: 我剛發現你的程序正在工作。 我用惠普驅動器測試過它正確上傳了密鑰(藍色指示燈)。我可以寫一個磁帶,上傳另一個密鑰,但我無法讀取磁帶,在更換爲正確的密鑰後,我可以再次從磁帶讀取數據。感謝您分享您的代碼。

+0

謝謝保羅。您能否讓我知道您使用的操作系統和版本?另外,如果你碰到這個問題對你有幫助,那將會很好。 – gjpc

+0

我使用的是Ubuntu 10.04服務器版本 – Paul