This post is a continuation of my previous post. I continued my implementation of the DES encryption standard in Verilog by wrapping the DES core into a triple DES 3DES implementation and completing the final test bench.
Disclaimer: I am a complete Verilog novice. I'm certain there are bad design/bad practice/bugs in this implementation. Eventually I intend for someone knowledgeable to review and critique my work in an effort to improve.
Using the DES block from my previous posts, I implemented a 3DES module. 3DES is a cryptographic alorithm that involves encrypting a given block three times with three different keys. The security level of 3DES far exceeds that of DES alone, and it prevents meet-in-the middle attacks against a double DES implementation. I started off my 3DES IP block with a new module. The module takes the same inputs as an individual DES block with two additional keys. I added a new flag, key_error
addition to the existing output_data
and valid
bits provided by the DES core. key_error
indicates if any of the user provided keys match. This is to mitigate the risk of using the same key for each round, compromising the security of 3DES.
module DES3
(
input clock,
input mode,
input enable,
input [0:63] key0,
input [0:63] key1,
input [0:63] key2,
input [0:63] input_data,
output reg [0:63] output_data,
output wire valid,
output wire key_error
);
Next I created a register to hold a valid flag. This register is initialized to 0
in the initial
block. I added two constants for ENCRYPT
and DECRYPT
, 0
and 1
respectively. Next, I added three registers to store the input keys. This allows the key schedule to be reversed for decryption operations. I then added a register to track a signal indicating that input key scheduling has been completed. I then added a 3-bit register to track when each of the three DES blocks are finished. A register was added to check the overall validity of the 3DES module. Lastly, a register was added to track key errors.
//Mode constants
localparam ENCRYPT = 1'b0;
localparam DECRYPT = 1'b1;
//Local key storage
reg [0:63] k0;
reg [0:63] k1;
reg [0:63] k2;
//Validity bits
reg key_valid;
wire [2:0] block_done;
reg valid_reg;
reg key_err_reg;
Next, I added an always
block to schedule the keys for the given mode. After the keys have been set, the key_valid
register is set.
//Schedule the keys in reverse if decrypting
always @(posedge clock)
begin
if(mode == ENCRYPT)
begin
k0 = key0;
k1 = key1;
k2 = key2;
end
else
begin
k0 = key2;
k1 = key1;
k2 = key0;
end
//Set keys valid
key_valid = 1'b1;
end
Next, three wires were added to chain the three DES blocks together in an output->input fashion.
//Wires to connect each DES block
wire [0:63] BLOCK0_1;
wire [0:63] BLOCK1_2;
wire [0:63] BLOCK2_O;
I instantiated three DES blocks. The input of the first block is connected to the input of the 3DES module. The output of the final module is routed to the output of the 3DES module. The valid
bits of each block are also chained together in a valid
->enable
fashion. Each block is assigned one of the three keys. The valid
bits are stored in a register called block_done
used to determine when all three DES blocks are finished, and the output is complete.
//Instantiate the first DES block
DES des0 (
.clock(clock),
.mode(mode),
.enable(key_valid),
.key(k0),
.input_data(input_data),
.output_data(BLOCK0_1),
.valid(block_done[0])
);
//Instantiate the second DES block
DES des1 (
.clock(clock),
.mode(mode),
.enable(block_done[0]),
.key(k1),
.input_data(BLOCK0_1),
.output_data(BLOCK1_2),
.valid(block_done[1])
);
//Instantiate the third DES block
DES des2 (
.clock(clock),
.mode(mode),
.enable(block_done[1]),
.key(k2),
.input_data(BLOCK1_2),
.output_data(BLOCK2_O),
.valid(block_done[2])
);
Next I added an always
block to set the output_data
output of the 3DES module to the output from the final DES block. Additionally, the keys are checked for validity, i.e. ensuring they don't match. Lastly, the always
block assigns the validity output of the 3DES module to the logical AND of block_done
, key_valid
, and the negation of key_err_reg
.
//Assign output data and update validity flag/key error
always @(posedge clock)
begin
//Output data is the output from the 3rd DES block
output_data = BLOCK2_O;
//A key error occurs if any of the keys match, this destroys
//the security of 3DES
key_err_reg = ((k0 == k1) || (k1 == k2) || (k2 == k0));
//The valid flag depends on all 3 blocks being done with valid keys
valid_reg = (block_done == 4'b111) && key_valid && !key_err_reg;
end
To finish up the module, I added another always
block to reset the validity if the keys, input data, enabled status, or mode change. Lastly, valid_reg
and key_err_reg
are assigned to the valid
and key_error
outputs of the module, respectively.
//Reset validity if keys or input data change
always @(key0, key1, key2, input_data, enable, mode)
begin
key_valid = 0;
valid_reg = 0;
end
//Assign validity bit to all blocks complete and keys valid
assign valid = valid_reg;
assign key_error = key_err_reg;
I created a test bench for the 3DES module to exercise all the functionality. The test bench is similar to the one created for the DES module, so I will not repeat the description here. The key difference is the assignment of three distinct keys instead of one. Running the test bench produces the following output.
Plaintext = 0000000100100011010001010110011110001001101010111100110111101111
Encryption output valid in 5 clock cycles.
Valid: 1 Cipher = 0100000010100011000010101101000101001001101010100010100101011001
Valid after mode and input data change: 0
Decryption output valid in 4 clock cycles.
Valid: 1 Decrypted plaintext = 0000000100100011010001010110011110001001101010111100110111101111
Decryption output matches input after encrypt->decrypt cycle
Valid after key change (expected 0): 0
Key error after key change (expected 0): 0
Valid after duplicate key: 0 key error: 1 (expected 0, 1)
Valid after resetting keys: 0 key error: 0 (expected 0, 0)
The next step to make this a functional module will be to wrap it as an AXI peripheral with memory mapped control and input/output registers. That will be the topic of my next post.