There are three types of keys in the banking system: master key/pinkey/Mackey. The pinkey is used to encrypt the password, and the mackey is used to verify whether the message has an error code, the CMK is used to encrypt pinkey and mackey.
CMK encryption pinkey and mackey are encrypted and decrypted using 3des.
The Code is as follows:
/* Param: pKey: Key (hexadecimal) strPlainAKey: string to be decrypted (hexadecimal) ciperAKey: returned value iflag: 1 decryption 0 encryption */void getCiper (char * pKey, char * strPlainAKey, char * ciperAKey, int iflag) {unsigned char binPlainAKey [64] = {0}; hex2binary (binPlainAKey, strPlainAKey, strlen (strPlainAKey); substring (pKey, (unsigned char *) binPlainAKey, strlen (strPlainAKey)/2, (unsigned char *) ciperAKey, iflag );} /* param: pKey: Key (hexadecimal) inB Inary: encryption and decryption string byte form inLen: length of the encryption and decryption string binCharString: returned value iflag: 1 decryption 0 encryption */void ASCIIStr2BinCharStrBy3DES (char * pKey, unsigned char * inBinary, int inLen, unsigned char * binCharString, int iflag) {unsigned char targetIdBin [random] = {0}; // TargetIdLen = 8 // 3DES encription unsigned char key [LEN_OF_KEY]; unsigned char block_key [9]; memset (key, 0, LEN_OF_KEY); hex2binary (key, pKey, strlen (pKey); DES_ke Y_schedule ks, ks2, ks3; memset (block_key, 0, sizeof (block_key); memcpy (block_key, key + 0, 8); encrypt (const_DES_cblock *) block_key, & ks); memcpy (block_key, key + 8, 8); DES_set_key_unchecked (const_DES_cblock *) block_key, & ks2); memcpy (block_key, key + 0, 8 ); DES_set_key_unchecked (const_DES_cblock *) block_key, & ks3); unsigned char input [8]; memset (input, 0, sizeof (input); unsigned c Har groups [DESBINARY_LEN]; memset (encryptedOutBinary, 0, sizeof (encryptedOutBinary); for (int I = 0; I <inLen/8; I ++) {memset (targetIdBin, 0, sizeof (targetIdBin); memcpy (void *) targetIdBin, (const void *) (inBinary + I * 8), 8); substring (const_DES_cblock *) targetIdBin, (DES_cblock *) encryptedOutBinary, & ks, & ks2, & ks3, iflag); binary2char (char *) binCharString + I * 16, encryptedOutBinary, DESBINARY_LEN) ;}/// A public function: convert binary string to character string, the character string's length = 2 // binary string. // @ param charArray: character array. output. // @ param binArray: binary array. input. // @ param binLen: length of binary array. // void binary2char (char * charArray, const unsigned char * binArray, int binLen) {int I; for (I = 0; I <binLen; I ++) {sprintf (charArray + 2 * I, "% 02X", binArray [I]);} charArray [2 * I] = '\ 0';} // A public function: convert hex string to binary string, the hex string's length = 2 * binary string. // @ param binArray: binary array. output. // @ param hexCharArray: character array contains hex string. input. // @ param hexLen: length of hex string array. input. // void hex2binary (unsigned char * binArray, const char * hexCharArray, int hexLen) {I F (hexLen % 2! = 0) {printf ("hex2binary (): length of input parameter hexCharArray shocould be even number! \ N "); return;} int I, j; // convert two hex chars to one byte char atom [2 + 1] =" \ 0 "; for (I = 0, j = 0; I
In general, the ATM will use the master key to decrypt the pinkey ciphertext, get the pinkey plaintext, then generate the pinblock plaintext using the account + password, then use the pinkey to use 3des encryption, and then pass it to the backend
The algorithm for generating pinblock plaintext is:
Char uniteBytes (char a, char B) {char c = (int (a-'0') <4) + B-'0'; return c ;} /* ** getHPin * convert the password * PIN format * length of BYTE 1 PIN * BYTE 2-BYTE 3/4/5/6/7 4--12 PIN (each PIN occupies 4 bits) * BYTE 4/5/6/7/8-BYTE 8 FILLER "F" (each "F" occupies 4 bits) * @ param pin String * @ return byte [] */void getHPin (char * pin, char * encode) {encode [0] = 6; encode [1] = uniteBytes (pin [0], pin [1]); encode [2] = uniteBytes (pin [2], pin [3]); encod E [3] = uniteBytes (pin [4], pin [5]); encode [4] = 255; encode [5] = 255; encode [6] = 255; encode [7] = 255 ;} /*** getHAccno ** converts an account * BYTE 1-BYTE 2 0X0000 * BYTE 3-BYTE 8 12 primary Accounts * takes the right 12 digits of the primary account (not including the rightmost checkpoint ), the value of less than 12 digits is 0x00 ". * @ Param accno String * @ return byte [] */char * getHAccno (char * accno, char * encode) {int len = strlen (accno ); int beginPos = len <13? 0: len-13; char arrTemp [13] = {0}; memcpy (arrTemp, accno + beginPos, len-beginPos-1); char arrAccno [12]; for (int I = 0; I <12; I ++) {arrAccno [I] = (I <= strlen (arrTemp )? ArrTemp [I]: 0);} encode [0] = 0; encode [1] = 0; encode [2] = uniteBytes (arrAccno [0], arrAccno [1]); encode [3] = uniteBytes (arrAccno [2], arrAccno [3]); encode [4] = uniteBytes (arrAccno [4], arrAccno [5]); encode [5] = uniteBytes (arrAccno [6], arrAccno [7]); encode [6] = uniteBytes (arrAccno [8], arrAccno [9]); encode [7] = uniteBytes (arrAccno [10], arrAccno [11]); return encode ;} /* getPinBlock * Standard ANSI X9.8 Format (with primary account information) pin block calculation * The pin block Format is equal to PIN by bit or primary account; * @ param pin String * @ param accno String * @ return byte [] */void process (char * pin, char * accno, char * pHexRet) {char arrAccno [128] = {0}; getHAccno (accno, arrAccno); char arrPin [128] = {0}; getHPin (pin, arrPin ); unsigned char arrRet [8] = {0}; for (int I = 0; I <8; I ++) {arrRet [I] = (unsigned char) (arrPin [I] ^ arrAccno [I]);} binary2char (pHexRet, arrRet, 8 );}
Mac:
The ATM obtains the mackey, decrypts the CMK to obtain the plaintext of the key, uses a string of the macdata format agreed by both parties, and obtains the macblock through ANSI 9.19. The message is sent to the backend, And the backend performs the same operation, then compare and obtain the verification result.
The Ansi 9.19 algorithm is as follows:
Void xor (unsigned char * input1, unsigned char * input2, unsigned char * output, int len) {while (len) {* output ++ = * input1 ++ ^ * input2 ++; len -- ;}}/** @ brief: Calculate MAC based on input data, the default initial IV vector is "x00x00x00x00x00x00x00x00" * @ param: sMacKey key * @ param: pInData input data * @ param: MAC calculated by pRetData * @ call the custom xor and des functions */void MacArithmetic (char * sMacKey, char * inBinary, char * pRetData) {// MAC Algorithm: // The pInata string is divided into 8 bytes of data blocks. If the parameter is not supplemented with x00, the numbers are D1, D2, D3 ,..., dn // set the initial vector E0 = "x00x00x00x00x00x00x00x00x00" // encrypt E0 ^ D1 -----> E1 (E0, after D1 exclusive or exclusive, the result is obtained by using the left eight des of the key to get E1) // put E1 ^ D2 -----> E2 // and so on, knowing that En ends, // use the right 8-bit des of the key to decrypt the En to get En0 // use the left 8-bit encryption En0 to get En1 // En1 is the calculated MAC unsigned char sUpData [512]; unsigned char sData [20]; unsigned char sXorData [20]; unsigned char sDesData [20]; int I, n, iNum, iInLen; unsigned char key [16]; unsigned char block_key [9]; iInLen = strlen (inBinary); memset (key, 0, sizeof (key); hex2binary (key, sMacKey, strlen (sMacKey )); DES_key_schedule ks, ks2, ks3; memset (block_key, 0, sizeof (block_key); memcpy (block_key, key + 0, 8); encrypt (const_DES_cblock *) block_key, & ks); memcpy (block_key, key + 8, 8); DES_set_key_unchecked (const_DES_cblock *) block_key, & ks2); memcpy (block_key, key + 0, 8 ); aggregate (const_DES_cblock *) block_key, & ks3); memset (sUpData, 0, sizeof (sUpData); memset (sData, 0, sizeof (sData); memset (sXorData, 0, sizeof (sXorData); memset (sDesData, 0, sizeof (sDesData); // You must encrypt the data in multiples of 8 to sUpData. If not, you must complete the x00 memcpy (sUpData, inBinary, iInLen); iNum = iInLen % 8; if (iNum = 0) n = iInLen/8; else {n = iInLen/8 + 1; memcpy (sUpData + iInLen, "\ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0", 8-iNum);} printf ("n = % dnsUpData = [% s] n", n, sUpData); memset (sDesData, 0, sizeof (sDesData); // The initial vector is assigned to sDesData for (I = 0; I <n; I ++) {memcpy (sData, sUpData + I * 8); xor (sDesData, sData, sXorData, 8); // exclusive or DES_ecb_encrypt (const_DES_cblock *) sXorData, (DES_cblock *) sDesData, & ks, 1);} reverse (const_DES_cblock *) sDesData, (DES_cblock *) sXorData, & ks2, 0); DES_ecb_encrypt (const_DES_cblock *) sXorData, (DES_cblock *) sDesData, & ks, 1); binary2char (pRetData, sDesData, 8); return ;}