(* $Id: crypt_3des.ml,v 1.2 2001/03/10 16:43:21 gerd Exp $
 * ----------------------------------------------------------------------
 * This module is part of the cryptgps package by Gerd Stolpmann.
 *)

open Crypt_aux

let check_parity key =
  match String.length key with
     8 -> Crypt_des.check_parity key
  | 16 -> Crypt_des.check_parity (String.sub key 0 8);
          Crypt_des.check_parity (String.sub key 8 8)
  | 24 -> Crypt_des.check_parity (String.sub key 0 8);
          Crypt_des.check_parity (String.sub key 8 8);
          Crypt_des.check_parity (String.sub key 16 8)
  | _ -> failwith "Crypt_3des: invalid key length"
;;


let set_parity key =
  match String.length key with
     8 -> Crypt_des.set_parity key
  | 16 -> Crypt_des.set_parity (String.sub key 0 8) ^
          Crypt_des.set_parity (String.sub key 8 8)
  | 24 -> Crypt_des.set_parity (String.sub key 0 8) ^
          Crypt_des.set_parity (String.sub key 8 8) ^
          Crypt_des.set_parity (String.sub key 16 8)
  | _ -> failwith "Crypt_3des: invalid key length"
;;


module Cryptsystem : Cryptsystem_64.T =
  struct
    
    type key =
	{ k1 : Crypt_des.Cryptsystem.key;
	  k2 : Crypt_des.Cryptsystem.key;
	  k3 : Crypt_des.Cryptsystem.key;
	  n_keys : int
	} 


    let encrypt_ecb k x =
      match k.n_keys with
	1 -> Crypt_des.Cryptsystem.encrypt_ecb k.k1 x
      |	2 -> let x'  = Crypt_des.Cryptsystem.encrypt_ecb k.k1 x in
	     let x'' = Crypt_des.Cryptsystem.decrypt_ecb k.k2 x' in
	     Crypt_des.Cryptsystem.encrypt_ecb k.k1 x''
      |	3 -> let x'  = Crypt_des.Cryptsystem.encrypt_ecb k.k1 x in
	     let x'' = Crypt_des.Cryptsystem.decrypt_ecb k.k2 x' in
	     Crypt_des.Cryptsystem.encrypt_ecb k.k3 x''
      | _ -> failwith "Crypt_3des: invalid key length"


    let encrypt_ecb_int32 k xl xr ret_xl ret_xr =
      let x = quadruple_of_int32 xl xr in
      let y = encrypt_ecb k x in
      int32_of_quadruple y ret_xl ret_xr


    let decrypt_ecb k x =
      match k.n_keys with
	1 -> Crypt_des.Cryptsystem.decrypt_ecb k.k1 x
      |	2 -> let x'  = Crypt_des.Cryptsystem.decrypt_ecb k.k1 x in
	     let x'' = Crypt_des.Cryptsystem.encrypt_ecb k.k2 x' in
	     Crypt_des.Cryptsystem.decrypt_ecb k.k1 x''
      |	3 -> let x'  = Crypt_des.Cryptsystem.decrypt_ecb k.k1 x in
	     let x'' = Crypt_des.Cryptsystem.encrypt_ecb k.k2 x' in
	     Crypt_des.Cryptsystem.decrypt_ecb k.k3 x''
      | _ -> failwith "Crypt_3des: invalid key length"


    let decrypt_ecb_int32 k xl xr ret_xl ret_xr =
      let x = quadruple_of_int32 xl xr in
      let y = decrypt_ecb k x in
      int32_of_quadruple y ret_xl ret_xr


    let prepare key =
      let l_key = String.length key in
      match l_key with
	 8 -> let k = Crypt_des.Cryptsystem.prepare key in
	      { k1=k; k2=k; k3=k; n_keys=1 }
      |	16 -> let k1 = Crypt_des.Cryptsystem.prepare (String.sub key 0 8) in
	      let k2 = Crypt_des.Cryptsystem.prepare (String.sub key 8 8) in
	      { k1=k1; k2=k2; k3=k1; n_keys=2 }
      |	24 -> let k1 = Crypt_des.Cryptsystem.prepare (String.sub key 0 8) in
	      let k2 = Crypt_des.Cryptsystem.prepare (String.sub key 8 8) in
	      let k3 = Crypt_des.Cryptsystem.prepare (String.sub key 16 8) in
	      { k1=k1; k2=k2; k3=k3; n_keys=3 }
      |	_ -> failwith "Crypt_3des: invalid key length"


    let textkey k =
      match k.n_keys with
	1 -> Crypt_des.Cryptsystem.textkey k.k1
      |	2 -> Crypt_des.Cryptsystem.textkey k.k1 ^ 
	     Crypt_des.Cryptsystem.textkey k.k2
      |	3 -> Crypt_des.Cryptsystem.textkey k.k1 ^ 
	     Crypt_des.Cryptsystem.textkey k.k2 ^
	     Crypt_des.Cryptsystem.textkey k.k3
      | _ -> failwith "Crypt_3des: invalid key length"


    let is_weak k =
      match k.n_keys with
	1 -> Crypt_des.Cryptsystem.is_weak k.k1
      |	2 -> Crypt_des.Cryptsystem.is_weak k.k1 or
	     Crypt_des.Cryptsystem.is_weak k.k2 or
	     Crypt_des.Cryptsystem.textkey k.k1 = 
	       Crypt_des.Cryptsystem.textkey k.k2
      |	3 -> Crypt_des.Cryptsystem.is_weak k.k1 or
	     Crypt_des.Cryptsystem.is_weak k.k2 or
	     Crypt_des.Cryptsystem.is_weak k.k3 or
	     Crypt_des.Cryptsystem.textkey k.k1 = 
	       Crypt_des.Cryptsystem.textkey k.k2 or
	     Crypt_des.Cryptsystem.textkey k.k1 = 
	       Crypt_des.Cryptsystem.textkey k.k3 or
	     Crypt_des.Cryptsystem.textkey k.k2 = 
	       Crypt_des.Cryptsystem.textkey k.k3
      | _ -> failwith "Crypt_3des: invalid key length"

  end
;;


module Cryptmodes = Cryptmodes_64.Make_modes(Cryptsystem)
;;


(* ======================================================================
 * History:
 * 
 * $Log: crypt_3des.ml,v $
 * Revision 1.2  2001/03/10 16:43:21  gerd
 * 	int32 experiments
 *
 * Revision 1.1  1999/06/18 00:23:58  gerd
 * 	First release.
 *
 * 
 *)
