iOS - 常用的加密方式

1.Base64 加密

1.1 Base64 简单说明

描述:Base64可以成为密码学的基石,非常重要。
特点:可以将任意的二进制数据进行Base64编码
结果:所有的数据都能被编码为并只用65个字符就能表示的文本文件。
65字符:A~Z a~z 0~9 + / =
对文件进行base64编码后文件数据的变化:编码后的数据~=编码前数据的4/3,会大1/3左右。

1.2编码原理
  1. 将所有字符转化为ASCII码;
  2. 将ASCII码转化为8位二进制;
  3. 将二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位;
  4. 统一在6位二进制前补两个0凑足8位;
  5. 将补0后的二进制转为十进制;
  6. 从Base64编码表获取十进制对应的Base64编码;
1.3实现
  • 从iOS7.0 以后,苹果就提供了Base64的编码和解码支持

编码:

-(NSString *)base64EncodeString:(NSString *)string{
  //1.先把字符串转换为二进制数据
  NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
  //2.对二进制数据进行base64编码,返回编码后的字符串
  return [data base64EncodedStringWithOptions:0];
 } 

解码:

-(NSString *)base64DecodeString:(NSString *)string{
  //1.将base64编码后的字符串『解码』为二进制数据
  NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0];
  //2.把二进制数据转换为字符串返回
  return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
 }
  • iOS7.0 以前,根据原理自己写个方法来实现编码解码(目前来说,大多数APP已经不支持iOS7.0了)

编码

+ (NSString *)base64EncodedStringFrom:(NSString *)string{
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    if ([data length] == 0)
        return @"";
    
    char *characters = malloc((([data length] + 2) / 3) * 4);
    if (characters == NULL)
        return nil;
    NSUInteger length = 0;
    
    NSUInteger i = 0;
    while (i < [data length])
    {
        char buffer[3] = {0,0,0};
        short bufferLength = 0;
        while (bufferLength < 3 && i < [data length])
            buffer[bufferLength++] = ((char *)[data bytes])[i++];
        
        //  Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
        characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
        characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
        if (bufferLength > 1)
            characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
        else characters[length++] = '=';
        if (bufferLength > 2)
            characters[length++] = encodingTable[buffer[2] & 0x3F];
        else characters[length++] = '=';
    }
    
    return [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES];
}

解码

+ (NSString *)stringWithBase64EncodedString:(NSString *)string{
    if ([string length] == 0)
        return [NSData data];
    
    static char *decodingTable = NULL;
    if (decodingTable == NULL)
    {
        decodingTable = malloc(256);
        if (decodingTable == NULL)
            return nil;
        memset(decodingTable, CHAR_MAX, 256);
        NSUInteger i;
        for (i = 0; i < 64; i++)
            decodingTable[(short)encodingTable[i]] = i;
    }
    
    const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
    if (characters == NULL)     //  Not an ASCII string!
        return nil;
    char *bytes = malloc((([string length] + 3) / 4) * 3);
    if (bytes == NULL)
        return nil;
    NSUInteger length = 0;
    
    NSUInteger i = 0;
    while (YES)
    {
        char buffer[4];
        short bufferLength;
        for (bufferLength = 0; bufferLength < 4; i++)
        {
            if (characters[i] == '\0')
                break;
            if (isspace(characters[i]) || characters[i] == '=')
                continue;
            buffer[bufferLength] = decodingTable[(short)characters[i]];
            if (buffer[bufferLength++] == CHAR_MAX)      //  Illegal character!
            {
                free(bytes);
                return nil;
            }
        }
        
        if (bufferLength == 0)
            break;
        if (bufferLength == 1)      //  At least two characters are needed to produce one byte!
        {
            free(bytes);
            return nil;
        }
        
        //  Decode the characters in the buffer to bytes.
        bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
        if (bufferLength > 2)
            bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
        if (bufferLength > 3)
            bytes[length++] = (buffer[2] << 6) | buffer[3];
    }
    
    bytes = realloc(bytes, length);
    NSData *data = [NSData dataWithBytesNoCopy:bytes length:length];
    return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];

}

2.MD5 加密

1.1 MD5加密简单说明

描述:MD5加密是最常用的加密方法之一,是从一段字符串中通过相应特征生成一段32位的数字字母混合码。对输入信息生成唯一的128位散列值(32个字符)

结果:MD5生成的是固定的128bit,即128个0和1的二进制位,而在实际应用开发中,通常是以16进制输出的,所以正好就是32位的16进制,说白了也就是32个16进制的数字。

1.2 MD5加密的优点:

易计算:原数据计算出MD5值很容易。
压缩性:任意长度的元数据,计算出的MD5值长度固定
抗修改:原数据只修改一个字节,计算出的MD5值也有很大差别。也就说明,跟原数据和MD5值,想伪造一个类似的数据十分困难.想得到两个原数据不同,但MD5值接近的值也是很难.
其他: MD5加密是不可解密的,但是网上有一些解析MD5的,那个相当于一个大型的数据库,通过匹配MD5去找到原密码。所以,只要在要加密的假眼或者多次MD5加密来提高加密效果,这样出来的结果一般是解析不出来的.

1.3 使用

需要导入 #import <CommonCrypto/CommonCrypto.h>

+ (NSString *)md5:(NSString *)string{
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), digest);   
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02X", digest[i]];
    }
    return result;
}

//使用
+ (NSString *)md5ForString:(NSString *)string{
    NSString *md5String;
    md5String = [self md5:string]; // 第一次加密
    md5String = [md5String substringToIndex:18]; // 截取长度
    md5String = [md5String stringByAppendingString:@"Test"]; // 加盐(加盐的字符串没有要求)
    md5String = [self md5:md5String]; // 第二次加密
    // 多次加密只是为了加强加密效果
    return md5String;
}

3.AES 加密

  • AES256
- (NSData *)AES256Encrypt:(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 *)AES256Decrypt:(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;
}
  • AES128
 + (NSString *)AES128Encrypt:(NSString *)plainText{  //加密
      char keyPtr[kCCKeySizeAES128+1];
      memset(keyPtr, 0, sizeof(keyPtr));
      [AESKEY getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
      
      char ivPtr[kCCBlockSizeAES128+1];
      memset(ivPtr, 0, sizeof(ivPtr));
      [AESIV getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
      
      NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
      NSUInteger dataLength = [data length];
      
      int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
      int newSize = 0;
      
      if(diff > 0)
      {
          newSize = dataLength + diff;
      }
      
      char dataPtr[newSize];
      memcpy(dataPtr, [data bytes], [data length]);
      for(int i = 0; i < diff; i++)
      {
          dataPtr[i + dataLength] = 0x00;
      }
      
      size_t bufferSize = newSize + kCCBlockSizeAES128;
      void *buffer = malloc(bufferSize);
      memset(buffer, 0, bufferSize);
      
      size_t numBytesCrypted = 0;
      
      CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                            kCCAlgorithmAES128,
                                            0x0000,   //这里用的 NoPadding的填充方式 除此以外还有 kCCOptionPKCS7Padding 和 kCCOptionECBMode
                                            keyPtr,
                                            kCCKeySizeAES128,
                                            ivPtr,
                                            dataPtr,
                                           sizeof(dataPtr),
                                            buffer,
                                            bufferSize,
                                            &numBytesCrypted);
      
      if (cryptStatus == kCCSuccess) {
          NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
          return [GTMBase64 stringByEncodingData:resultData];
      }
      free(buffer);
      return nil;
  }
  
  + (NSString *)AES128Decrypt:(NSString *)encryptText{  //解密
      char keyPtr[kCCKeySizeAES128 + 1];
      memset(keyPtr, 0, sizeof(keyPtr));
      [AESKEY getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
      
      char ivPtr[kCCBlockSizeAES128 + 1];
      memset(ivPtr, 0, sizeof(ivPtr));
      [AESIV getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
      
      NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
      NSUInteger dataLength = [data length];
      size_t bufferSize = dataLength + kCCBlockSizeAES128;
      void *buffer = malloc(bufferSize);
      
      size_t numBytesCrypted = 0;
      CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                            kCCAlgorithmAES128,
                                            0x0000,
                                            keyPtr,
                                            kCCBlockSizeAES128,
                                            ivPtr,
                                            [data bytes],
                                            dataLength,
                                            buffer,
                                            bufferSize,
                                            &numBytesCrypted);
      if (cryptStatus == kCCSuccess) {
          NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
          return [[[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding] autorelease];
     }
     free(buffer);
     return nil;
 }

4.SHA1(哈希) 加密

需要导入头文件
#import <CommonCrypto/CommonDigest.h>

- (NSString *) sha1:(NSString *)string{
    const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:string.length];
    
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, (unsigned int)data.length, digest);
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    
    for(int i=0; i<CC_SHA1_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }
    return output;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容