zoukankan      html  css  js  c++  java
  • iOS与PHP/Android AES128 ECB NoPadding加密

    前言

    谈谈AES加密,网上有很多的版本,当我没有真正在加密安全问题前,总以为百度出来某个AES加密算法就可以直接使用,实际上当我真正要做加密时,遇到了很多的坑,原来不是拿过来就能用的。写下本篇文章,记录下曾经遇到的坑,严防以后再出现同样的坑。

    AES规则

    原输入数据不够16字节的整数位时,就要补齐。因此就会有padding,若使用不同的padding,那么加密出来的结果也会不一样。

    AES加密算法

    苹果提供给我们的API只有这一个函数用来加密或者解密:

    • 其中第一个CCOperation只有两个值,要么是kCCEncrypt表示加密,要么是kCCDecrypt表示解密。
    • 第二个参数表示加密的算法,它只有以下向种类型:

    我们这里使用的是kCCAlgorithmAES128表示使用AES128位加密。

    • 第三个参数表示选项,这里使用的是kCCOptionECBMode,表示ECB:
    • 第四个参数表示加密/解密的密钥。
    • 第五个参数keyLength表示密钥的长度。
    • 第六个参数iv是个固定值,通过直接使用密钥即可。大家一定要注视这个参数,如果安卓、服务端和iOS端不统一,那么加密结果就会不一样,解密可能能解出来,但是解密后在末尾会出现一些、 之类的。
    • 第七个参数dataIn表示要加密/解密的数据。
    • 第八个参数dataInLength表示要加密/解密的数据的长度。
    • 第九个参数dataOut用于接收加密后/解密后的结果。
    • 第十个参数dataOutAvailable表示加密后/解密后的数据的长度。
    • 第十一个参数dataOutMoved表示实际加密/解密的数据的长度。(因为有补齐)

    加密算法

    依赖于第三方库:GTMBase64,这个库已经几年没有维护了,现在还是MRC版本,要使用请到GITHUB查看使用教程,那里有ARC接入说明:

    对于加密算法,大家一定要注意,保证iOS、安卓、服务端的加密规则是一定的,建议统一使用No Padding的,这里使用No Padding是这样的:

    其实所谓Padding就是指在位数不够需要补齐时,使用什么来填充,而No Padding就是使用16个0,对应0x0000.如果三端不统一,加密出来就算能解密,也会出现一些奇怪的字符,甚至会有部分乱码。

    另外,这里使用的是kCCOptionECBMode,也就是ECB。在安卓端和PHP端,也得使用ECB。在调试过程中,发现PHP使用CBC解密不了IOS端的。于是改成了使用ECB。

    解密算法

    依赖于第三方库:GTMBase64,这个库已经几年没有维护了,现在还是MRC版本,要使用请到GITHUB查看使用教程,那里有ARC接入说明:

    解密时也得跟加密一样指定为ECB,否则解出来会出现乱码,或者末尾会出现、 之类的符号。

    写在最后

    开发中总会遇到各种坑,网上查了很多的资料,但是终究没有说明解决的办法,而是只将自己的代码放出来。对于刚接触这方面知识的开发人员来说,是很懵懂的。甚至很多新手会觉得系统就是这样的,我也没办法。其实总会有解决办法的,关键在于与其他各端统一连调。

    • 一行代码实现加密

    更新:MD5加密是单向的,只能加密不能解密(破解除外)。标题可能会引起读者误解,已经改正,感谢Li_Cheng同学的提醒,另外笔者发现Li_Cheng同学有篇MD5加密更为详尽的文章,推荐阅读:iOS开发 关于MD5加密的相关使用

    加密的Demo,欢迎下载

    java端的加密解密,读者可以看我同事的这篇文章http://www.jianshu.com/p/98569e81cc0b

    最近做了一个移动项目,是有服务器和客户端类型的项目,客户端是要登录才行的,服务器也会返回数据,服务器是用Java开发的,客户端要同时支持多平台(Android、iOS),在处理iOS的数据加密的时候遇到了一些问题。起初采取的方案是DES加密,老大说DES加密是对称的,网络抓包加上反编译可能会被破解,故采取RSA方式加密。RSA加密时需要公钥和私钥,客户端保存公钥加密数据,服务器保存私钥解密数据。(iOS端公钥加密私钥解密、java端公钥加密私钥解密,java端私钥加密公钥解密都容易做到,iOS不能私钥加密公钥解密,只能用于验签)。

    问题

    问题1:iOS端公钥加密的数据用Java端私钥解密。

    iOS无论使用系统自带的sdk函数,用mac产生的或者使用java的jdk产生的公钥和私钥,进行加密解密自己都可以使用。不过ios加密,java解密,或者反过来就不能用了。要么是无法创建报告个-9809或-50的错误,要么解出来是乱码。ios系统函数种只有用公钥加密,私钥解密的方式。而公钥加密每次结果都不同。

    MAC上生成公钥、私钥的方法,及使用
    • 1.打开终端,切换到自己想输出的文件夹下
    • 2.输入指令:openssl(openssl是生成各种秘钥的工具,mac已经嵌入
    • 3.输入指令:genrsa -out rsa_private_key.pem 1024 (生成私钥,java端使用的)
    • 4.输入指令:rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout (生成公钥)
    • 5.输入指令:pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt(私钥转格式,在ios端使用私钥解密时用这个私钥)
      注意:在MAC上生成三个.pem格式的文件,一个公钥,两个私钥,都可以在终端通过指令vim xxx.pem 打开,里面是字符串,第三步生成的私钥是java端用来解密数据的,第五步转换格式的私钥iOS端可以用来调试公钥、私钥解密(因为私钥不留在客户端)
      详细步骤

    问题2:服务器返回数据也要加密,老大打算用java私钥加密,ios用公钥解密(由于iOS做不到用私钥加密公钥解密,只能私钥加密公钥验签),所以这种方案也有问题。

    通过看一些大牛的介绍,了解了iOS常用的加密方式
    • 1 通过简单的URLENCODE + BASE64编码防止数据明文传输
    • 2 对普通请求、返回数据,生成MD5校验(MD5中加入动态密钥),进行数据完整性(简单防篡改,安全性较低,优点:快速)校验
    • 3 对于重要数据,使用RSA进行数字签名,起到防篡改作
    • 4 对于比较敏感的数据,如用户信息(登陆、注册等),客户端发送使用RSA加密,服务器返回使用DES(AES)加密
      原因:客户端发送之所以使用RSA加密,是因为RSA解密需要知道服务器私钥,而服务器私钥一般盗取难度较大;如果使用DES的话,可以通过破解客户端获取密钥,安全性较低。而服务器返回之所以使用DES,是因为不管使用DES还是RSA,密钥(或私钥)都存储在客户端,都存在被破解的风险,因此,需要采用动态密钥,而RSA的密钥生成比较复杂,不太适合动态密钥,并且RSA速度相对较慢,所以选用DES)
      所以此次加密,我们选择了第四种加密方式

    加密方式

    ios端进行DES加密、解密时非常方便

    1、引入头文件 #import "DES3Util.h"
    2、加密时调用类方法  +(NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key;
    3、解密时调用类方法  +(NSString *)decryptUseDES:(NSString *)cipherText key:(NSString *)key;

    ios端进行RSA加密、解密时非常方便

    1、引入头文件 #import "RSAUtil.h"
    2、公钥加密时调用类方法:
    + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;
    + (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey;
    3、私钥解密时调用类方法 
    + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey;
    + (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privKey;

    ios端进行MD5加密、解密时非常方便

    1、引入头文件 #import "MD5Util"
    2、加密时调用方法:- (NSString *)md5:(NSString *)str;

    ios端进行AES加密、解密时非常方便

    1、引入头文件 #import "AES.h"
    2、加密时调用方法
    + (NSString *)encrypt:(NSString *)message password:(NSString *)password;
    2、解密时调用的方法
    + (NSString *)decrypt:(NSString *)base64EncodedString password:(NSString *)password;

    有关RSA、MD5、AES加密的原理介绍

    • MD5加密

    iOS中提供了很多种加密算法,对于存储密码,可以使用不可逆的MD5加密。
    使用MD5加密需要导入头文件:
    ''#import <CommonCrypto/CommonDigest.h>

    ##### 简单的MD5加密
    + ( NSString *)md5String:( NSString *)str
    
    {
    
    const char *myPasswd = [str UTF8String ];
    
    unsigned char mdc[ 16 ];
    
    CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);
    
    NSMutableString *md5String = [ NSMutableString string ];
    
    for ( int i = 0 ; i< 16 ; i++) {
    
    [md5String appendFormat : @"%02x" ,mdc[i]];
    
    }
    
    return md5String;
    
    }
    
    ##### 复杂一些的MD5加密
    + ( NSString *)md5String:( NSString *)str
    
     {
    
     const char *myPasswd = [str UTF8String ];
    
     unsigned char mdc[ 16 ];
    
     CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);
    
     NSMutableString *md5String = [ NSMutableString string ];
    
     [md5String appendFormat : @"%02x" ,mdc[ 0 ]];
    
     for ( int i = 1 ; i< 16 ; i++) {
    
     [md5String appendFormat : @"%02x" ,mdc[i]^mdc[ 0 ]];
    •  AES加密

    高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法。 以下实现代码中分别为NSData和NSString增加了一个Category。使用时直接调用即可。

    需要注意的是,AES并不能作为HASH算法,加密并解密后的结果,并不一定与原文相同,使用时请注意进行结果验算。例如解密原文的长度,格式规则等。 NG实例

    原文:170987350
    密码:170

    Objective-c的AES加密和解密算法的具体实现代码如下: 1.拓展NSData,增加AES256加密方法

     
    //
    //NSData+AES256.h
    //
     
    #import <Foundation/Foundation.h>
    #import <CommonCrypto/CommonDigest.h>
    #import <CommonCrypto/CommonCryptor.h>
     
    @interface NSData(AES256)
    -(NSData *) aes256_encrypt:(NSString *)key;
    -(NSData *) aes256_decrypt:(NSString *)key;
    @end
     
     
    //
    //NSData+AES256.m
    //
    #import "NSData+AES256.h"
     
    @implementation NSData(AES256)
     
    - (NSData *)aes256_encrypt:(NSString *)key   //加密
    {
      char keyPtr[kCCKeySizeAES256+1];
      bzero(keyPtr, sizeof(keyPtr));
      [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
      NSUInteger dataLength = [self length];
      size_t bufferSize = dataLength + kCCBlockSizeAES128;
      void *buffer = malloc(bufferSize);
      size_t numBytesEncrypted = 0;
      CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                          keyPtr, kCCBlockSizeAES128,
                          NULL,
                          [self bytes], dataLength,
                          buffer, bufferSize,
                          &numBytesEncrypted);
      if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
      }
      free(buffer);
      return nil;
    }
     
     
    - (NSData *)aes256_decrypt:(NSString *)key   //解密
    {
      char keyPtr[kCCKeySizeAES256+1];
      bzero(keyPtr, sizeof(keyPtr));
      [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
      NSUInteger dataLength = [self length];
      size_t bufferSize = dataLength + kCCBlockSizeAES128;
      void *buffer = malloc(bufferSize);
      size_t numBytesDecrypted = 0;
      CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                          keyPtr, kCCBlockSizeAES128,
                          NULL,
                          [self bytes], dataLength,
                          buffer, bufferSize,
                          &numBytesDecrypted);
      if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
     
      }
      free(buffer);
      return nil;
    }
    @end

    2.拓展NSString,增加AES256加密方法,需要导入NSData+AES256.h

     
     
    //
    //NSString +AES256.h
    //
     
    #import <Foundation/Foundation.h>
    #import <CommonCrypto/CommonDigest.h>
    #import <CommonCrypto/CommonCryptor.h>
     
    #import "NSData+AES256.h"
     
    @interface NSString(AES256)
     
    -(NSString *) aes256_encrypt:(NSString *)key;
    -(NSString *) aes256_decrypt:(NSString *)key;
     
    @end
     
     
    //
    //NSString +AES256.h
    //
     
    @implementation NSString(AES256)
     
    -(NSString *) aes256_encrypt:(NSString *)key
    {
      const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
      NSData *data = [NSData dataWithBytes:cstr length:self.length];
      //对数据进行加密
      NSData *result = [data aes256_encrypt:key];
     
      //转换为2进制字符串
      if (result && result.length > 0) {
     
        Byte *datas = (Byte*)[result bytes];
        NSMutableString *output = [NSMutableString stringWithCapacity:result.length * 2];
        for(int i = 0; i < result.length; i++){
          [output appendFormat:@"%02x", datas[i]];
        }
        return output;
      }
      return nil;
    }
     
    -(NSString *) aes256_decrypt:(NSString *)key
    {   
      //转换为2进制Data
      NSMutableData *data = [NSMutableData dataWithCapacity:self.length / 2];
      unsigned char whole_byte;
      char byte_chars[3] = {'','',''};
      int i;
      for (i=0; i < [self length] / 2; i++) {
        byte_chars[0] = [self characterAtIndex:i*2];
        byte_chars[1] = [self characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
      }
     
      //对数据进行解密
      NSData* result = [data aes256_decrypt:key];
      if (result && result.length > 0) {
        return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]autorelease];
      }
      return nil;
    }
    @end
     
  • 相关阅读:
    解决Sublime 3提示 Sublime Text Error while loading PyV8 binary
    SQL中select与set的区别
    Microsoft Dynamics CRM 2011 安装完全教程
    sql语句优化
    CRM牛人博客
    Customize Spring @RequestParam Deserialization for Maps and/or Nested Objects
    Customize Spring @RequestParam Deserialization for Maps and/or Nested Objects
    Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(二)
    Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(二)
    使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境(一)
  • 原文地址:https://www.cnblogs.com/dzhs/p/5377060.html
Copyright © 2011-2022 走看看