/******************************************************************************/
// @copyright   Copyright Notification
//   No part may be reproduced except as authorized by written permission.
//   The copyright and the foregoing restriction extend to reproduction in all media.
//   (c) 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC).
//   All rights reserved.
// @version: IWD_23wk37
// $Date: 2023-09-13 17:51:49 +0200 (Wed, 13 Sep 2023) $
// $Rev: 37110 $
/******************************************************************************/
module EUTRA_NR_SecurityFunctions {
  import from CommonDefs all;

  //============================================================================
  // constants and types
  type integer SK_Counter_Type;                 /* @status    APPROVED (ENDC, IMS, NR5GC, NR5GC_IRAT, POS) */

  const SK_Counter_Type tsc_SK_Counter:= 0;     /* @status    APPROVED (ENDC, NR5GC_IRAT) */
  const integer tsc_NAS_Enc_Alg := 1;           /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
  const integer tsc_NAS_Int_Alg := 2;           /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
  const integer tsc_RRC_Enc_Alg := 3;           /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
  const integer tsc_RRC_Int_Alg := 4;           /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
  const integer tsc_UP_Enc_Alg  := 5;           /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
  const integer tsc_N_UP_Int_Alg  := 6;         /* @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */

  type integer NR_AlgTypeDistg_Type(tsc_NAS_Enc_Alg,
                                    tsc_NAS_Int_Alg,
                                    tsc_RRC_Enc_Alg,
                                    tsc_RRC_Int_Alg,
                                    tsc_UP_Enc_Alg,
                                    tsc_N_UP_Int_Alg);      /* As per Table A.8-1 of 33.501;   @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
                                 
  type integer AlgTypeDistg_Type(tsc_NAS_Enc_Alg,
                                 tsc_NAS_Int_Alg,
                                 tsc_RRC_Enc_Alg,
                                 tsc_RRC_Int_Alg,
                                 tsc_UP_Enc_Alg);      /* As per Table A.8-1 of 33.401;  @status      */
  
  //============================================================================
  // TEMPLATES
  //----------------------------------------------------------------------------
  
  //============================================================================

  group Auth_S_Function {       // Group of S functions defined in Annex A of 33.401

  //--------------------------------------------------------------------------
  /*
   * @desc      KASME to CKSRVCC, IKSRVCC derivation (S1A)
   *            As per annex A.12 of 33.401
   * @param     p_KDF
   * @param     p_KASME
   * @param     p_DL_NAS_Count
   * @return    B256_Type
   * @status    APPROVED (IMS_IRAT, LTE_A_IRAT, LTE_IRAT)
   */
  function f_EUTRA_Authentication_S1A(KDF_Type p_KDF,
                                      B256_Type p_KASME,
                                      O4_Type p_DL_NAS_Count) return B256_Type
  {
    const octetstring const_S1A_FC :='1A'O;
    var octetstring v_S;
    
    // Generation of String
    v_S := const_S1A_FC;
    //FC = 0x1A
    v_S :=   ( v_S &  p_DL_NAS_Count );
    //P0 = NAS downlink COUNT value
    v_S :=   ( v_S & '0004'O );
    //L0 = length of NAS downlink COUNT value (i.e. 0x00 0x04)
    
    return fx_KeyDerivationFunction ( p_KDF, p_KASME, v_S ); // @sic R5s160711 sic@
    // The result is 256 bit  CKSRVCC ll IKSRVCC  each of 128 bits
  };
  
  //--------------------------------------------------------------------------
  /*
   * @desc      S-KeNB derivation function used at SeNB
   *            As per annex A.15 of 33.401
   * @param     p_KDF
   * @param     p_KENB
   * @param     p_SCG_Counter
   * @return    B256_Type
   * @status    APPROVED (ENDC, NR5GC_IRAT)
   */
  function f_EUTRA_Authentication_S1C(KDF_Type p_KDF,
                                      B256_Type p_KENB,
                                      SK_Counter_Type p_SCG_Counter) return B256_Type
  {
    const octetstring const_S1C_FC :='1C'O;
    var octetstring v_S;
    // Generation of String
    v_S := const_S1C_FC;
    //FC = 0x1C
    v_S :=   ( v_S & int2oct (p_SCG_Counter,2));
    //P0 = Value of the SCG Counter as a non-negative integer
    v_S :=  ( v_S & '0002'O );
    //L0 = length of the SCG Counter value (i.e. 0x00 0x02)
    return fx_KeyDerivationFunction ( p_KDF, p_KENB , v_S );
  }
  
  //--------------------------------------------------------------------------
  /*
   * @desc      Algorithm key derivation functions (S15)
   *            As per annex A.7 of 33.401
   * @param     p_AlgTypeDistg
   * @param     p_Alg
   * @param     p_Key
   * @param     p_KDF_Type
   * @return    B128_Type
   * @status    APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC_IRAT, POS)
   */
  function f_EUTRA_NB_Authentication_S15(NR_AlgTypeDistg_Type p_AlgTypeDistg,   //  @sic R5-235451 sic@
                                         B3_Type p_Alg,
                                         B256_Type p_Key,
                                         KDF_Type p_KDF_Type) return B128_Type
  {
    const octetstring const_S15_FC :='15'O;
    var octetstring v_S;
    // Generation of String
    v_S := const_S15_FC;
    //FC = 0x15
    v_S :=   ( v_S & int2oct ( p_AlgTypeDistg, 1  ) );
    //P0 = algorithm type distinguisher
    v_S :=   ( v_S & '0001'O );
    //L0 = length of algorithm type distinguisher (i.e. 0x00 0x01))
    v_S :=   ( v_S & bit2oct ( p_Alg ) );
    //P1 = algorithm identity
    v_S :=   ( v_S & '0001'O );
    //L1 = length of algorithm identity (i.e. 0x00 0x01)
    
    return substr(fx_KeyDerivationFunction(p_KDF_Type, p_Key, v_S), 128, 128);
    // returns LSB 128 bits[truncated] of the key generated
  };
  
  //--------------------------------------------------------------------------
  /*
   * @desc      Algorithm key derivation functions (S69)
   *            As per annex A.8 of 33.501/ A.19 of 33.401
   * @param     p_AlgTypeDistg
   * @param     p_Alg
   * @param     p_Key
   * @param     p_KDF_Type
   * @return    B128_Type
   * @status    APPROVED (ENDC, IMS, NR5GC, NR5GC_IRAT, POS)
   */
  function f_NG_Authentication_A8(NR_AlgTypeDistg_Type p_AlgTypeDistg,
                                  B4_Type p_Alg,
                                  B256_Type p_Key,
                                  KDF_Type p_KDF_Type) return B128_Type
  {
    const octetstring const_S69_FC :='69'O;
    var octetstring v_S;
    // Generation of String
    v_S := const_S69_FC;
    //FC = 0x69
    v_S :=   ( v_S & int2oct ( p_AlgTypeDistg, 1  ) );
    //P0 = algorithm type distinguisher
    v_S :=   ( v_S & '0001'O );
    //L0 = length of algorithm type distinguisher (i.e. 0x00 0x01))
    v_S :=   ( v_S & bit2oct ( p_Alg ) );
    //P1 = algorithm identity
    v_S :=   ( v_S & '0001'O );
    //L1 = length of algorithm identity (i.e. 0x00 0x01)
    
    return substr(fx_KeyDerivationFunction(p_KDF_Type, p_Key, v_S), 128, 128);
    // returns LSB 128 bits[truncated] of the key generated
  }
  
  //--------------------------------------------------------------------------
  /*
   * @desc      KAMF to KAMF' horizontal derivation function
   *            As per annex A.13 of 33.501
   * @param     p_Handover
   * @param     p_Count
   * @param     p_KAMF
   * @param     p_KDF_Type
   * @return    B256_Type
   * @status    APPROVED (NR5GC)
   */
  function f_NG_Authentication_A13(boolean p_Handover,
                                  O4_Type p_Count,
                                  B256_Type p_KAMF,
                                  KDF_Type p_KDF_Type) return B256_Type
  {
    const octetstring const_S72_FC :='72'O;
    var octetstring v_S;
    var octetstring v_P0;

    // Generation of String
    v_S := const_S72_FC;
    //FC = 0x72
    if (p_Handover) {
      v_P0 := '01'O;
    } else { // mobility registration
      v_P0 := '00'O;
    }
    v_S :=  (v_S & v_P0);
    //P0 = Direction
    v_S :=  (v_S & '0001'O) ;
    //L0 = length of direction
    v_S :=  (v_S & p_Count);
    //P1 = Count
    v_S :=  (v_S & '0004'O) ;
    //L1 = length of count
    
    return fx_KeyDerivationFunction(p_KDF_Type, p_KAMF, v_S);
  };
  
  //--------------------------------------------------------------------------
  /*
   * @desc      KAMF to KASME' derivation function
   *            As per annex A.14 of 33.501
   * @param     p_Handover
   * @param     p_Count
   * @param     p_KAMF
   * @param     p_KDF_Type
   * @return    B256_Type
   * @status    APPROVED (NR5GC_IRAT)
   */
  function f_NG_Authentication_A14(boolean p_Handover,
                                  O4_Type p_Count,
                                  B256_Type p_KAMF,
                                  KDF_Type p_KDF_Type) return B256_Type
  {
    const octetstring const_S73_FC :='73'O;
    const octetstring const_S74_FC :='74'O;
    var octetstring v_S;

    if (p_Handover) {
      // Generation of String
      v_S := const_S74_FC;
      //FC = 0x73
    } else { // mobility registration
      // Generation of String
      v_S := const_S73_FC;
      //FC = 0x74
    }
    v_S :=  (v_S & p_Count);
    //P0 = Count
    v_S :=  (v_S & '0004'O) ;
    //L0 = length of count
    
    return fx_KeyDerivationFunction(p_KDF_Type, p_KAMF, v_S);
  };
  
  //--------------------------------------------------------------------------
  /*
   * @desc      KASME to KAMF' derivation function
   *            As per annex A.15 of 33.501
   * @param     p_Count
   * @param     p_KASME
   * @param     p_KDF_Type
   * @return    B256_Type
   * @status    APPROVED (NR5GC_IRAT)
   */
  function f_NG_Authentication_A15_IdleMode(O4_Type p_Count,
                                            B256_Type p_KASME,
                                            KDF_Type p_KDF_Type) return B256_Type
  {
    const octetstring const_S75_FC :='75'O;
    var octetstring v_S;

    // Generation of String
    v_S := const_S75_FC;
    //FC = 0x75
    v_S :=  (v_S & p_Count);
    //P0 = UL Count
    v_S :=  (v_S & '0004'O) ;
    //L0 = length of count
    
    return fx_KeyDerivationFunction(p_KDF_Type, p_KASME, v_S);
  };
  
  /*
   * @desc      KASME to KAMF' derivation function
   *            As per annex A.15 of 33.501
   * @param     p_NH
   * @param     p_KASME
   * @param     p_KDF_Type
   * @return    B256_Type
   * @status    APPROVED (NR5GC_IRAT)
   */
  function f_NG_Authentication_A15_HO(B256_Type p_NH,
                                      B256_Type p_KASME,
                                      KDF_Type p_KDF_Type) return B256_Type
  {
    const octetstring const_S76_FC :='76'O;
    var octetstring v_S;

    // Generation of String
    v_S := const_S76_FC;
    //FC = 0x76
    v_S :=  (v_S & bit2oct(p_NH));
    //P0 = NH
    v_S :=  (v_S & '0020'O) ;
    //L0 = length of NH
    
    return fx_KeyDerivationFunction(p_KDF_Type, p_KASME, v_S);
  };
  
  } /* End of group Auth_S_Function */

  //============================================================================
  /*
   * @desc      Function to be used for AS KEy derivation for SgNB data encryption.
   * @param     p_KDF
   * @param     p_KENB
   * @param     p_SK_Counter
   * @return    B256_Type
   * @status    APPROVED (ENDC, NR5GC_IRAT)
   */
  function f_EUTRA_NR_InitAS_KeyChaining_SgNB(KDF_Type p_KDF,
                                              B256_Type p_KENB,
                                              SK_Counter_Type p_SK_Counter) return B256_Type
  {
    // Derive S-KgNB from KeNB
    return f_EUTRA_Authentication_S1C (p_KDF,
                                       p_KENB,
                                       p_SK_Counter);
    // Ciphering algorithm for UP is same as RRC
  }


}
