ChipWhisperer教程(三)

——CW305目標板的波形采集

一、目標板介紹

CW305 是一款獨立的 FPGA 目標板,搭載的FPGA芯片為Xilinx Artix-7系列。 它具有與 FPGA 通信的 USB 接口、為 FPGA 提供時鐘的外部 PLL、編程 VCC-INT 電源以及用于故障注入環境的二極管保護。 CW305 電路板有多種配置,與其他 ChipWhisperer 獨立目標一樣,它需要外部設備進行側通道功率分析或故障注入,并具有標準 ChipWhisperer 20 引腳/SMA 接口。

Xilinx Artix-7系列是賽靈思公司推出的一款中高端現場可編程門陣列(FPGA),它主要面向需要較高性能和較低成本的設計應用。以下是Xilinx Artix-7系列的一些主要特點:

  1. 邏輯資源豐富:Artix-7系列提供了大量的邏輯單元、查找表(LUTs)、寄存器、塊RAM和數字信號處理(DSP)切片,可以滿足復雜算法和數據處理的需求。
  2. 高速IO:支持高速串行IO標準,如6.25 Gbps的GTP收發器,能夠實現高速數據傳輸。
  3. 集成硬核處理器:部分Artix-7器件集成了硬核處理器,如PowerPC 440,可用于處理復雜控制任務。
  4. 高級時鐘管理:具有多個數字時鐘管理器(DCMs)和鎖相環(PLLs),可以提供穩定的時鐘信號,支持多種時鐘域的操作。

二、目標板代碼編寫

CW305目標板的代碼為verilog代碼,通過vivado軟件進行綜合、實現和生成比特流文件。CW305目標板通過USB接口與FPGA芯片通信,目標板代碼同樣分為USB接口通信和密碼算法實現兩部分,密碼算法實現本文不再講解,讀者自行學習。ChiWhisperer官網已經給出了AES循環迭代實現、AES流水線實現和ECC的代碼,以及與CW305、CW312T-A35、CW312T-iCE40和CW308T-S6LX9共4種FPGA目標板的通信接口(參考https://github.com/newaetech/chipwhisperer/tree/develop/firmware/fpgas?)。以CW305的AES循環迭代實現為例,涉及CW305的USB通信接口的代碼包含以下6個verilog文件:

  • cdc_pulse.v:不同時鐘域的同步。
  • clocks.v:選擇輸入時鐘并驅動輸出時鐘。
  • cw305_usb_reg_fe.v:處理USB接口的前端邏輯。
  • cw305_defines.v:定義了一些寄存器地址(常量),用于在系統中進行寄存器訪問。
  • cw305_reg_aes.v:處理與AES加密相關的寄存器操作。
  • cw305_top.v:頂層模塊,連接了各個子模塊并處理系統的整體邏輯。

前三個文件相對固定,一般無需修改,本文主要對后面三個文件進行說明。

1. cw305_defines.v

該文件定義了一些寄存器的地址,如果用戶有新的需求可以添加更多的地址,默認14位的地址空間,比較充足。

`define REG_CLKSETTINGS                 'h00	//密碼運算單元的時鐘來源
`define REG_USER_LED                    'h01	//CW305目標板上的用戶LED燈
`define REG_CRYPT_TYPE                  'h02	//加密類型
`define REG_CRYPT_REV                   'h03	//加密版本
`define REG_IDENTIFY                    'h04	//標識符
`define REG_CRYPT_GO                    'h05	//寫該地址開始執行加/解密和采波,讀該地址獲取加密運算單元是否繁忙
`define REG_CRYPT_TEXTIN                'h06	//輸出到加密運算單元的明文
`define REG_CRYPT_CIPHERIN              'h07	//輸出到加密運算單元的密文
`define REG_CRYPT_TEXTOUT               'h08	//來自加密運算單元的明文
`define REG_CRYPT_CIPHEROUT             'h09	//來自加密運算單元的明文
`define REG_CRYPT_KEY                   'h0a	//密鑰
`define REG_BUILDTIME                   'h0b	//構建時間

2. cw305_reg_aes.v

`default_nettype none		//設置沒有顯示聲明的網絡類型為none,編譯器會報錯,用于捕獲未聲明的信號
`timescale 1ns / 1ps		//設置仿真時間單位為1ns,精度為1ps
`include "cw305_defines.v"	//包含cw305_defines.v文件//模塊聲明和參數化
module cw305_reg_aes #(parameter pADDR_WIDTH = 21,	//寄存器地址寬度parameter pBYTECNT_SIZE = 7,	//對寄存器進行字節計數的大小parameter pDONE_EDGE_SENSITIVE = 1,	//指示I_done信號是否是邊沿敏感的parameter pPT_WIDTH = 128,	//明文寬度parameter pCT_WIDTH = 128,	//密文寬度parameter pKEY_WIDTH = 128,	//密鑰寬度parameter pCRYPT_TYPE = 2,	//加密類型parameter pCRYPT_REV = 4,	//加密版本parameter pIDENTIFY = 8'h2e	//標識符
)(//主機與寄存器交互的端口聲明input  wire                                  usb_clk,		//USB時鐘input  wire                                  crypto_clk,		//加密時鐘input  wire                                  reset_i,		//復位信號input  wire [pADDR_WIDTH-pBYTECNT_SIZE-1:0]  reg_address,	//寄存器地址input  wire [pBYTECNT_SIZE-1:0]              reg_bytecnt,	//寄存器中第幾個字節output reg  [7:0]                            read_data,		//從寄存器讀取的數據,將會通過USB接口傳回主機input  wire [7:0]                            write_data,		//從主機傳入的用于寫入寄存器的數據input  wire                                  reg_read,		//讀有效標志input  wire                                  reg_write,		//寫有效標志input  wire                                  reg_addrvalid,	//地址有效標志input  wire                                  exttrigger_in,	//外部觸發信號,為高則開始加密和采波//來自加密運算單元的輸入信號input  wire [pPT_WIDTH-1:0]                  I_textout,		//明文(執行解密時有效)input  wire [pCT_WIDTH-1:0]                  I_cipherout,	//密文(執行加密時有效)input  wire                                  I_ready,		//準備就緒input  wire                                  I_done,			//執行完畢input  wire                                  I_busy,			//執行中//輸出到加密運算單元的信號output reg  [4:0]                            O_clksettings,	//用于選擇加密運算單元的時鐘信號output reg                                   O_user_led,		//用戶LED燈信號output wire [pKEY_WIDTH-1:0]                 O_key,			//密鑰output wire [pPT_WIDTH-1:0]                  O_textin,		//明文(執行加密時有效)output wire [pCT_WIDTH-1:0]                  O_cipherin,		//密文(執行解密時有效)output wire                                  O_start			//開始執行加/解密并采波);//內部信號聲明reg  [7:0]                   reg_read_data;			//存儲從USB接口讀取的數據reg  [pCT_WIDTH-1:0]         reg_crypt_cipherin;		//輸出到加密運算單元的密文reg  [pKEY_WIDTH-1:0]        reg_crypt_key;			//密鑰reg  [pPT_WIDTH-1:0]         reg_crypt_textin;		//輸出到加密運算單元的明文reg  [pPT_WIDTH-1:0]         reg_crypt_textout;		//來自加密運算單元的明文reg  [pCT_WIDTH-1:0]         reg_crypt_cipherout;	//來自加密運算單元的密文reg                          reg_crypt_go_pulse;		//用于生成加密啟動脈沖wire                         reg_crypt_go_pulse_crypt;//加密啟動脈沖1//狀態管理和信號同步reg                          busy_usb;reg                          done_r;wire                         done_pulse;wire                         crypt_go_pulse;		//加密啟動脈沖2reg                          go_r;reg                          go;wire [31:0]                  buildtime;			//保存構建時間//ASYNC_REG屬性用于跨時鐘域的信號同步(* ASYNC_REG = "TRUE" *) reg  [pKEY_WIDTH-1:0] reg_crypt_key_crypt;(* ASYNC_REG = "TRUE" *) reg  [pPT_WIDTH-1:0] reg_crypt_textin_crypt;(* ASYNC_REG = "TRUE" *) reg  [pPT_WIDTH-1:0] reg_crypt_textout_usb;(* ASYNC_REG = "TRUE" *) reg  [pCT_WIDTH-1:0] reg_crypt_cipherout_usb;(* ASYNC_REG = "TRUE" *) reg  [1:0] go_pipe;(* ASYNC_REG = "TRUE" *) reg  [1:0] busy_pipe;//時鐘域同步邏輯//在crypto_clk時鐘域中,處理I_done信號的邊沿檢測,并生成done_pulse信號always @(posedge crypto_clk) begindone_r <= I_done & pDONE_EDGE_SENSITIVE;endassign done_pulse = I_done & ~done_r;//在crypto_clk時鐘域中,將加密完成時的密文和明文數據存儲到reg_crypt_cipherout和reg_crypt_textout中always @(posedge crypto_clk) beginif (done_pulse) beginreg_crypt_cipherout <= I_cipherout;reg_crypt_textout   <= I_textout;endreg_crypt_key_crypt <= reg_crypt_key;reg_crypt_textin_crypt <= reg_crypt_textin;end//在usb_clk時鐘域中,將reg_crypt_cipherout和reg_crypt_textout同步到usb_clk時鐘域always @(posedge usb_clk) beginreg_crypt_cipherout_usb <= reg_crypt_cipherout;reg_crypt_textout_usb   <= reg_crypt_textout;end//將同步后的信號作為密碼運算單元的輸入assign O_textin = reg_crypt_textin_crypt;assign O_key = reg_crypt_key_crypt;assign O_start = crypt_go_pulse || reg_crypt_go_pulse_crypt;//讀寄存器邏輯,讀取結果會通過USB接口傳回電腦主機always @(*) beginif (reg_addrvalid && reg_read) begin //當reg_addrvalid和reg_read為高電平時開始讀寄存器case (reg_address)	//根據reg_address選擇讀取的數據是什么`REG_CLKSETTINGS:           reg_read_data = O_clksettings;	//讀加密時鐘設置寄存器`REG_USER_LED:              reg_read_data = O_user_led;		//讀用戶LED燈寄存器`REG_CRYPT_TYPE:            reg_read_data = pCRYPT_TYPE;	//讀加密類型`REG_CRYPT_REV:             reg_read_data = pCRYPT_REV;		//讀加密`REG_IDENTIFY:              reg_read_data = pIDENTIFY;		//讀標識符`REG_CRYPT_GO:              reg_read_data = busy_usb;		//讀加密運算單元是否繁忙//reg_bytecnt在此處指明讀取128位數據中的哪個字節//讀密鑰寄存器`REG_CRYPT_KEY:             reg_read_data = reg_crypt_key[reg_bytecnt*8 +: 8];//讀輸出到加密運算單元的明文寄存器`REG_CRYPT_TEXTIN:          reg_read_data = reg_crypt_textin[reg_bytecnt*8 +: 8];//讀輸出到加密運算單元的密文寄存器`REG_CRYPT_CIPHERIN:        reg_read_data = reg_crypt_cipherin[reg_bytecnt*8 +: 8];//讀來自加密運算單元的明文寄存器`REG_CRYPT_TEXTOUT:         reg_read_data = reg_crypt_textout_usb[reg_bytecnt*8 +: 8];//讀來自加密運算單元的密文寄存器`REG_CRYPT_CIPHEROUT:       reg_read_data = reg_crypt_cipherout_usb[reg_bytecnt*8 +: 8];//讀構建時間寄存器`REG_BUILDTIME:             reg_read_data = buildtime[reg_bytecnt*8 +: 8];default:                    reg_read_data = 0;endcaseendelsereg_read_data = 0;end//在usb_clk時鐘域中,將reg_read_data賦值給read_dataalways @(posedge usb_clk)read_data <= reg_read_data;//寫寄存器邏輯,將來自電腦主機的數據寫入寄存器always @(posedge usb_clk) beginif (reset_i) beginO_clksettings <= 0;O_user_led <= 0;reg_crypt_go_pulse <= 1'b0;endelse beginif (reg_addrvalid && reg_write) begin	//當reg_addrvalid和reg_write為高電平時開始寫寄存器case (reg_address)`REG_CLKSETTINGS:        O_clksettings <= write_data;	//寫加密時鐘設置寄存器`REG_USER_LED:           O_user_led <= write_data;		//寫用戶LED燈寄存器//寫輸出到加密運算單元的明文寄存器`REG_CRYPT_TEXTIN:       reg_crypt_textin[reg_bytecnt*8 +: 8] <= write_data;//寫輸出到加密運算單元的密文寄存器`REG_CRYPT_CIPHERIN:     reg_crypt_cipherin[reg_bytecnt*8 +: 8] <= write_data;//寫密鑰寄存器`REG_CRYPT_KEY:          reg_crypt_key[reg_bytecnt*8 +: 8] <= write_data;endcaseend//寫入REG_CRYPT_GO寄存器會生成一個脈沖信號,用于啟動加/解密和采波過程if ( (reg_addrvalid && reg_write && (reg_address == `REG_CRYPT_GO)) )reg_crypt_go_pulse <= 1'b1;elsereg_crypt_go_pulse <= 1'b0;endend//跨時鐘域同步邏輯//在crypto_clk時鐘域中,處理exttrigger_in信號的同步,并生成crypt_go_pulse信號always @(posedge crypto_clk) begin{go_r, go, go_pipe} <= {go, go_pipe, exttrigger_in};endassign crypt_go_pulse = go & !go_r;//使用cdc_pulse模塊將reg_crypt_go_pulse信號從usb_clk時鐘域同步到crypto_clk時鐘域cdc_pulse U_go_pulse (.reset_i       (reset_i),.src_clk       (usb_clk),.src_pulse     (reg_crypt_go_pulse),.dst_clk       (crypto_clk),.dst_pulse     (reg_crypt_go_pulse_crypt));//在usb_clk時鐘域中,將I_busy信號同步到busy_usbalways @(posedge usb_clk){busy_usb, busy_pipe} <= {busy_pipe, I_busy};//如果沒有定義__ICARUS__宏,則使用USR_ACCESSE2原語讀取構建時間`ifndef __ICARUS__USR_ACCESSE2 U_buildtime (.CFGCLK(),.DATA(buildtime),.DATAVALID());`else	//如果定義了__ICARUS__宏,則將buildtime信號賦值為0assign buildtime = 0;`endifendmodule`default_nettype wire	//恢復默認的網絡類型為wire

如果密碼運算單元還需要輸入其他數據,則需要新定義一個寄存器,添加寫該寄存器的邏輯,并將寄存器值經過同步后輸出。如果密碼運算單元會產生更多的輸出,同樣先新定義一個寄存器,在crypt_clk時鐘域獲取密碼運算單元的輸出,之后將寄存器的值同步到usb_clk時鐘域,并添加讀該寄存器的邏輯。最后,不要忘記在cw305_defines.v中添加寄存器地址的常量。

3. cw305_top.v

`timescale 1ns / 1ps	//設置仿真時間單位為1ns,精度為1ps
`default_nettype none	//設置沒有顯示聲明的網絡類型為none,編譯器會報錯,用于捕獲未聲明的信號//模塊聲明和參數化
module cw305_top #(parameter pBYTECNT_SIZE = 7,	//對寄存器進行字節計數的大小parameter pADDR_WIDTH = 21,		//寄存器地址的寬度parameter pPT_WIDTH = 128,		//明文寬度parameter pCT_WIDTH = 128,		//密文寬度parameter pKEY_WIDTH = 128		//密鑰寬度
)(//USB接口input wire                          usb_clk,        //USB時鐘inout wire [7:0]                    usb_data,       //USB數據,用于讀寫操作input wire [pADDR_WIDTH-1:0]        usb_addr,       //USB地址input wire                          usb_rdn,        //USB讀信號input wire                          usb_wrn,        //USB寫信號input wire                          usb_cen,        //USB片選信號input wire                          usb_trigger,    //觸發信號//CW305目標板上DIP開關、按鈕和LED燈input wire                          j16_sel,        //DIP開關輸入input wire                          k16_sel,        //DIP開關輸入input wire                          k15_sel,        //DIP開關輸入input wire                          l14_sel,        //DIP開關輸入input wire                          pushbutton,     //復位按鈕output wire                         led1,           //紅色LED輸出output wire                         led2,           //綠色LED輸出output wire                         led3,           //藍色LED輸出//PLLinput wire                          pll_clk1,       //PLL時鐘通道1//input wire                        pll_clk2,       //PLL時鐘通道2(本例中未使用)//20針連接器信號output wire                         tio_trigger,	//輸出到外部的觸發信號(本例為密碼運算單元繁忙信號)output wire                         tio_clkout,		//輸出到外部的密碼運算單元時鐘input  wire                         tio_clkin		//外部時鐘);wire [pKEY_WIDTH-1:0] crypt_key;		//密鑰wire [pPT_WIDTH-1:0] crypt_textout;		//加密運算單元的輸入明文wire [pCT_WIDTH-1:0] crypt_cipherin;	//加密運算單元的輸出密文//加密狀態信號wire crypt_ready;wire crypt_start;wire crypt_done;wire crypt_busy;//USB和寄存器相關的信號wire usb_clk_buf;wire [7:0] usb_dout;wire isout;wire [pADDR_WIDTH-pBYTECNT_SIZE-1:0] reg_address;wire [pBYTECNT_SIZE-1:0] reg_bytecnt;wire reg_addrvalid;wire [7:0] write_data;wire [7:0] read_data;wire reg_read;wire reg_write;wire [4:0] clk_settings;wire crypt_clk;  //復位信號wire resetn = pushbutton;wire reset = !resetn;//生成USB時鐘的心跳信號(通過觀察CW305目標板的紅色LED燈是否閃爍來判斷USB時鐘是否正常)reg [24:0] usb_timer_heartbeat;always @(posedge usb_clk_buf) usb_timer_heartbeat <= usb_timer_heartbeat +  25'd1;assign led1 = usb_timer_heartbeat[24];//生成加密時鐘的心跳信號(通過觀察CW305目標板的綠色LED燈是否閃爍來判斷加密時鐘是否正常)reg [22:0] crypt_clk_heartbeat;always @(posedge crypt_clk) crypt_clk_heartbeat <= crypt_clk_heartbeat +  23'd1;assign led2 = crypt_clk_heartbeat[22];//實例化cw305_usb_reg_fe模塊,處理USB接口的寄存器讀寫操作cw305_usb_reg_fe #(.pBYTECNT_SIZE           (pBYTECNT_SIZE),.pADDR_WIDTH             (pADDR_WIDTH)) U_usb_reg_fe (.rst                     (reset),.usb_clk                 (usb_clk_buf), .usb_din                 (usb_data), .usb_dout                (usb_dout), .usb_rdn                 (usb_rdn), .usb_wrn                 (usb_wrn),.usb_cen                 (usb_cen),.usb_alen                (1'b0),                 // unused.usb_addr                (usb_addr),.usb_isout               (isout), .reg_address             (reg_address), .reg_bytecnt             (reg_bytecnt), .reg_datao               (write_data), .reg_datai               (read_data),.reg_read                (reg_read), .reg_write               (reg_write), .reg_addrvalid           (reg_addrvalid));//AES寄存器模塊實例化,處理與AES加密相關的寄存器操作cw305_reg_aes #(.pBYTECNT_SIZE           (pBYTECNT_SIZE),.pADDR_WIDTH             (pADDR_WIDTH),.pPT_WIDTH               (pPT_WIDTH),.pCT_WIDTH               (pCT_WIDTH),.pKEY_WIDTH              (pKEY_WIDTH)) U_reg_aes (.reset_i                 (reset),.crypto_clk              (crypt_clk),.usb_clk                 (usb_clk_buf), .reg_address             (reg_address[pADDR_WIDTH-pBYTECNT_SIZE-1:0]), .reg_bytecnt             (reg_bytecnt), .read_data               (read_data), .write_data              (write_data),.reg_read                (reg_read), .reg_write               (reg_write), .reg_addrvalid           (reg_addrvalid),.exttrigger_in           (usb_trigger),.I_textout               (128'b0),.I_cipherout             (crypt_cipherin),.I_ready                 (crypt_ready),.I_done                  (crypt_done),.I_busy                  (crypt_busy),.O_clksettings           (clk_settings),.O_user_led              (led3),.O_key                   (crypt_key),.O_textin                (crypt_textout),.O_cipherin              (),.O_start                 (crypt_start));//根據isout信號的值,控制usb_data總線的方向assign usb_data = isout? usb_dout : 8'bZ;//實例化clocks模塊,處理時鐘選擇和輸出clocks U_clocks (.usb_clk                 (usb_clk),.usb_clk_buf             (usb_clk_buf),.I_j16_sel               (j16_sel),.I_k16_sel               (k16_sel),.I_clock_reg             (clk_settings),.I_cw_clkin              (tio_clkin),.I_pll_clk1              (pll_clk1),.O_cw_clkout             (tio_clkout),.O_cryptoclk             (crypt_clk));//AES運算單元輸入輸出信號定義wire aes_clk;wire [127:0] aes_key;wire [127:0] aes_pt;wire [127:0] aes_ct;wire aes_load;wire aes_busy;assign aes_clk = crypt_clk;assign aes_key = crypt_key;assign aes_pt = crypt_textout;assign crypt_cipherin = aes_ct;assign aes_load = crypt_start;assign crypt_ready = 1'b1;assign crypt_done = ~aes_busy;assign crypt_busy = aes_busy;//AES運算單元實例化aes_core (.clk(aes_clk),.load(aes_load),.mkey(aes_key),.pt(aes_pt),.ct(aes_ct),.busy(aes_busy));//將aes_busy信號連接到tio_trigger輸出端口assign tio_trigger = aes_busy;endmodule`default_nettype wire	//恢復默認的網絡類型為wire

可見,這三個文件是相互配合的,編寫分組密碼算法時,不需要改動太多,只需要修改頂層模塊,以及明密文的位寬參數。當編寫更復雜的算法時,需要重新編寫這三個文件,不過ChiWhipserer官方已經給出了AES流水線實現的ECC實現示例,用戶可在此基礎上進行修改。

三、采集代碼編寫

采集代碼為運行在jupyter notebook上的代碼,ChipWhipserer官方已經給了非常詳細的說明,下載網址為https://github.com/newaetech/chipwhisperer-jupyter?。這里給一個比較標準的CW305目標板采集模板,并進行補充說明。

#連接捕獲板,并進行一些初始設置(比較固定,一般不變)
import chipwhisperer as cw
scope = cw.scope()
scope.adc.basic_mode = "rising_edge"	#上升沿觸發
scope.trigger.triggers = "tio4"			#觸發信號為目標板20針SMA接口的IO4
scope.io.tio1 = "serial_rx"				#目標板20針SMA接口的IO1用于UART接收
scope.io.tio2 = "serial_tx"				#目標板20針SMA接口的IO2用于UART發送
scope.io.hs2 = "disabled"				#目標板20針SMA接口的HS2置為高阻態
#本文采用的是CW305-35t的目標板
TARGET_PLATFORM = 'CW305_35t'
fpga_id = '35t'#比特流文件的路徑
bit_file=r"D:\mycode\vivado\aes_normal\bitfile\cw305_top.bit"#連接目標板,并將比特流文件燒寫到FPGA
target = cw.target(scope, cw.targets.CW305, force=True, fpga_id=fpga_id,bsfile=bit_file)
#設置VCC-INT電壓為1V,VCC-INT是內部邏輯電路的供電電壓
target.vccint_set(1.0)
#僅啟用PLL1,作為密碼運行執行單元的時鐘信號
target.pll.pll_enable_set(True)
target.pll.pll_outenable_set(False, 0)
target.pll.pll_outenable_set(True, 1)
target.pll.pll_outenable_set(False, 2)
#設置PLL1的頻率為10MHz(可設置為5MHz-160MHz)
target.pll.pll_outfreq_set(10E6, 1)
#設置在加密運行單元執行過程中自動關閉USB時鐘,以減少噪聲
target.clkusbautooff = True
#設置USB時鐘在任務完成后1毫秒進入睡眠模式
target.clksleeptime = 1#確保ADC(模數轉換器)的時鐘源來自FPGA而不是內部時鐘,可以提高數據采集的精度和穩定性
if scope._is_husky:scope.clock.clkgen_src = 'extclk'
else:scope.clock.adc_src = "extclk_x4"#確保DCM(數字時鐘管理器)鎖定
import time
for i in range(5):scope.clock.reset_adc()time.sleep(0.5)if scope.clock.adc_locked:break 
assert (scope.clock.adc_locked), "ADC failed to lock"
#這里可以對一些捕獲板的參數進行設置
scope.clock.adc_mul=10		#每個時鐘周期采集的點數,默認為4
scope.gain.db=20			#低噪聲放大器的增益,默認為25,當波形失真時可以減小該值,一般在[0,25]之間調整
scope.adc.samples = 1000	#采樣點數
scope.adc.offset =0			#采樣位置的偏移
'''
#波形的采集1
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
plaintext=bytearray([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
key=bytearray([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])#官方教程中均采用類似于下面的封裝函數capture_trace進行采波
trs = cw.capture_trace(scope, target, plaintext, key)
print("plaintext:",trs.textin.hex())
print("key:",trs.key.hex())
print("ciphertext:",trs.textout.hex())
plt.plot(np.array(trs.wave))
plt.show()
'''
#波形的采集2
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
plaintext=bytearray([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
key=bytearray([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])#本文建設使用更底層的函數進行采集,以便理解如何對其他類型密碼算法進行采波
#首先根據cw305_defines.v文件對target類中的寄存器地址進行設置(用戶可根據實際情況設置更多的地址)
target.REG_CRYPT_KEY = 0x0a
target.REG_CRYPT_TEXTIN = 0x06
target.REG_CRYPT_GO = 0x05
target.REG_USER_LED = 0x01
target.REG_CRYPT_CIPHEROUT = 0x09
target.REG_BUILDTIME = 0x0b
target.REG_CRYPT_TYPE = 0x02
target.REG_CRYPT_REV = 0x03#寫入密鑰,注意寫入數據均需要先逆序
key = key[::-1]	#逆序操作
target.fpga_write(target.REG_CRYPT_KEY, key)#寫入明文
plaintext = plaintext[::-1]
target.fpga_write(target.REG_CRYPT_TEXTIN, plaintext)#開始采波
scope.arm()
target.go()
ret = scope.capture()
if ret:print("Failed capture")
wave = scope.get_last_trace()#讀取密文
ciphertext = target.fpga_read(target.REG_CRYPT_CIPHEROUT, 16)
ciphertext = ciphertext[::-1]#輸出結果
print(ciphertext.hex())
plt.plot(np.array(wave))
plt.show()

從上面的程序可以看出,軟件與硬件部分最關鍵的聯系便是寄存器地址,這對于理解整個工作流程,以及擴展自己的密碼算法比較重要。如果擴展密碼算法比較復雜,可以參考ECC和AES流水線實現的示例,編寫一個單獨的采集腳本。

#開始正式采波from tqdm.notebook import trange
import numpy as np#可以根據上面的觀察結果重新調整采集的點數和偏移
scope.adc.samples = 2000
scope.adc.offset =0#根據cw305_defines.v文件對target類中的寄存器地址進行設置
target.REG_CRYPT_KEY = 0x0a
target.REG_CRYPT_TEXTIN = 0x06
target.REG_CRYPT_GO = 0x05
target.REG_USER_LED = 0x01
target.REG_CRYPT_CIPHEROUT = 0x09
target.REG_BUILDTIME = 0x0b
target.REG_CRYPT_TYPE = 0x02
target.REG_CRYPT_REV = 0x03#采集60000條曲線
N=60000
plaintext=[]
ciphertext=[]
traces=[]#寫入密鑰,注意寫入數據均需要先逆序
key=bytearray([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
key = key[::-1]	#逆序操作
target.fpga_write(target.REG_CRYPT_KEY, key)#開始采集
for i in trange(N, desc='Capturing traces'):plain=np.random.randint(256,size=16,dtype=np.uint8)	#生成一個16字節隨機明文plaintext.append(plain)plain= plain[::-1]target.fpga_write(target.REG_CRYPT_TEXTIN, plain)scope.arm()target.go()ret = scope.capture()if ret:print("Failed capture")wave = scope.get_last_trace()traces.append(wave)cipher= target.fpga_read(target.REG_CRYPT_CIPHEROUT, 16)cipher = cipher[::-1]ciphertext.append(np.array(cipher,dtype=np.uint8))
#保存采集結果,建議均保存為.npy文件,讀寫速度較快,且可以直接讀取為numpy數組,無需二次轉化
#如果需要和其他非python程序交互,建議保存為二進制文件,如果保存為txt、csv等文本類型,則保存和讀取速度均較慢#保存能量曲線
traces_path="D:/WMD_DATA/aes_normal_traces.npy"
np.save(traces_path,np.array(traces))#保存明文
plaintext_path="D:/WMD_DATA/aes_normal_plaintext.npy"
np.save(plaintext_path,np.array(plaintext,np.uint8))#保存密文
ciphertext_path="D:/WMD_DATA/aes_normal_ciphertext.npy"
np.save(ciphertext_path,np.array(ciphertext,np.uint8))
#每次采集完畢記得斷開和板子的連接
#如果不執行下面的函數,在其他jupyter notebook文件中連接時會出錯,此時需要將板子斷電
scope.dis()
target.dis()

四、補充

如果想直接將保存的數據保存為.trs格式的文件,需要進行以下步驟:

1. 安裝trsfile庫

在jupyter notebook文件中,執行下面的命令:

%%sh
pip install --upgrade pip	#更新pip
pip install trsfile			#安裝trsfile庫

當然也可以直接打開ChipWhisperer Bash,然后執行pip install trsfile,執行后記得重啟ChipWhisperer。

2. 將數據寫入.trs文件的模板函數

import os
import numpy as np
from trsfile import trs_open, Trace, SampleCoding, Header
from trsfile.parametermap import TraceParameterMap, TraceParameterDefinitionMap
from trsfile.traceparameter import ParameterType, TraceParameterDefinition_type_to_ParameterType={'bool':'BOOL','int8':'BYTE','uint8':'BYTE','int16':'SHORT','uint16':'SHORT','int32':'INT','uint32':'INT','int64':'LONG','uint64':'LONG','float16':'FLOAT','float32':'FLOAT','float64':'DOUBLE','str':'STRING','bytes':'STRING'
}
_type_to_SampleCoding = {"int8": 'BYTE', "uint8": 'BYTE',"int16": 'SHORT', "uint16": 'SHORT',"int32": 'INT', "uint32": 'INT',"int64": 'INT', "uint64": 'INT',"float32": 'FLOAT', "float64": 'FLOAT'
}def save_trs(header,traces,param:dict, trs_file_path:str):header = {Header[key]: value for key, value in header.items()}parameter_def,param_offset = {},0for key in param:param[key]=np.array(param[key],np.uint8)param_len=param[key].shape[1]param_type=ParameterType[_type_to_ParameterType[param[key].dtype.name]]parameter_def[key] = TraceParameterDefinition(param_type, param_len, param_offset)param_offset += param_len*param_type.byte_sizeheader[Header.LENGTH_DATA] = param_offsetheader[Header.TRACE_PARAMETER_DEFINITIONS] = TraceParameterDefinitionMap(parameter_def)if not isinstance(traces,np.ndarray):traces=np.array(traces)if traces.dtype.name.endswith('64'):traces_type_new=traces.dtype.name.replace('64','32')traces=np.array(traces,np.dtype(traces_type_new))trs_type=SampleCoding[_type_to_SampleCoding[traces.dtype.name]]if os.path.exists(trs_file_path):os.remove(trs_file_path)header[Header.NUMBER_TRACES]=0with trs_open(trs_file_path,'w',headers=header,live_update=True) as trs_file:for i in range(traces.shape[0]):trs_param={}for key,value in parameter_def.items():trace_parameter=value.param_type.param_classtrs_param[key]=trace_parameter(param[key][i])trs_file.extend(Trace(trs_type,traces[i],TraceParameterMap(trs_param)))

該函數較長,且一般無需更改,可以將其保存為一個文件,本文命名為trsfile_save.py,保存在D:/mycode/chipwhisperer/utils下。

3. 修改jupyter notebook中的保存文件部分

%run D:/mycode/chipwhisperer/utils/trsfile_save.py #通過魔法函數%run執行trsfile_save.py文件#定義trs文件保存路徑
trsfile_path="D:/WMD_DATA/cw305_aes_normal.trs"#創建trs文件的頭,里面可以定義一些有用的信息,具體可通過執行help(Header)查看
header={#這里定義了其中的'DESCRIPTION'參數,指明了采集目標,以及主密鑰'DESCRIPTION':'target: cw305, AES normal; main key:0x0123456789abcdeffedcba9876543210'#用戶還可以定義其他的一些參數,不過‘NUMBER_TRACES’,'NUMBER_SAMPLES'等參數無需聲明,會自動生成
} #定義trs文件的param數據,param為一個字典,其中保存和能量跡一一對應的數據,如明文、密文、掩碼等
param={'plaintext': plaintext,'ciphertext': ciphertext
}#調用save_trs函數進行保存
save_trs(header,traces,param,trsfile_path)

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83612.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83612.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83612.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

django中如何解析content-type=application/json的請求

django中如何解析content-typeapplication/json的請求 本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 往期文章回顧: …

Chainlink VRF 深度解析與實戰

背景 在區塊鏈的去中心化應用中&#xff0c;隨機性是一個常見但難以實現的需求。例如&#xff0c;區塊鏈游戲需要隨機決定戰斗結果&#xff0c;NFT 項目需要隨機分配稀有屬性&#xff0c;去中心化抽獎需要公平選擇獲獎者。然而&#xff0c;傳統的鏈上隨機數生成方法&#xff0…

7. TypeScript接口

TypeScript 中的接口&#xff08;Interfaces&#xff09;用于定義對象的結構。它們允許開發者指定一個對象應具有哪些屬性以及這些屬性的類型。接口有助于確保對象遵循特定的結構&#xff0c;從而在整個應用中提供一致性&#xff0c;并提升代碼的可維護性。 一、認識接口 Typ…

UE 新版渲染器輸出視頻

安裝包解壓到C盤 打開UE插件 Movie Render Queue 進入UE引擎在項目設置找到 libx264 aac mp4 影片渲染隊列調用出 命令行編碼器安裝包路徑&#xff0c;序列輸出路徑&#xff0c;定序器不能有中文

基于用戶的協同過濾推薦算法實現(Java電商平臺)

在電商平臺中&#xff0c;基于用戶的協同過濾推薦算法是一種常見的推薦系統方法。它通過分析用戶之間的相似性來推薦商品。以下是一個簡單的實現思路和示例代碼&#xff0c;使用Java語言。 實現思路 數據準備&#xff1a;收集用戶的評分數據&#xff0c;通常以用戶-商品評分矩…

LeetCode - 904. 水果成籃

題目 904. 水果成籃 - 力扣&#xff08;LeetCode&#xff09; 思路 題目本質 你有一個整數數組&#xff0c;每個元素代表一種水果。你只能用兩個籃子&#xff0c;每個籃子只能裝一種水果。你要在數組中找一個最長的連續子數組&#xff0c;這個子數組里最多只包含兩種不同的…

發現 Kotlin MultiPlatform 的一點小變化

最近發現 Kotlin 官方已經開始首推 Idea 的社區版的 KMP 插件了. 以前有網頁創建 KMP 的項目的文檔也消失了. 雖然有 Android Studio 的選項. 但是卻不是在默認的位置上了. 足以說明官方是有意想讓大家直接使用 Idea 社區版或者專業版 所以我直接在社區版上安裝 KMP 插件. 嘗試…

【Photoshop】金屬字體制作

新建一個空白項目&#xff0c;選擇橫排文字工具&#xff0c;輸入想要的文件建立文字圖層 選擇橫排文字工具選擇出文字內容&#xff0c;在通知欄出點擊’拾色器‘&#xff0c;設置好需要的文字顏色 圖層面板右下角點擊‘添加圖層樣式’&#xff0c;選擇斜面和浮雕 樣式設置為內斜…

centos 7.9 升級ssh版本 7.4p1 升級到 8.2p1

centos 7.9 升級ssh版本 7.4p1 升級到 8.2p1 1、安裝包下載2、安裝telnet3、安裝openssl-OpenSSL_1_1_1f.tar.gz4、安裝openssh-8.2p1.tar.gz5、修改ssh服務的相關配置文件6、確定可以ssh連接服務器后&#xff0c;卸載telnet&#xff0c;因為telnet不安全 本文是離線環境下升級…

stm32---dma串口發送+fifo隊列框架

之前分享了一個關于gd32的fifo框架&#xff0c;這次就用stm32仿照寫一個&#xff0c;其實幾乎一樣&#xff0c;這次說的更詳細點&#xff0c;我全文都寫上了注釋&#xff0c;大家直接cv模仿我的調用方式即可 uasrt.c #include "stm32f10x.h" // D…

【生產就曲篇】讓應用可觀測:Actuator監控端點與日志最佳實踐

摘要 本文是《Spring Boot 實戰派》系列的終章&#xff0c;我們將探討如何讓應用真正達到**“生產就緒” (Production-Ready)** 的標準。文章的核心是可觀測性 (Observability)&#xff0c;即從外部了解一個系統內部運行狀態的能力。 我們將深度挖掘 Spring Boot Actuator 的…

操作系統知識(1)

操作系統的分類總結 1、批處理操作系統:單道批處理和多道批處理(主機與外設可并行) 2、分時操作系統:一個計算機系統與多個終端設備連接。將CPU的工作時間劃分為許多很短的時間片&#xff0c;輪流為各個終端的用戶服務。 3、實時操作系統:實時是指計算機對于外來信息能夠以足…

一.Sharding分庫分表-基因法+自定義多key分片實現多字段查詢

前言 當下遇到這樣一個場景&#xff0c;由于訂單數據量達到千萬級別&#xff0c;采用分庫分表進行優化&#xff0c;根據訂單的熱查條件&#xff1a;order_no訂單編號進行分表&#xff0c;但是這樣帶來一個問題&#xff0c;用戶查詢自己的訂單怎么查&#xff1f;由于分片鍵使用…

【leetcode】543. 二叉樹的直徑

二叉樹的直徑 題目題解解釋 題目 543. 二叉樹的直徑 給你一棵二叉樹的根節點&#xff0c;返回該樹的 直徑 。 二叉樹的 直徑 是指樹中任意兩個節點之間最長路徑的 長度 。這條路徑可能經過也可能不經過根節點 root 。 兩節點之間路徑的 長度 由它們之間邊數表示。 題解 …

AI基礎知識(07):基于 PyTorch 的手寫體識別案例手冊

目錄 實驗介紹 實驗對象 實驗時間 實驗流程 實驗介紹 隨著人工智能技術的飛速發展&#xff0c;圖像識別技術在眾多領域得到了廣泛應用。手寫體識別作為圖像 識別的一個重要分支&#xff0c;其在教育、金融、醫療等領域具有廣泛的應用前景。本實驗旨在利用深度 學習框架 PyTorc…

wordpress后臺更新后 前端沒變化的解決方法

使用siteground主機的wordpress網站&#xff0c;會出現更新了網站內容和修改了php模板文件、js文件、css文件、圖片文件后&#xff0c;網站沒有變化的情況。 不熟悉siteground主機的新手&#xff0c;遇到這個問題&#xff0c;就很抓狂&#xff0c;明明是哪都沒操作錯誤&#x…

信號(瞬時)頻率求解與仿真實踐(2)

引言 本文是信號(瞬時)頻率求解與仿真實踐專題的第二篇文章&#xff0c;在上一篇博文 [1]信號(瞬時)頻率求解與仿真實踐(1)-CSDN博客中&#xff0c;我構建了信號瞬時頻率求解的基本框架&#xff0c;并且比較詳細地討論了瞬時頻率法。這篇博文探討適用于信號瞬時頻率求解的另一種…

Linux運行發布jar文件攜帶哪些參數

在 CentOS 8 上運行發布的 JAR 文件時,可以根據不同需求攜帶以下參數: 1. 基本運行方式 bash 復制 下載 java -jar your-application.jar 2. 常用 JVM 參數 參數說明-Xms256m初始堆內存大小(如 256MB)-Xmx1024m最大堆內存大小(如 1GB)-XX:MaxMetaspaceSize=256m元空間…

在GIS 工作流中實現數據處理(4)

結果輸出與可視化 最后&#xff0c;我們將統計結果輸出為一個 Excel 文件&#xff0c;并在 ArcMap 中對城市中心區域的土地利用情況進行可視化展示。 import pandas as pd# 將統計表格轉換為 pandas DataFrame df pd.read_csv(statistics_table, sep"\t")# 輸出為…

【術語解釋】網絡安全((SAST, DAST, SCA, IAST),Hadoop, Spark, Hive 的關系

## OWASP Top 10等 OWASP Top 10&#xff1a;OWASP (Open Worldwide Application Security Project&#xff0c;開放全球應用程序安全項目) Top 10 是一份由全球安全專家定期更新的報告&#xff0c;列出了當前 Web 應用程序面臨的十大最關鍵安全風險。 它是一個廣受認可的意識文…