Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
829a1a833This file is pinned to the selected release. Download the original to open it in your design tool.
//======================================================================
//
// aes_key_mem.v
// -------------
// The AES key memort including round key generator.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2013 Secworks Sweden AB
// 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
//======================================================================