开源Objective-C语言封装的iso8583协议实现

image

这几年接触了蛮多的8583协议,有银联标准版,到各大银行,有些第三方收单平台,大家都在使用iso8583报文协议,但是各个机构制定的协议又都各具特色,不尽相同。不过以我的经验,差别最大的还是各机构在处理密钥方面差别比较大,银联的自不必说,各成员机构也在密钥体系,加密算法等方面稍有差异,不过总得说来是大同小异。

我前后使用C语言、PHP语言、Python语言、C++语言实现过银联标准版的POS终端协议规范,其中PHP和Python版是计划开发作为模拟测试用的,后来进入互联网支付行业,开始iOS的开发,采用的协议也就改为HTTP的方式了,直接的socket使用的就比较少了。恰好,最近帮助朋友开发一个项目,在这个项目中,我又开始接触到了久违的8583协议,于是筹划自己实现一套。

在我筹划过程中,发现已经有一位开发者采用C语言已经实现了这套协议,而且还开源了,在阅读了其源码之后,我深感自己再实现一遍,也不会有他那么完善了,所以我打算采用OC封装他的实现,这样大大缩短了我的开发时间,因为是基于开源的代码,所以我也计划把我封装的代码开源了。一来感谢前人的开源,二来网上这方面的资源也比较少,希望可以帮助其他的同仁,共同进步。

以上就是开源的缘起了,当然开源中去掉了非行业通用做法的部分接口,加之各机构协议上的细小差异,所以你需要作下改造才行。不过基础的8583打包,解包,DES,3DES,PIN的加密(带PAN信息),MAC的计算(非银联版)。

包括一些字节转换的方法,TLV格式的打包解包也是采用网上的开源代码。最后简单地介绍一下这个开源项目吧,如果需要了解实现细节,我觉得代码胜过一切。

ObjC-PZ8583是基于BerTlv和Oscar-ISO8583的基础上进行的iOS封装,底层8583的打包和拆包使用了C语言的Oscar-ISO8583版本,为了适应开发需求,进行了Objective-C的封装,使得使用起来更方便一些。

附件一段签到的代码实现吧,项目源码地址:ObjC-PZ8583。Enjoy it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
- (void)mposGetWorkKeyFromServerWithBlock:(void(^)(NSString *text))display {
    display(@"----------------签到-------------");
//    NSString *lmk = @"a2dff4e59289a82fc740f4f4e5d997e6";
    NSString *lmk = self.masterKey;
    BOOL ret =[self.sockMgr startStop];
    if (ret ) {
        PZSignInRequest *request = [PZSignInRequest new];
        [request.posFields setTranTtc:self.transTtc];
        [request.posFields setTerminalId:self.terminalId];
        [request.posFields setMerchantId:self.merchantId];
        PZPrivateField60 *field60 = [PZPrivateField60 new];
        field60.msgType = kSignInField60MsgType;
        field60.batchNumber = self.batchNumber;
        field60.networkCode = kSignInField60Network;
        [request.posFields setPrivate60:[field60 encode]];
        [request setOprNumber:@"01 "];

        NSData *data = [request encode];
        NSLog(@"send:%@",data);

        display(request.posFields.description);

        __block NSData *recvData = nil;
        [self.sockMgr sendDataToServer:data finishCallBack:^(NSData *pospData,NSError *error){
            if (!error) {
                recvData = [pospData subdataWithRange:NSMakeRange(2, pospData.length -2)];

                PZSignInResponse  *signResp = [PZSignInResponse new];
                [signResp decode:recvData];

                display(signResp.posFields.description);

                if ([signResp.respCode isEqualToString:kResponseCodeSuccess00]) {
                    NSLog(@"%@",[signResp.private62 description]);
                    PZPrivateField62    *field62 = signResp.private62;
                    NSString *pinKey = [NSString decrypt3Des:field62.pinKey withKey:lmk];
                    NSString *macKey = [NSString decrypt3Des:field62.macKey withKey:lmk];
                    NSString *trkKey = [NSString decrypt3Des:field62.trkKey withKey:lmk];

                    NSString    *pinCheck = [NSString encrypt3Des:@"0000000000000000" withKey:pinKey];
                    NSString    *macCheck = [NSString encrypt3Des:@"0000000000000000" withKey:macKey];
                    NSString    *trkCheck = [NSString encrypt3Des:@"0000000000000000" withKey:trkKey];

                    NSLog(@"pinkey:%@,check:%@;macKey:%@,check:%@;trkKey:%@,check:%@",pinKey,pinCheck,macKey,macCheck,trkKey,trkCheck);
                    NSString    *log = [NSString stringWithFormat:@"%@\npinkey:%@,check:%@;macKey:%@,check:%@;trkKey:%@,check:%@",[signResp.private62 description],pinKey,pinCheck,macKey,macCheck,trkKey,trkCheck];
                    display(log);

                    self.pinKey = pinKey;
                    self.macKey = macKey;
                    self.trkKey = trkKey;

                } else {
                    NSLog(@"response:%@",signResp.respCode);
                }
            }
            [self.sockMgr didDisconnected];
        }];
    }
}
作者: Peter
出处: http://codefunny.github.io/
本文基于
署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 Peter(包含链接)。