//====================================================================== // // aes_encipher_block.v // -------------------- // The AES encipher round. A pure combinational module that implements // the initial round, main round and final round logic for // enciper operations. // // // Author: Joachim Strombergson // Copyright (c) 2014, NORDUnet A/S // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // - Neither the name of the NORDUnet nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //====================================================================== module aes_encipher_block( input wire clk, input wire reset_n, input wire next, input wire keylen, output wire [3 : 0] round, input wire [127 : 0] round_key, input wire [127 : 0] block, output wire [127 : 0] new_block, output wire ready ); //---------------------------------------------------------------- // Internal constant and parameter definitions. //---------------------------------------------------------------- localparam AES_128_BIT_KEY = 1'h0; localparam AES_256_BIT_KEY = 1'h1; localparam AES128_ROUNDS = 4'ha; localparam AES256_ROUNDS = 4'he; localparam NO_UPDATE = 2'h0; localparam INIT_UPDATE = 2'h1; localparam MAIN_UPDATE = 2'h2; localparam FINAL_UPDATE = 2'h3; localparam CTRL_IDLE = 2'h0; localparam CTRL_INIT = 2'h1; localparam CTRL_MAIN = 2'h2; //---------------------------------------------------------------- // Round functions with sub functions. //---------------------------------------------------------------- function [7 : 0] gm2(input [7 : 0] op); begin gm2 = {op[6 : 0], 1'b0} ^ (8'h1b & {8{op[7]}}); end endfunction // gm2 function [7 : 0] gm3(input [7 : 0] op); begin gm3 = gm2(op) ^ op; end endfunction // gm3 function [31 : 0] mixw(input [31 : 0] w); reg [7 : 0] b0, b1, b2, b3; reg [7 : 0] mb0, mb1, mb2, mb3; begin b0 = w[31 : 24]; b1 = w[23 : 16]; b2 = w[15 : 08]; b3 = w[07 : 00]; mb0 = gm2(b0) ^ gm3(b1) ^ b2 ^ b3; mb1 = b0 ^ gm2(b1) ^ gm3(b2) ^ b3; mb2 = b0 ^ b1 ^ gm2(b2) ^ gm3(b3); mb3 = gm3(b0) ^ b1 ^ b2 ^ gm2(b3); mixw = {mb0, mb1, mb2, mb3}; end endfunction // mixw function [127 : 0] mixcolumns(input [127 : 0] data); reg [31 : 0] w0, w1, w2, w3; reg [31 : 0] ws0, ws1, ws2, ws3; begin w0 = data[127 : 096]; w1 = data[095 : 064]; w2 = data[063 : 032]; w3 = data[031 : 000]; ws0 = mixw(w0); ws1 = mixw(w1); ws2 = mixw(w2); ws3 = mixw(w3); mixcolumns = {ws0, ws1, ws2, ws3}; end endfunction // mixcolumns function [127 : 0] shiftrows(input [127 : 0] data); reg [31 : 0] w0, w1, w2, w3; reg [31 : 0] ws0, ws1, ws2, ws3; begin w0 = data[127 : 096]; w1 = data[095 : 064]; w2 = data[063 : 032]; w3 = data[031 : 000]; ws0 = {w0[31 : 24], w1[23 : 16], w2[15 : 08], w3[07 : 00]}; ws1 = {w1[31 : 24], w2[23 : 16], w3[15 : 08], w0[07 : 00]}; ws2 = {w2[31 : 24], w3[23 : 16], w0[15 : 08], w1[07 : 00]}; ws3 = {w3[31 : 24], w0[23 : 16], w1[15 : 08], w2[07 : 00]}; shiftrows = {ws0, ws1, ws2, ws3}; end endfunction // shiftrows function [127 : 0] addroundkey(input [127 : 0] data, input [127 : 0] rkey); begin addroundkey = data ^ rkey; end endfunction // addroundkey //---------------------------------------------------------------- // Registers including update variables and write enable. //---------------------------------------------------------------- reg [127 : 0] block_reg; reg [127 : 0] block_new; reg block_we; reg [3 : 0] round_ctr_reg; reg [3 : 0] round_ctr_new; reg round_ctr_we; reg round_ctr_rst; reg round_ctr_inc; reg ready_reg; reg ready_new; reg ready_we; reg [1 : 0] enc_ctrl_reg; reg [1 : 0] enc_ctrl_new; reg enc_ctrl_we; //---------------------------------------------------------------- // Wires. //---------------------------------------------------------------- reg [1 : 0] update_type; reg [31 : 0] sboxw0; reg [31 : 0] sboxw1; reg [31 : 0] sboxw2; reg [31 : 0] sboxw3; wire [31 : 0] new_sboxw0; wire [31 : 0] new_sboxw1; wire [31 : 0] new_sboxw2; wire [31 : 0] new_sboxw3; //---------------------------------------------------------------- // Concurrent connectivity for ports etc. //---------------------------------------------------------------- assign new_block = block_reg; assign round = round_ctr_reg; assign ready = ready_reg; //---------------------------------------------------------------- // Sboxes //---------------------------------------------------------------- aes_sbox sbox_inst0(.sboxw(sboxw0), .new_sboxw(new_sboxw0)); aes_sbox sbox_inst1(.sboxw(sboxw1), .new_sboxw(new_sboxw1)); aes_sbox sbox_inst2(.sboxw(sboxw2), .new_sboxw(new_sboxw2)); aes_sbox sbox_inst3(.sboxw(sboxw3), .new_sboxw(new_sboxw3)); //---------------------------------------------------------------- // reg_update // // Update functionality for all registers in the core. // All registers are positive edge triggered with asynchronous // active low reset. All registers have write enable. //---------------------------------------------------------------- always @ (posedge clk or negedge reset_n) begin: reg_update if (!reset_n) begin block_reg <= 128'h0; round_ctr_reg <= 4'h0; ready_reg <= 1'b1; enc_ctrl_reg <= CTRL_IDLE; end else begin if (block_we) block_reg <= block_new; if (round_ctr_we) round_ctr_reg <= round_ctr_new; if (ready_we) ready_reg <= ready_new; if (enc_ctrl_we) enc_ctrl_reg <= enc_ctrl_new; end end // reg_update //---------------------------------------------------------------- // round_logic // // The logic needed to implement init, main and final rounds. //---------------------------------------------------------------- always @* begin : round_logic reg [127 : 0] subbytes_block, shiftrows_block, mixcolumns_block; reg [127 : 0] addkey_init_block, addkey_main_block, addkey_final_block; block_new = 128'h0; block_we = 1'b0; sboxw0 = block_reg[127 : 96]; sboxw1 = block_reg[95 : 64]; sboxw2 = block_reg[63 : 32]; sboxw3 = block_reg[31 : 0]; subbytes_block = {new_sboxw0, new_sboxw1, new_sboxw2, new_sboxw3}; shiftrows_block = shiftrows(subbytes_block); mixcolumns_block = mixcolumns(shiftrows_block); addkey_init_block = addroundkey(block, round_key); addkey_main_block = addroundkey(mixcolumns_block, round_key); addkey_final_block = addroundkey(shiftrows_block, round_key); case (update_type) INIT_UPDATE: begin block_new = addkey_init_block; block_we = 1'b1; end MAIN_UPDATE: begin block_new = addkey_main_block; block_we = 1'b1; end FINAL_UPDATE: begin block_new = addkey_final_block; block_we = 1'b1; end default: begin end endcase // case (update_type) end // round_logic //---------------------------------------------------------------- // round_ctr // // The round counter with reset and increase logic. //---------------------------------------------------------------- always @* begin : round_ctr round_ctr_new = 4'h0; round_ctr_we = 1'b0; if (round_ctr_rst) begin round_ctr_new = 4'h0; round_ctr_we = 1'b1; end else if (round_ctr_inc) begin round_ctr_new = round_ctr_reg + 1'b1; round_ctr_we = 1'b1; end end // round_ctr //---------------------------------------------------------------- // encipher_ctrl // // The FSM that controls the encipher operations. //---------------------------------------------------------------- always @* begin: encipher_ctrl reg [3 : 0] num_rounds; if (keylen == AES_256_BIT_KEY) num_rounds = AES256_ROUNDS; else num_rounds = AES128_ROUNDS; round_ctr_inc = 1'b0; round_ctr_rst = 1'b0; ready_new = 1'b0; ready_we = 1'b0; update_type = NO_UPDATE; enc_ctrl_new = CTRL_IDLE; enc_ctrl_we = 1'b0; case(enc_ctrl_reg) CTRL_IDLE: begin if (next) begin round_ctr_rst = 1'b1; ready_new = 1'b0; ready_we = 1'b1; enc_ctrl_new = CTRL_INIT; enc_ctrl_we = 1'b1; end end CTRL_INIT: begin round_ctr_inc = 1'b1; update_type = INIT_UPDATE; enc_ctrl_new = CTRL_MAIN; enc_ctrl_we = 1'b1; end CTRL_MAIN: begin round_ctr_inc = 1'b1; if (round_ctr_reg < num_rounds) begin update_type = MAIN_UPDATE; end else begin update_type = FINAL_UPDATE; ready_new = 1'b1; ready_we = 1'b1; enc_ctrl_new = CTRL_IDLE; enc_ctrl_we = 1'b1; end end default: begin // Empty. Just here to make the synthesis tool happy. end endcase // case (enc_ctrl_reg) end // encipher_ctrl endmodule // aes_encipher_block //====================================================================== // EOF aes_encipher_block.v //======================================================================