aboutsummaryrefslogtreecommitdiffstats
path: root/hdcp/hdcp_cipher.v
diff options
context:
space:
mode:
Diffstat (limited to 'hdcp/hdcp_cipher.v')
-rwxr-xr-xhdcp/hdcp_cipher.v411
1 files changed, 411 insertions, 0 deletions
diff --git a/hdcp/hdcp_cipher.v b/hdcp/hdcp_cipher.v
new file mode 100755
index 0000000..9804d10
--- /dev/null
+++ b/hdcp/hdcp_cipher.v
@@ -0,0 +1,411 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011, Andrew "bunnie" Huang
+// 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.
+//
+// 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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+`timescale 1 ns / 1 ps
+
+// generates a stream of hdcp cipher data
+module hdcp_cipher(
+ input wire clk,
+ input reset,
+
+ input [55:0] Km, // shared secret value
+ input [63:0] An, // session random number
+
+ input hdcpBlockCipher_init, // pulsed only one cycle
+ input authentication, // pulsed one cycle same time as above
+ input hdcpRekeyCipher, // pulsed one cycle to initiate rekey
+ input hdcpStreamCipher,// advance cipher state one clock
+ output [23:0] pr_data, // pseudorandom data output
+ output reg stream_ready // asserted when stream is ready (after init seq)
+ );
+
+ wire lfsr_out;
+ wire [23:0] ostream;
+ wire [83:0] Bo_wire;
+
+ parameter INIT = 12'b1 << 0;
+ parameter BLOCK_1 = 12'b1 << 1;
+ parameter BLOCK_2 = 12'b1 << 2;
+ parameter BLOCK_3 = 12'b1 << 3;
+ parameter BLOCK_4 = 12'b1 << 4;
+ parameter BLOCK_5 = 12'b1 << 5;
+ parameter BLOCK_6 = 12'b1 << 6;
+ parameter BLOCK_7 = 12'b1 << 7;
+ parameter BLOCK_8 = 12'b1 << 8;
+ parameter BLOCK_9 = 12'b1 << 9;
+ parameter GET_M = 12'b1 << 10;
+ parameter STREAM = 12'b1 << 11;
+ parameter REKEY = 12'b1 << 12;
+ parameter nSTATES = 13;
+
+ reg [(nSTATES-1):0] cstate = {{(nSTATES-1){1'b0}},1'b1};
+ reg [(nSTATES-1):0] nstate;
+
+// `define SIMULATION 1
+`ifdef SIMULATION
+ // synthesis translate_off
+ reg [8*20:1] state_ascii = "INIT ";
+ always @(cstate) begin
+ if (cstate == INIT ) state_ascii <= "INIT ";
+ else if (cstate == BLOCK_1 ) state_ascii <= "BLOCK_1 ";
+ else if (cstate == BLOCK_2 ) state_ascii <= "BLOCK_2 ";
+ else if (cstate == BLOCK_3 ) state_ascii <= "BLOCK_3 ";
+ else if (cstate == BLOCK_4 ) state_ascii <= "BLOCK_4 ";
+ else if (cstate == BLOCK_5 ) state_ascii <= "BLOCK_5 ";
+ else if (cstate == BLOCK_6 ) state_ascii <= "BLOCK_6 ";
+ else if (cstate == BLOCK_7 ) state_ascii <= "BLOCK_7 ";
+ else if (cstate == BLOCK_8 ) state_ascii <= "BLOCK_8 ";
+ else if (cstate == BLOCK_9 ) state_ascii <= "BLOCK_9 ";
+ else if (cstate == GET_M ) state_ascii <= "GET_M ";
+ else if (cstate == STREAM ) state_ascii <= "STREAM ";
+ else if (cstate == REKEY ) state_ascii <= "REKEY ";
+ else state_ascii <= "WTF ";
+ end
+ // synthesis translate_on
+`endif // `ifdef SIMULATION
+
+ reg [5:0] statecnt;
+ reg rekey;
+ reg load_block;
+ reg load_56; // load 56 or 80 bits...
+ reg load_lfsr;
+ reg advance_lfsr;
+ reg advance_block;
+ reg [83:0] Ks;
+ reg [83:0] Ki;
+ reg [63:0] Mi;
+ reg load_ks;
+ reg auth_mode;
+ reg [83:0] Kmod;
+
+ always @ (posedge clk or posedge reset) begin
+ if (reset)
+ cstate <= INIT;
+ else
+ cstate <=#1 nstate;
+ end
+
+ hdcp_lfsr lfsr( .clk(clk), .reset(reset),
+ .iv(auth_mode ? Ks[55:0] : Ki[55:0]),
+ .init_iv(load_lfsr),
+ .advance(advance_lfsr),
+ .onebit(lfsr_out));
+
+ hdcp_block block( .clk(clk), .reset(reset),
+
+ .load(load_block),
+ .B(auth_mode ? {20'b0,An} : {20'b0,Mi}),
+ .K(Kmod),
+ .Bo(Bo_wire),
+ .rekey(rekey),
+ .lfsr_in(lfsr_out),
+ .ostream(ostream),
+ .advance(advance_block));
+ assign pr_data = ostream;
+
+ always @ (*) begin
+ case ({auth_mode,load_56}) //synthesis parallel_case full_case
+ 2'b00: begin // not auth mode, load 84 bits
+ Kmod = Ki;
+ end
+ 2'b01: begin // not auth mode, but load 56 bits only
+ Kmod = {28'b0,Ks[55:0]};
+ end
+ 2'b10: begin // auth mode, load 84 bits
+ Kmod = Ks;
+ end
+ 2'b11: begin // auth mode, load only 56 bits
+ Kmod = {28'b0,Km[55:0]};
+ end
+ endcase // case ({auth_mode,load_56})
+ end // always @ (*)
+
+
+ always @ (*) begin
+ case (cstate) //synthesis parallel_case full_case
+ INIT: begin
+ nstate = hdcpBlockCipher_init ? BLOCK_1 : INIT;
+ end
+ BLOCK_1: begin
+ nstate = BLOCK_2;
+ end
+ BLOCK_2: begin
+ nstate = (statecnt >= 6'd47) ? BLOCK_3: BLOCK_2;
+ end
+ BLOCK_3: begin
+ nstate = BLOCK_4;
+ end
+ BLOCK_4: begin
+ nstate = BLOCK_5;
+ end
+ BLOCK_5: begin
+ nstate = BLOCK_6;
+ end
+ BLOCK_6: begin
+ nstate = BLOCK_7;
+ end
+ BLOCK_7: begin
+ nstate = BLOCK_8;
+ end
+ BLOCK_8: begin
+ nstate = (statecnt >= 6'd55) ? BLOCK_9: BLOCK_8;
+ end
+ BLOCK_9: begin
+ nstate = GET_M;
+ end
+ GET_M: begin
+ nstate = STREAM;
+ end
+ STREAM: begin
+ if( hdcpBlockCipher_init ) begin
+ nstate = BLOCK_1;
+ end else if( hdcpRekeyCipher ) begin
+ nstate = REKEY;
+ end else begin
+ nstate = STREAM;
+ end
+ end
+ REKEY: begin
+ if( hdcpBlockCipher_init ) begin
+ nstate = BLOCK_1;
+ end else begin
+ nstate = (statecnt >= 6'd55) ? STREAM : REKEY;
+ end
+ end
+ endcase // case (cstate)
+ end
+
+ always @ (posedge clk or posedge reset) begin
+ if( reset ) begin
+ statecnt <=#1 6'b0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end else begin
+ case (cstate) // synthesis parallel_case full_case
+ INIT: begin
+ statecnt <=#1 6'b0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 authentication;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_1: begin
+ statecnt <=#1 6'b0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b1; // load B & K regs of block module
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b1;
+ end
+ BLOCK_2: begin
+ statecnt <=#1 statecnt + 1; // 48 clocks
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b1;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_3: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b1; // save Ks, Ki, and B=>K
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_4: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b1; // dup of above
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_5: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b1; // reload block cipher
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_6: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b1; // init lfsr
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_7: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b1; // assert rekey
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_8: begin
+ statecnt <=#1 statecnt + 1; // 56 clocks
+ rekey <=#1 1'b1;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b1;
+ advance_block <=#1 1'b1;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ BLOCK_9: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0; // de-assert rekey
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end // case: BLOCK_9
+ GET_M: begin // one cycle wait to get M register loaded properly
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b0;
+ advance_block <=#1 1'b0;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 1'b0;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ STREAM: begin
+ statecnt <=#1 0;
+ rekey <=#1 1'b0;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 hdcpStreamCipher;
+ advance_block <=#1 hdcpStreamCipher;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 authentication;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b1;
+ load_56 <=#1 1'b0;
+ end
+ REKEY: begin
+ statecnt <=#1 statecnt + 1;
+ rekey <=#1 1'b1;
+ load_block <=#1 1'b0;
+ advance_lfsr <=#1 1'b1;
+ advance_block <=#1 1'b1;
+ load_ks <=#1 1'b0;
+ auth_mode <=#1 auth_mode;
+ load_lfsr <=#1 1'b0;
+ stream_ready <=#1 1'b0;
+ load_56 <=#1 1'b0;
+ end
+ endcase // case (cstate)
+ end
+ end // always @ (posedge clk or posedge reset)
+
+ always @(posedge clk or posedge reset) begin
+ if( reset ) begin
+ Ks <= 80'b0;
+ Ki <= 80'b0;
+ end else begin
+// if( hdcpBlockCipher_init ) begin
+// Ks <= (authentication | auth_mode) ? {28'b0,Km} : Ks;
+// Ki <= 80'b0;
+// end else if( load_ks && auth_mode ) begin
+ if( load_ks && auth_mode ) begin
+ Ks <= Bo_wire;
+ Ki <= 80'b0;
+ end else if( load_ks && !auth_mode ) begin
+ Ks <= Ks;
+ Ki <= Bo_wire;
+ end else begin
+ Ks <= Ks;
+ Ki <= Ki;
+ end
+ end
+ end // always @ (posedge clk or posedge reset)
+
+ always @(posedge clk or posedge reset) begin
+ if( reset ) begin
+ Mi <= 80'b0;
+ end else begin
+ if( (cstate == BLOCK_8) || (cstate == BLOCK_9) || (cstate == GET_M) ) begin
+ Mi[15:0] <= ostream[15:0];
+ Mi[31:16] <= Mi[15:0];
+ Mi[47:32] <= Mi[31:16];
+ Mi[63:48] <= Mi[47:32];
+ end else begin
+ Mi <= Mi;
+ end
+ end // else: !if( reset )
+ end // always @ (posedge clk or posedge reset)
+
+endmodule // hdcp_cipher