最近做项目遇到的问题

        产品需求是把积分查询以页面的形式展示,本来以为给一个url直接打开webview就行了,实际上远比想的要复杂,为了安全。

1,url是后台接口请求成功了才返回的。接口要上送sign和data两个参数,其中sign就是签名,通过一系列业务参数和请求头参数排序偏接,最后md5.

NSString *str=[NSString stringWithFormat:@"%@%@%@%@%@%@%@",@"F49E993869A212F3F505ED53",@"102",@"102",timeStt,@"1.1.1",@"102",vsTr];

      NSString *sign=[tool.md5 getMD5StringWithString:str] ;

data就是请求头参数和业务参数一起组合成一个字典,然后3des加密上送。

{
sign = "3ef8ca5186d7b301479bae31cb0c7de9",
data = "密文l",
}

差不多是这个意思,结果后台一直取值参数为空,sign和data取值都为nil,又出现以前的问题了,下班之前阿斌顺便说了句 form提交可以成功,按之前钱包后台的json恐怕不行,要不你试试

NSString *postString = [self getFormDataString:para];

        NSData *data = [postString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];

[request setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];

都已经这么设置了 ,但是还是反复收不到值。后来干脆下班了,走的时候跟楠哥打了个电话描述,楠哥人真的很好,看到别人有困难,发自内心尽自己能力帮忙,我描述完,楠哥答应了,楠哥一直是让人觉得有安全感很踏实的人。睡觉的时候还在想,该做的都做了,怎么就是收不到,后来想到只有data对应的value才需要加密,但是我感觉把整体字典都转data还加密了。觉得第二天自己再试试自己的猜想,要不然楠哥从头看起,或许更乱。

{
sign = "3ef8ca5186d7b301479bae31cb0c7de9",
data = "密文l",
}

 

所以此时后台根据原先的两个key  sign和data是怎么都取不到值的。因为key已经被我无意中加密了,为了快省事,复制以前的代码和经验。后来只好改过来第二天试试。后面的结果过不其然,验证了自己的猜想。人有时候总还算有些灵感的。或者说不到这个点,就是发现不了。

//       [request setHTTPBody:[[self encodeXML:data withKey:@"F49E993869A212F3F505ED53" application:nil] dataUsingEncoding:NSUTF8StringEncoding]];

    [request setHTTPBody:data];

       }

para指的就是这个字典 ,字段过多,就不展示了,大概7个key-value吧,组成个字典装下

//先转data

NSData *data = [NSJSONSerialization dataWithJSONObject:para options:NSJSONWritingPrettyPrinted error:nil];

//data转成字符串  然后3des加密  (因为这里需要传字符串,其实是字典变成data,然后data又变成字符串了,字典变成字符串很神奇,data竟然是桥梁)

、//TripleDES  加密方法  得到密文字符串

    NSString * encryptionData=[NSString TripleDES:[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding] encryptOrDecrypt:kCCEncrypt];

//拿到密文,组装成字典上送,这里做到两个key都没有加密,第二个value   data对应的值才加密。

    NSMutableDictionary *idic=[[NSMutableDictionary alloc] initWithDictionary:@{@"sign":sign,@"data":encryptionData}];

    

    [[YFCardCoponRequest sharedInstance] requestWithDictionary:idic hasLoading:@"" completion:^(BOOL success, id responseData) {

        if (responseData) {

              }

    }];

 

此时成功了一半,然后又遇到第二个问题,加密过去的data值 ,后台解不了。说有代码例子。

public static String encode(String data, String key){

              String result = "";

              try {

                     if (data == null || data.length() == 0) {

                            throw new RuntimeException();

                     }

 

                     DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));

                     SecretKeyFactory keyFactory = SecretKeyFactory

                                   .getInstance("DESede");

                     SecretKey securekey = keyFactory.generateSecret(dks);

                     Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

                     cipher.init(Cipher.ENCRYPT_MODE, securekey);

                     byte[] retByte = cipher.doFinal(Base64.encode(data.getBytes()).getBytes());

                     result = Base64.encode(retByte);

                     result = result.replace('+', '_').replace('=', '%')

                                   .replace('/', '*');

              } catch (Exception e) {

                     e.printStackTrace();

                     result = "";

 

              }

              return result;

       }

本人做iOS的只能看一个大概,于是没有仔细细看。就盯着DESede/ECB/PKCS5Padding  ,然后网上找个匹配的。后来找了四五套3des包括des的 类去匹配,结果总是解不开。问了下好友来瑞松。说你最好把java发过来的加密方法,随便找个串加密了对比下,跟你加出来是是不是一样的。然后把java的加解密类导入eclipse,果真不一样,

 

然后开始仔细阅读和理解java的这段加密过程,在对比我找的几套加密,一步步参照,发现最后

result = Base64.encode(retByte);

   result = result.replace('+', '_').replace('=', '%').replace('/', '*');//这是重点,本来已经拿到result,还有字符替换。原来他们也是网上找的java加密类,只是他们也担心安全就在结尾处拿到加密串了,替换某些字符,然后解密的时候也跟着替换了。网上找的现成了,自己还改了,那我网上找的对的也匹配不上啊。。。。

明白这里我也跟着在方法里面加这些所谓的替换。跟旭东一起研究,因为他是原先做iOS,然后自学java转过去的。可惜的是,到后来加密出来的结果还是对不上,可喜的是长度一致!到这里真的没有招了,网上找的人家写好的加密类,又是对着java的加密最后字符替换。自己写,底层的不太明白,后台说正好商城的同事有现成的,要不过来试试,怎么才说!安卓直接现成的,拿过去都不用调,所以做安卓还是很有优势的,语言一致,不存在这些问题!

商城的同事后来发过来一个类,放在项目里面直接用,是成功的,以为他们之前已经调过了。得到前面的验证。发现和龙哥发过来的方法看上去几乎一样,

还有特别的说明,这是个大神级别的,实力不容怀疑的。在我们看来,他出现了就有安全,就没有解决不了的问题。手机银行号称。

 

正好替换字符,也正是他发的这个方法上改写的。他都说了 ,好多项目都是用的这个。连银行都用的这个,应该是加解密写法肯定没问题了。

对比了下商城同事发过来的 ,有两点不一样,其中一个影响很大,一个几乎没有影响,

一是

  Byte iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};   //商城的同事发过来的这行是注释的

    ccStatus = CCCrypt(encryptOrDecrypt,

                       kCCAlgorithm3DES,

                       kCCOptionPKCS7Padding|kCCOptionECBMode,

                       vkey,

                       kCCKeySize3DES,

                       iv,                       //这里他们就传nil

                       vplainText,

                       plainTextBufferSize,

                       (void *)bufferPtr,

                       bufferPtrSize,

                       &movedBytes);

                           

二是,也是这段代码       ,设置模式商城的同事是 kCCOptionPKCS7Padding|kCCOptionECBMode,

龙哥给的是kCCOptionPKCS7Padding。

然后问题就在这里了,后来我们得到的是长度一致,内容不一样。第一个  Byte iv[]  这个传也行,传nil也不会有影响,|kCCOptionECBMode  这个是必须要加的,以防止万一,结果我们的后台对调就遇到了,他们的代码里面Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

第一个说的是3des方式加密  第二个是加密模式ECB     第三个是长度(具体不明白,有的说5位的 128字节一段加密,当然还有256位的)

没有加,导致模式不是ECB的 ,而且长度和PKCS5Padding么有一个有效的匹配,iOS里面这个没得选,只有个7pading的 

开始怀疑 kCCOptionECBMode  这个的指定是任何长度的匹配和模式的指定。不过只是怀疑,最后加上这个就加密结果一样。后面的流程很顺,前面准备的数据也没错。

补充一点的就是加签和验签,加签方式前面说过了,偏接字符串,md5,把加密串给后台就行。验签是这样,后台也会返回个sign对应字段有个值,我这边需要偏接下返回来的其他的业务参数,做一下md5去比较,如果一致,验签通过。防止数据被串改。其实按照斌仔说的 ,url都直接返回了,打开就行了。呵呵

NSString *str=[NSString stringWithFormat:@"%@%@%@",@"F49E993869A212F3F505ED53",dic[@"respCode"],dic[@"result"][@"url"]];

                NSString *sign=[tool.md5 getMD5StringWithString:str] ;

                if ([signResp isEqual:sign]) {        //指的是后台接口成功返回的

                    completion(YES,dic);

       }

说了一大堆,也行只能自己看懂,不过确实印象很深,康斌到后来问了说学到不少东西了吧。确实是,加密的过程有更深的理解。第一个坑是自己挖的,没有人讨论的话,有时候很难发现,总以为是java取值,转流的问题。深刻的记录一次!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值