//====================================================================== // // aes_key_mem.v // ------------- // The AES key memort including round key generator. // // // Author: Joachim Strombergson // Copyright (c) 2014, SUNET // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the following // conditions are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. 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. // // 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 OWNER 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_key_mem( input wire clk, input wire reset_n, input wire [255 : 0] key, input wire keylen, input wire init, input wire [3 : 0] round, output wire [127 : 0] round_key, output wire ready, output wire [31 : 0] sboxw, input wire [31 : 0] new_sboxw ); //---------------------------------------------------------------- // Parameters. //---------------------------------------------------------------- parameter AES_128_BIT_KEY = 1'h0; parameter AES_256_BIT_KEY = 1'h1; parameter AES_128_NUM_ROUNDS = 4'ha; parameter AES_256_NUM_ROUNDS = 4'he; parameter CTRL_IDLE = 3'h0; parameter CTRL_INIT = 3'h1; parameter CTRL_GENERATE = 3'h2; parameter CTRL_DONE = 3'h3; //---------------------------------------------------------------- // Registers. //---------------------------------------------------------------- reg [127 : 0] key_mem [0 : 14]; reg [127 : 0] key_mem_new; reg key_mem_we; reg [127 : 0] prev_key0_reg; reg [127 : 0] prev_key0_new; reg prev_key0_we; reg [127 : 0] prev_key1_reg; reg [127 : 0] prev_key1_new; reg prev_key1_we; reg [3 : 0] round_ctr_reg; reg [3 : 0] round_ctr_new; reg round_ctr_rst; reg round_ctr_inc; reg round_ctr_we; reg [2 : 0] key_mem_ctrl_reg; reg [2 : 0] key_mem_ctrl_new; reg key_mem_ctrl_we; reg ready_reg; reg ready_new; reg ready_we; reg [7 : 0] rcon_reg; reg [7 : 0] rcon_new; reg rcon_we; reg rcon_set; reg rcon_next; //---------------------------------------------------------------- // Wires. //---------------------------------------------------------------- reg [31 : 0] tmp_sboxw; reg round_key_update; reg [3 : 0] num_rounds; reg [127 : 0] tmp_round_key; //---------------------------------------------------------------- // Concurrent assignments for ports. //---------------------------------------------------------------- assign round_key = tmp_round_key; assign ready = ready_reg; assign sboxw = tmp_sboxw; //---------------------------------------------------------------- // 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 key_mem [0] <= 128'h00000000000000000000000000000000; key_mem [1] <= 128'h00000000000000000000000000000000; key_mem [2] <= 128'h00000000000000000000000000000000; key_mem [3] <= 128'h00000000000000000000000000000000; key_mem [4] <= 128'h00000000000000000000000000000000; key_mem [5] <= 128'h00000000000000000000000000000000; key_mem [6] <= 128'h00000000000000000000000000000000; key_mem [7] <= 128'h00000000000000000000000000000000; key_mem [8] <= 128'h00000000000000000000000000000000; key_mem [9] <= 128'h00000000000000000000000000000000; key_mem [10] <= 128'h00000000000000000000000000000000; key_mem [11] <= 128'h00000000000000000000000000000000; key_mem [12] <= 128'h00000000000000000000000000000000; key_mem [13] <= 128'h00000000000000000000000000000000; key_mem [14] <= 128'h00000000000000000000000000000000; prev_key0_reg <= 128'h00000000000000000000000000000000; prev_key1_reg <= 128'h00000000000000000000000000000000; rcon_reg <= 8'h00; ready_reg <= 0; round_ctr_reg <= 4'h0; key_mem_ctrl_reg <= CTRL_IDLE; end else begin if (round_ctr_we) begin round_ctr_reg <= round_ctr_new; end if (ready_we) begin ready_reg <= ready_new; end if (rcon_we) begin rcon_reg <= rcon_new; end if (key_mem_we) begin key_mem[round_ctr_reg] <= key_mem_new; end if (prev_key0_we) begin prev_key0_reg <= prev_key0_new; end if (prev_key1_we) begin prev_key1_reg <= prev_key1_new; end if (key_mem_ctrl_we) begin key_mem_ctrl_reg <= key_mem_ctrl_new; end end end // reg_update //---------------------------------------------------------------- // key_mem_read // // Combinational read port for the key memory. //---------------------------------------------------------------- always @* begin : key_mem_read tmp_round_key = key_mem[round]; end // key_mem_read //---------------------------------------------------------------- // round_key_gen // // The round key generator logic for AES-128 and AES-256. //---------------------------------------------------------------- always @* begin: round_key_gen reg [31 : 0] w0, w1, w2, w3, w4, w5, w6, w7; reg [31 : 0] k0, k1, k2, k3; reg [31 : 0] rconw, rotstw, tw, trw; // Default assignments. key_mem_new = 128'h00000000000000000000000000000000; key_mem_we = 0; prev_key0_new = 128'h00000000000000000000000000000000; prev_key0_we = 0; prev_key1_new = 128'h00000000000000000000000000000000; prev_key1_we = 0; k0 = 32'h00000000; k1 = 32'h00000000; k2 = 32'h00000000; k3 = 32'h00000000; rcon_set = 1; rcon_next = 0; // Extract words and calculate intermediate values. // Perform rotation of sbox word etc. w0 = prev_key0_reg[127 : 096]; w1 = prev_key0_reg[095 : 064]; w2 = prev_key0_reg[063 : 032]; w3 = prev_key0_reg[031 : 000]; w4 = prev_key1_reg[127 : 096]; w5 = prev_key1_reg[095 : 064]; w6 = prev_key1_reg[063 : 032]; w7 = prev_key1_reg[031 : 000]; rconw = {rcon_reg, 24'h000000}; tmp_sboxw = w7; rotstw = {new_sboxw[23 : 00], new_sboxw[31 : 24]}; trw = rotstw ^ rconw; tw = new_sboxw; // Generate the specific round keys. if (round_key_update) begin rcon_set = 0; key_mem_we = 1; case (keylen) AES_128_BIT_KEY: begin if (round_ctr_reg == 0) begin key_mem_new = key[255 : 128]; prev_key1_new = key[255 : 128]; prev_key1_we = 1; rcon_next = 1; end else begin k0 = w4 ^ trw; k1 = w5 ^ w4 ^ trw; k2 = w6 ^ w5 ^ w4 ^ trw; k3 = w7 ^ w6 ^ w5 ^ w4 ^ trw; key_mem_new = {k0, k1, k2, k3}; prev_key1_new = {k0, k1, k2, k3}; prev_key1_we = 1; rcon_next = 1; end end AES_256_BIT_KEY: begin if (round_ctr_reg == 0) begin key_mem_new = key[255 : 128]; prev_key0_new = key[255 : 128]; prev_key0_we = 1; end else if (round_ctr_reg == 1) begin key_mem_new = key[127 : 0]; prev_key1_new = key[127 : 0]; prev_key1_we = 1; rcon_next = 1; end else begin if (round_ctr_reg[0] == 0) begin k0 = w0 ^ trw; k1 = w1 ^ w0 ^ trw; k2 = w2 ^ w1 ^ w0 ^ trw; k3 = w3 ^ w2 ^ w1 ^ w0 ^ trw; end else begin k0 = w0 ^ tw; k1 = w1 ^ w0 ^ tw; k2 = w2 ^ w1 ^ w0 ^ tw; k3 = w3 ^ w2 ^ w1 ^ w0 ^ tw; rcon_next = 1; end // Store the generated round keys. key_mem_new = {k0, k1, k2, k3}; prev_key1_new = {k0, k1, k2, k3}; prev_key1_we = 1; prev_key0_new = prev_key1_reg; prev_key0_we = 1; end end default: begin end endcase // case (keylen) end end // round_key_gen //---------------------------------------------------------------- // rcon_logic // // Caclulates the rcon value for the different key expansion // iterations. //---------------------------------------------------------------- always @* begin : rcon_logic reg [7 : 0] tmp_rcon; rcon_new = 8'h00; rcon_we = 0; tmp_rcon = {rcon_reg[6 : 0], 1'b0} ^ (8'h1b & {8{rcon_reg[7]}}); if (rcon_set) begin rcon_new = 8'h8d; rcon_we = 1; end if (rcon_next) begin rcon_new = tmp_rcon[7 : 0]; rcon_we = 1; end end //---------------------------------------------------------------- // round_ctr // // The round counter logic with increase and reset. //---------------------------------------------------------------- always @* begin : round_ctr round_ctr_new = 4'h0; round_ctr_we = 0; if (round_ctr_rst) begin round_ctr_new = 4'h0; round_ctr_we = 1; end else if (round_ctr_inc) begin round_ctr_new = round_ctr_reg + 1'b1; round_ctr_we = 1; end end //---------------------------------------------------------------- // num_rounds_logic // // Logic to select the number of rounds to generate keys for //---------------------------------------------------------------- always @* begin : num_rounds_logic num_rounds = 4'h0; case (keylen) AES_128_BIT_KEY: begin num_rounds = AES_128_NUM_ROUNDS; end AES_256_BIT_KEY: begin num_rounds = AES_256_NUM_ROUNDS; end default: begin end endcase // case (keylen) end //---------------------------------------------------------------- // key_mem_ctrl // // // The FSM that controls the round key generation. //---------------------------------------------------------------- always @* begin: key_mem_ctrl // Default assignments. ready_new = 0; ready_we = 0; round_key_update = 0; round_ctr_rst = 0; round_ctr_inc = 0; key_mem_ctrl_new = CTRL_IDLE; key_mem_ctrl_we = 0; case(key_mem_ctrl_reg) CTRL_IDLE: begin if (init) begin ready_new = 0; ready_we = 1; key_mem_ctrl_new = CTRL_INIT; key_mem_ctrl_we = 1; end end CTRL_INIT: begin round_ctr_rst = 1; key_mem_ctrl_new = CTRL_GENERATE; key_mem_ctrl_we = 1; end CTRL_GENERATE: begin round_ctr_inc = 1; round_key_update = 1; if (round_ctr_reg == num_rounds) begin key_mem_ctrl_new = CTRL_DONE; key_mem_ctrl_we = 1; end end CTRL_DONE: begin ready_new = 1; ready_we = 1; key_mem_ctrl_new = CTRL_IDLE; key_mem_ctrl_we = 1; end default: begin end endcase // case (key_mem_ctrl_reg) end // key_mem_ctrl endmodule // aes_key_mem //====================================================================== // EOF aes_key_mem.v //======================================================================