• 银行密钥体系


    银行系统的密钥有三种,主密钥/pinkey/Mackey,其中pinkey是用来加密密码的,而mackey是用来校验报文是否有错码,主密钥是用来加密pinkey和mackey的.

    其中主密钥加密pinkey和mackey是是用3des来加解密的

    代码如下:

    /*
    param:
        pKey:密钥(十六进制)
        strPlainAKey:需要加解密的字符串(十六进制) 
        ciperAKey:返回值
        iflag:1解密 0加密
    */
    void getCiper(char* pKey, char* strPlainAKey, char* ciperAKey,  int iflag)
    {
        unsigned char binPlainAKey[64] = {0};
        hex2binary(binPlainAKey, strPlainAKey, strlen(strPlainAKey));
        ASCIIStr2BinCharStrBy3DES(pKey,(unsigned char*)binPlainAKey,strlen(strPlainAKey)/2, (unsigned char*)ciperAKey, iflag);
    }
    
    /*
    param:
        pKey:密钥(十六进制)
        inBinary:加解密字符串的字节形式
        inLen:加解密字符串的长度
        binCharString:返回值
        iflag:1解密 0加密
    */
    void ASCIIStr2BinCharStrBy3DES(char* pKey, unsigned char* inBinary, int inLen, unsigned char* binCharString,int iflag)
    {
        unsigned char targetIdBin[DESBINARY_LEN] = {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_key_schedule ks,ks2,ks3;
    
    
        memset(block_key, 0, sizeof(block_key));  
        memcpy(block_key, key + 0, 8); 
        DES_set_key_unchecked((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 char encryptedOutBinary[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);
            DES_ecb3_encrypt((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] = '';
    }
    
    
    //
    // 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)
    {
            if (hexLen%2 != 0)
            {
                printf("hex2binary(): length of input parameter hexCharArray should be even number!
    ");
                return;
            }
    
    
            int i, j;
            //convert two hex chars to one byte
            char atom[2 + 1] = "";
            for (i = 0, j = 0; i < hexLen/2; i++, j+=2)
            {
                strncpy(atom, hexCharArray + j, sizeof(atom) - 1);
                atom[sizeof(atom) - 1] = '';
                binArray[i] = (unsigned char)strtol(atom, NULL, 16);
            }
    }

    一般来说,ATM拿到pinkey密文会使用主密钥解密,得到pinkey明文,然后是用帐号+密码生成pinblock明文,然后使用pinkey使用3des加密,然后传给后端

    生成pinblock明文的算法为:

    char uniteBytes(char a,char b)
    {
        char c = (int(a-'0')<<4)+b-'0';
        return c;
    }
    /**
        * getHPin
        * 对密码进行转换
        * PIN格式
        * BYTE 1 PIN的长度
        * BYTE 2 – BYTE 3/4/5/6/7 4--12个PIN(每个PIN占4个BIT)
        * BYTE 4/5/6/7/8 – BYTE 8 FILLER “F” (每个“F“占4个BIT)
        * @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]);
        encode[3] = uniteBytes(pin[4], pin[5]);
        encode[4] = 255;
        encode[5] = 255;
        encode[6] = 255;
        encode[7] = 255;
    }
    
        /**
        * getHAccno
        * 对帐号进行转换
        * BYTE 1 — BYTE 2 0X0000
        * BYTE 3 — BYTE 8 12个主帐号
        * 取主帐号的右12位(不包括最右边的校验位),不足12位左补“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
        * 标准ANSI X9.8 Format(带主帐号信息)的PIN BLOCK计算
        * PIN BLOCK 格式等于 PIN 按位异或 主帐号;
        * @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运算:

    ATM拿到mackey,通过主密钥解密得到密钥明文,使用一串双方协议好的macdata格式,通过ANSI 9.19得到macblock,随报文发到后端,后端也会做同样的操作,然后比对,得到校验结果

    Ansi 9.19的算法如下

    void xor(unsigned char *input1,unsigned char *input2,unsigned char *output,int len)
    {
        while (len) {
            *output++=*input1++^*input2++;
            len--;
        }
    }
    
    
    /*
    *@brief: 根据输入数据计算MAC,初始IV向量默认为"x00x00x00x00x00x00x00x00"
    *@param: sMacKey 密钥
    *@param: pInData 输入数据
    *@param: pRetData 计算出来的MAC
    *@调用自定义xor和des函数
    */
    
    void MacArithmetic(char *sMacKey,char *inBinary,char *pRetData)
    {
    //MAC算法:
    //将字符串pInata分为8字节为单位的数据块,不足补x00,分别标号为D1,D2,D3,...,Dn
    //设置初始向量E0="x00x00x00x00x00x00x00x00"
    //将E0^D1 —---->E1(E0,D1异或的后结果经使用密钥左8位des加密得到E1)
    //将E1^D2 ----->E2
    //如此类推,知道得出En结束,
    //使用密钥右8位des解密En得到En0
    //使用密钥左8位加密En0得到En1
    //En1即是计算出来的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); 
        DES_set_key_unchecked((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); 
    
        memset(sUpData,0,sizeof(sUpData));
        memset(sData,0,sizeof(sData));
        memset(sXorData,0,sizeof(sXorData));
        memset(sDesData,0,sizeof(sDesData));
    
    
    //补全要加密数据成8倍数到sUpData,不足补x00
        memcpy(sUpData,inBinary,iInLen);
        iNum = iInLen%8;
        if (iNum == 0)
            n=iInLen/8;
        else {
            n=iInLen/8+1;
            memcpy(sUpData+iInLen,"",8-iNum);
        }
    
        printf("n=%dnsUpData=[%s]n",n,sUpData);
    
        memset(sDesData,0,sizeof(sDesData)); //初始向量赋给sDesData
        for (i=0;i<n;i++) {
            memcpy(sData,sUpData+i*8,8);
            xor(sDesData,sData,sXorData,8); //异或
            DES_ecb_encrypt((const_DES_cblock*)sXorData, (DES_cblock*)sDesData, &ks,1);
        }
        DES_ecb_encrypt((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 ;
    }
  • 相关阅读:
    [UWP] 为WinRT组件创建Nuget包
    再见北京,深圳你好
    [UWP] 用 AudioGraph 来增强 UWP 的音频处理能力——AudioFrameInputNode
    [UWP] 用 AudioGraph 来增强 UWP 的音频处理能力
    UWP 多语言的三个概念
    利用 Win32 启动和检测 UWP App 的方法
    反向代理教务系统
    [UWP] Custom Capability的使用
    [UWP]针对UWP程序多语言支持的总结,含RTL
    Xamarin自定义布局系列——支持无限滚动的自动轮播视图CarouselView
  • 原文地址:https://www.cnblogs.com/kukafeiso/p/3793178.html
Copyright © 2020-2023  润新知