📄 cave.c
字号:
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
C A V E M O D U L E
GENERAL DESCRIPTION
This module contains routines to support the CAVE (Cellular
Authentication, Voice Privacy and Encryption) algorithm as specified
in "Common Cryptographic Algorithms" called out in IS-95.
This module is common to all hardware targets.
NOTES
1. See "Common Cryptographic Algorithms" for explanations and
specifications of all these algorithms.
2. Most of the arrays specified in "Common Cryptographic Algorithms"
are indexed backwards as compared to C arrays: XXX[0] is the
MOST significant byte of XXX. This module follows that convention
for arrays, but keeps whole values in conventional byte order.
Some code here depends on Intel byte order.
NOTICE
Information embodied in this module may be subject to the export
jurisdiction of the US Department of State as specified in the
International Traffic in Arms Regulations (title 22 CFR parts
120 through 130 inclusive). A license issued by the Department
of State is required for the export of such technical data.
EXTERNALIZED FUNCTIONS
CAVE_init
Initializes CAVE processing, at powerup or NAM change.
CAVE_validate_A_key
Checks a manually-entered A-key against its check digits.
CAVE_update_A_key
Stores a new A-key and clears out SSD.
CAVE_generate_SSD
Generates new A and B values of Shared Secret Data.
CAVE_update_SSD
Stores new A and B values of SSD.
CAVE_auth_signature
Computes and authentication signature.
CAVE_encrypt
Encrypts a message buffer using the CMEA algorithm.
CAVE_private_lcm
Returns the private long code mask to be used for CDMA voice privacy.
INITIALIZATION AND SEQUENCING REQUIREMENTS
CAVE_init must be called once on powerup or NAM change, to set
up the identity variables, before any other functions are called.
CAVE_auth_signature must be called with save_registers set to TRUE,
and CAVE_generate_key must be called, before any message encryption
can be performed or the private long code mask can be returned.
Copyright(c) 1994,1995,1996 QUALCOMM INCORPORATED. All Rights Reserved.
Copyright(c) 1999 QUALCOMM INCORPORATED. All Rights Reserved.
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
/*===========================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$PVCSPath: L:/src/asw/MSM5100/CP_REL_A/vcs/cave.c_v 1.4 09 Sep 2002 16:22:20 azafer $
$Header: //depot/asic/msmshared/1x/cp/MSMSHARED_CP_CDMA.02.00.64B/cave.c#1 $ $DateTime: 2004/08/24 16:28:29 $ $Author: louiel $
when who what, where, why
-------- --- ----------------------------------------------------------
09/09/02 ts Added support for Run Time R-UIM Enable feature
08/09/01 sb Merged following changes from common archive:
06/19/01 ts Moved the VPM size constant to this file.
06/13/01 ts A change in the VPM octet offset has caused
a problem with CAVE_update_keys. Changed
the VPM size to use the proper size and not
the offset.
05/25/01 ts Added feature switches for new UIM server.
03/09/01 fas Added include for customer.h to inhibit compiler warning.
06/28/00 cah Removed MSG_FILE undef work around for nonRUIM builds.
05/30/00 ck Added undef MSG_FILE to remove compiler warning.
05/24/00 ck Added the function CAVE_update_keys() that sets the CMEA
and VPM keys based on the keys computed by the RUIM.
Featurised out most of the CAVE functionality based on
FEATURE_RUIM.
04/06/00 va Merged the following from MSM3100_CP.03.00.17
ry Added OTAPA support
08/13/99 jq Removed the use of ROM, since it's no longer defined.
06/17/99 ck Fixed the problem where the CMEA and VPM keys were computed
based on the old SSD during re-authentication.
05/10/99 kmp Replaced T_AUTH with FEATURE_AUTH
04/08/99 ck Removed the initialisation of SSD_A and SSD_B after the
update of A-Key by OTASP as it erased the previous contents
of valid SSD.
03/18/99 ck Merged in support for A-Key exchange and Re-Authentication
03/18/99 ck Merged the change from rev 1.10 SPSW
Keyword 'const' inserted in front of the ROM macro.
09/15/98 pms Backed out _near pointers
09/04/98 pms Neared the variables to save ROM space.
06/21/96 dna Removed checksums for A-key, SSD-A and SSD-B. We now make
them zero if unitialized and always consider them valid.
05/15/96 dna CMEA key generation status now set ASAP.
04/24/96 dna Now write checksum for zero'd SSD when changing A-Key.
08/23/95 dna Checked in initial version.
04/19/94 ptw Created module.
===========================================================================*/
/*===========================================================================
INCLUDE FILES FOR MODULE
===========================================================================*/
#include "comdef.h"
#include "target.h"
#include "customer.h"
#ifdef FEATURE_AUTH
/* Temporary change to rid msg_file compiler warning until msg fix is in */
#if defined( FEATURE_UIM_RUIM ) && !defined( FEATURE_UIM_RUN_TIME_ENABLE )
#undef MSG_FILE
#endif /* FEATURE_UIM_RUIM && !FEATURE_UIM_RUN_TIME_ENABLE */
#include "err.h"
#include "mccdma.h"
#include "msg.h"
#include "nv.h"
#include "qw.h"
#include "cave.h"
#include "ulpn.h" /* For ulpn_type definition */
#include "auth.h"
#include "authi.h"
#include "crc.h"
#ifdef FEATURE_UIM_RUIM
#include "memory.h"
#endif /* FEATURE_UIM_RUIM */
/*===========================================================================
LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE
This section contains local definitions for constants, macros, types,
variables and other items needed by this module.
===========================================================================*/
#define CAVE_VPM_SIZE 65
/* Size of VPM in bytes. */
#define CAVE_AAV (0xC7)
/* Authentication Algorithm Version */
LOCAL dword CAVE_esn;
/* The electronic serial number of this phone. */
LOCAL qword CAVE_A_key;
/* The current A_key in use for CAVE */
LOCAL qword CAVE_SSD_A;
/* The current A value of Shared Secret Data in use for CAVE */
LOCAL qword CAVE_SSD_B;
/* The current B value of Shared Secret Data in use for CAVE */
LOCAL qword CAVE_new_SSD_A;
/* A possible new A value of Shared Secret Data */
LOCAL qword CAVE_new_SSD_B;
/* A possible new B value of Shared Secret Data */
LOCAL byte CAVE_NAM_index;
/* Index of current NAM being used */
LOCAL dword CAVE_lfsr;
/* The linear (actually non-linear) feedback shift register used
in the CAVE algorithm. */
LOCAL dword CAVE_saved_lfsr;
/* Value of lfsr saved from the authentication that is to be used
as seed for encryption and voice privacy */
LOCAL byte CAVE_mixing_reg[16];
/* The mixing registers used in the CAVE algorithm */
LOCAL byte CAVE_offset_1, CAVE_offset_2;
/* Offsets into the CAVE table used in the CAVE algorithm */
LOCAL byte CAVE_saved_offset_1, CAVE_saved_offset_2;
/* Values of offset_1 and offset_2 saved from the authentication
that is to be used as seed for encryption and voice privacy */
LOCAL dword CAVE_saved_rand;
/* Value of rand_challenge saved from the authentication that is
to be used as seed for encryption and voice privacy */
LOCAL dword CAVE_saved_data;
/* Value of auth_data saved from the authentication that is to be used
as seed for encryption and voice privacy */
LOCAL byte CAVE_CMEA_key[8];
/* Key used for message encryption */
LOCAL byte CAVE_VPM[CAVE_VPM_SIZE];
/* 520 bit voice privacy mask. Actually, only the 40 LSBits of this
are ever used. VPM[64] is the least significant byte. */
/*-------------------------------------------------------------------------
CAVE Table
This table is taken from Exhibit 2-3 of "Common Cryptographic Algorithms"
It is really two tables: the LS nibble of each entry is table0, and
the MS nibble of each entry is table1.
-------------------------------------------------------------------------*/
#define LOMASK 0x0F /* Mask all but the least significant nibble */
#define HIMASK 0xF0 /* Mask all but the most significant nibble */
static byte const CAVE_table[256] = {
/* 0 */ 0xd9, 0x23, 0x5f, 0xe6, 0xca, 0x68, 0x97, 0xb0,
0x7b, 0xf2, 0x0c, 0x34, 0x11, 0xa5, 0x8d, 0x4e,
/* 1 */ 0x0a, 0x46, 0x77, 0x8d, 0x10, 0x9f, 0x5e, 0x62,
0xf1, 0x34, 0xec, 0xa5, 0xc9, 0xb3, 0xd8, 0x2b,
/* 2 */ 0x59, 0x47, 0xe3, 0xd2, 0xff, 0xae, 0x64, 0xca,
0x15, 0x8b, 0x7d, 0x38, 0x21, 0xbc, 0x96, 0x00,
/* 3 */ 0x49, 0x56, 0x23, 0x15, 0x97, 0xe4, 0xcb, 0x6f,
0xf2, 0x70, 0x3c, 0x88, 0xba, 0xd1, 0x0d, 0xae,
/* 4 */ 0xe2, 0x38, 0xba, 0x44, 0x9f, 0x83, 0x5d, 0x1c,
0xde, 0xab, 0xc7, 0x65, 0xf1, 0x76, 0x09, 0x20,
/* 5 */ 0x86, 0xbd, 0x0a, 0xf1, 0x3c, 0xa7, 0x29, 0x93,
0xcb, 0x45, 0x5f, 0xe8, 0x10, 0x74, 0x62, 0xde,
/* 6 */ 0xb8, 0x77, 0x80, 0xd1, 0x12, 0x26, 0xac, 0x6d,
0xe9, 0xcf, 0xf3, 0x54, 0x3a, 0x0b, 0x95, 0x4e,
/* 7 */ 0xb1, 0x30, 0xa4, 0x96, 0xf8, 0x57, 0x49, 0x8e,
0x05, 0x1f, 0x62, 0x7c, 0xc3, 0x2b, 0xda, 0xed,
/* 8 */ 0xbb, 0x86, 0x0d, 0x7a, 0x97, 0x13, 0x6c, 0x4e,
0x51, 0x30, 0xe5, 0xf2, 0x2f, 0xd8, 0xc4, 0xa9,
/* 9 */ 0x91, 0x76, 0xf0, 0x17, 0x43, 0x38, 0x29, 0x84,
0xa2, 0xdb, 0xef, 0x65, 0x5e, 0xca, 0x0d, 0xbc,
/* a */ 0xe7, 0xfa, 0xd8, 0x81, 0x6f, 0x00, 0x14, 0x42,
0x25, 0x7c, 0x5d, 0xc9, 0x9e, 0xb6, 0x33, 0xab,
/* b */ 0x5a, 0x6f, 0x9b, 0xd9, 0xfe, 0x71, 0x44, 0xc5,
0x37, 0xa2, 0x88, 0x2d, 0x00, 0xb6, 0x13, 0xec,
/* c */ 0x4e, 0x96, 0xa8, 0x5a, 0xb5, 0xd7, 0xc3, 0x8d,
0x3f, 0xf2, 0xec, 0x04, 0x60, 0x71, 0x1b, 0x29,
/* d */ 0x04, 0x79, 0xe3, 0xc7, 0x1b, 0x66, 0x81, 0x4a,
0x25, 0x9d, 0xdc, 0x5f, 0x3e, 0xb0, 0xf8, 0xa2,
/* e */ 0x91, 0x34, 0xf6, 0x5c, 0x67, 0x89, 0x73, 0x05,
0x22, 0xaa, 0xcb, 0xee, 0xbf, 0x18, 0xd0, 0x4d,
/* f */ 0xf5, 0x36, 0xae, 0x01, 0x2f, 0x94, 0xc3, 0x49,
0x8b, 0xbd, 0x58, 0x12, 0xe0, 0x77, 0x6c, 0xda
};
/*-------------------------------------------------------------------------
Macros to access individual bytes of the LFSR
These macros exist to make the code in this module read more like
the pseudocode in "Common Cryptographic Algorithms".
Note: these macros are lvalues, so you can say LFSR_A = x.
Caution: the macros depend on Intel byte order.
-------------------------------------------------------------------------*/
#define LFSR_A (B_PTR(CAVE_lfsr)[3])
#define LFSR_B (B_PTR(CAVE_lfsr)[2])
#define LFSR_C (B_PTR(CAVE_lfsr)[1])
#define LFSR_D (B_PTR(CAVE_lfsr)[0])
#if !defined (FEATURE_UIM_RUIM) || defined (FEATURE_UIM_RUN_TIME_ENABLE)
/*===========================================================================
FUNCTION CAVE_init
DESCRIPTION
This function is called to perform initialization for the CAVE
operations. This mainly involves setting some variables from their
values in semi-permanent memory.
DEPENDENCIES
This function should only be called once on powerup or NAM change,
or when the A_Key is changed.
RETURN VALUE
AUTH_INIT_OK if initialization is successful
AUTH_UNINITIALIZED if initialization fails
SIDE EFFECTS
None.
===========================================================================*/
auth_init_status_type CAVE_init
(
byte NAM_index
/* NAM which CAVE variables will be taken from */
)
{
nv_item_type nv_item;
/* Item to hold values retrieved from NV */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* --------------------------------------------------
** Read the ESN first so that no matter what happens,
** the ESN is valid for use in CAVE_validate_A_key().
** -------------------------------------------------- */
#if (TG!=T_PC)
(void) auth_get_nv_item(NV_ESN_CHKSUM_I, &nv_item);
if (nv_item.esn_chksum.chksum != NV_VALID_ESN_CHKSUM)
{
ERR("Invalid ESN", 0, 0, 0);
return (AUTH_UNINITIALIZED);
}
#endif
(void) auth_get_nv_item( NV_ESN_I, &nv_item );
CAVE_esn = nv_item.esn.esn;
/* ---------------------------------------------
** The a_key_checksum is now ignored, and zero
** is assumed if the a_key isn't available.
** --------------------------------------------- */
nv_item.a_key.nam = NAM_index;
if (auth_get_nv_item( NV_A_KEY_I, &nv_item ) == NV_DONE_S)
{
qw_equ( CAVE_A_key, nv_item.a_key.key );
}
else
{
MSG_HIGH("Uninitialized value of A-key", 0, 0, 0);
qw_set( CAVE_A_key, 0L, 0L );
}
/* -------------------------------------------
** SSD checksums are no longer used, and zero
** is assumed for SSD if it is not available.
** ------------------------------------------- */
nv_item.ssd_a.nam = NAM_index;
if (auth_get_nv_item( NV_SSD_A_I, &nv_item ) == NV_DONE_S)
{
qw_equ( CAVE_SSD_A, nv_item.ssd_a.ssd );
}
else
{
MSG_HIGH("Uninitialized value of SSD A", 0, 0, 0);
qw_set( CAVE_SSD_A, 0L, 0L );
}
nv_item.ssd_b.nam = NAM_index;
if (auth_get_nv_item( NV_SSD_B_I, &nv_item ) == NV_DONE_S)
{
qw_equ( CAVE_SSD_B, nv_item.ssd_b.ssd );
}
else
{
MSG_HIGH("Uninitialized value of SSD B", 0, 0, 0);
qw_set( CAVE_SSD_B, 0L, 0L );
}
CAVE_NAM_index = NAM_index;
MSG_MED("CAVE initialized", 0L, 0L, 0L);
return (AUTH_INIT_OK);
} /* CAVE_init */
/*===========================================================================
FUNCTION CAVE_LFSR_cycle
DESCRIPTION
This function cycles the linear feedback shift register (lfsr) once.
It implements the LFSR specified in "Common Cryptographic Algorithms."
DEPENDENCIES
None.
RETURN VALUE
None.
SIDE EFFECTS
None.
===========================================================================*/
LOCAL void CAVE_LFSR_cycle(void)
{
boolean new_bit;
/* The new bit to shift in on the left */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Compute the new bit to shift in. It is the XOR
of four specific bits from the old state value. */
/*lint -e514 Yes, I mean to XOR Booleans. */
new_bit = ((LFSR_B & 0x40) != 0 )
^ ((LFSR_D & 0x04) != 0 )
^ ((LFSR_D & 0x02) != 0 )
^ ((LFSR_D & 0x01) != 0 ) ;
/*lint -restore */
/* This isn't very efficient. Keep it straightforward for now. */
CAVE_lfsr >>= 1; /* Shift the shift register */
/* Bring in the new bit */
if (new_bit != 0)
{
CAVE_lfsr |= 0x80000000L;
}
} /* CAVE_LFSR_cycle */
/*===========================================================================
FUNCTION CAVE_rotate_right_registers
DESCRIPTION
This function rotates the mixing_reg[] array, considered as a single
128-bit value, right by one place. The former LSbit becomes the new
MSbit.
Notice that mixing_reg[0] is consider the MSbyte.
DEPENDENCIES
None.
RETURN VALUE
None.
SIDE EFFECTS
None.
===========================================================================*/
LOCAL void CAVE_rotate_right_registers( void )
{
boolean new_bit;
/* The new bit to shift in on the left */
int R_index;
/* Index into the mixing_reg array */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Pick off the old LSbit for end-around-carry */
new_bit = CAVE_mixing_reg[15] & 0x01;
/* Shift right bytewise */
for (R_index = 15; R_index >= 1; R_index--)
{
CAVE_mixing_reg[R_index] >>= 1; /* Shift a byte */
if (CAVE_mixing_reg[R_index-1] & 0x01) /* Propagate the carry bit */
{
CAVE_mixing_reg[R_index] |= 0x80;
}
}
CAVE_mixing_reg[0] >>= 1; /* Shift the last byte */
if (new_bit) /* Bring in the end-around carry */
{
CAVE_mixing_reg[0] |= 0x80;
}
} /* CAVE_rotate_right_registers */
/*===========================================================================
FUNCTION CAVE_ROUNDS
DESCRIPTION
This function performs the specified number of rounds of the CAVE
algorithm. It operates on the values found in the regional mixing_reg,
and leaves its results there.
Note that variable names and the structure of this function follow
the pseudocode definition given in Exhibit 2-2 of "Common Cryptographic
Algorithms".
DEPENDENCIES
The regionals mixing_reg, lfsr, offset_1, and offset_2 must be properly
initialized before calling this function.
RETURN VALUE
None.
SIDE EFFECTS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -