85-Swift 之加密(md5\base64\3des)

引言

             在现在迅速发展的互联网时代,数据安全非常重要。为了保证数据的安全,可以在数据的传送时对数据进行加密来保证数据的安全。

加密介绍

             加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。

开发常用的加密

第一、MD5 加密

1> 什么是MD5 ?

              MD5 的全称是 Message-Digest Algorithm 5MD5 以512位分组来处理输入文本,每一分组又划分为16个32位子分组。算法的输出由四个32位分组组成,将它们级联形成一个128位散列值。

2> 使用MD5要引入的头文件

              MD5Swift 中使用需要引入头文件 #import <CommonCrypto/CommonDigest.h> 。由于 Swift 还没有 CommonCrypto/CommonDigest.h 文件。所以我们需要使用 OCCommonCrypto/CommonDigest.h 。在Swfit 中使用 OC 的文件需要搭建桥接文件,桥接文件规则是:"项目的名称"-Bridging-Header.h不会创建桥接文件的点击这里

3> MD5 的核心代码
// TODO: MD5加密处理(私有的加密处理方法)
private class func md5ToString(string:String? , type:MD5Type) -> String? {
    // 判断传入对象是否存在
    if string == nil {
        return nil
    }
    let inputString = string!
    if inputString.length() == 0  {
        return nil
    }
    // 获取将要加密对象UTF8编码后的字符数据引用
    let encodingArray = inputString.cString(using: String.Encoding.utf8)
    // 获取要加密对象的字节数
    let encryptedObjByteCount = inputString.lengthOfBytes(using: String.Encoding.utf8)
    // 获取加密后的占位空间 (CC_MD5_DIGEST_LENGTH 是 16 位的)
    let digestLength = Int(CC_MD5_DIGEST_LENGTH)
    // 声明一个不可变的存放加密后的字符数组
    let charsArray  =  UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLength)
    // 进行加密处理
    CC_MD5(encodingArray, CC_LONG(encryptedObjByteCount), charsArray)
    // 创建一个可变的字符串
    let mutableString = NSMutableString.init()
    // 判断输出规则
    var printfType:String!
    switch type {
        case .Lower32:
            printfType = "%02x"
            break
        case .Capitalize32:
            printfType = "%02X"
            break
    }
    // 将加密后生成的字符拼接起来
    for i in 0 ..< digestLength {
        mutableString.appendFormat(printfType as NSString, charsArray[i])
    }
    // 释放加密后的字符数组对象
    charsArray.deinitialize()
    // 返回加密后的字符串
    return mutableString as String
}
4、MD5 的测试
  • 测试代码
let str = "NetWork小贱".md5ToLower32String()
print("小写MD5加密输出"+"----"+str!)
let strmd5 = "NetWork小贱".md5ToCapitalize32String()
print("大写MD5加密输出"+"----"+strmd5!)
  • 测试结果


    E4599BDF-5FBB-4EE5-B48B-D1B07E2F0081.png

第二、Base64 加密

1、 什么是base64加密?

              Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。作用是Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。

2、 Base64 的核心代码
// TODO: base64编码处理
private class func base64CodingToString(object:String? , type:CodingType) -> String? {
    // 判断传入对象是否存在
    if object == nil {
        return object
    }
    // 判断是加密还是解密
    switch type {
        case .Encrypting:
            // 将传入的数据 UTF8 进行编码
            let codingData = object?.data(using: .utf8)
            return codingData!.base64EncodedString()
        case .Decryption:
            // 将数据转化为二进制数据
            let decryptionData =  Data.init(base64Encoded: object!, options: .ignoreUnknownCharacters)
            return String.init(data: decryptionData!, encoding: .utf8)
    }
}
3、Base64 的测试
  • 测试代码
let str = "NetWork小贱".base64EncryptingToString()! as String
print("Base64加密输出"+"----"+str)
let strBase64 = str.base64DecryptionToString()
print("Base64解密输出"+"----"+strBase64!)
  • 测试结果


    4B1A8A93-5A7F-4AB4-AB5B-415305E829CD.png

第三 、 3DES 加密

1、 3DES 是什么?

              3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。

2、 3DES 的工作流程

              3DES又称Triple DES,是DES加密算法的一种模式,它使用3条56位的密钥对数据进行三次加密。3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,C代表密文,这样:

3DES加密过程为:C=Ek3(Dk2(Ek1(M)))
3DES解密过程为:M=Dk1(EK2(Dk3(C)))

3、3DES 的使用前的准备

             3DES 的加密的使用,需要引入头文件 #import <CommonCrypto/CommonCryptor.h>,由于该头文件是Object-OC 的文件,如果想使用该文件,就需要我们搭建桥接文件。搭建规则

4、3DES 核心代码
// TODO: 3des 的处理函数
private class func threeDESCodingToString(coding  object:String? , key:String , type:CodingType) -> String? {
    // TODO: 创建要加密或解密的数据接受对象
    var data = Data.init()
    // 加密
    if type == .Encrypting {
        // 将要加密的对象编码
        data = object!.data(using: .utf8)!
    }
    // 解密
    if type == .Decryption {
        // 将要解密的对象编码
        data = Data.init(base64Encoded: object!, options: .ignoreUnknownCharacters)!
    }
    // 创建数据编码后的指针
    let dataPointer = UnsafeRawPointer((data as NSData).bytes)
    // 获取转码后数据的长度
    let dataLength = size_t(data.count)
    
    // TODO: 将加密或解密的密钥转化为Data数据
    let keyData = key.data(using: .utf8)! as NSData
    // 创建密钥的指针
    let keyPointer = UnsafeRawPointer(keyData.bytes)
    // 设置密钥的长度
    let keyLength = size_t(kCCKeySize3DES)

    // TODO: 创建加密或解密后的数据对象
    let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)
    // 获取返回数据(cryptData)的指针
    let cryptPointer = UnsafeMutableRawPointer(mutating: cryptData!.mutableBytes)
    // 获取接收数据的长度
    let cryptDataLength = size_t(cryptData!.length)
    // 加密或则解密后的数据长度
    var cryptBytesLength:size_t = 0
    
    // TODO: 数据参数的准备
    // 是解密或者加密操作(CCOperation 是32位的)
    let operation:CCOperation = UInt32(type.hashValue)
    // 算法的类型
    let algorithm:CCAlgorithm = UInt32(kCCAlgorithm3DES)
    // 设置密码的填充规则( PKCS7 & ECB 两种填充规则)
    let options:CCOptions = UInt32(kCCOptionPKCS7Padding)|UInt32(kCCOptionECBMode)
    // 执行算法处理
    let cryptStatue = CCCrypt(operation, algorithm, options, keyPointer, keyLength,nil, dataPointer, dataLength, cryptPointer, cryptDataLength, &cryptBytesLength)
    // 通过返回状态判断加密或者解密是否成功
    if  UInt32(cryptStatue) == kCCSuccess  {
        // 加密
        if type == .Encrypting {
            cryptData!.length = cryptBytesLength
            // 返回3des加密对象
            return cryptData!.base64EncodedString(options: .lineLength64Characters)
        }
        // 解密
        if type == .Decryption {
            // 返回3des解密对象
            cryptData!.length = cryptBytesLength
            let outString = NSString(data:cryptData! as Data ,encoding:String.Encoding.utf8.rawValue)
            return outString! as String
        }
    }
    // 3des 加密或者解密不成功
    return " 3des Encrypt or Decrypt is faill"
}

代码解析:

        从上面核心代码来看已经注释很详细了,但是有些地方还是要再详细的解释一下:

  • UnsafeRawPointer 和 UnsafeMutableRawPointer 的介绍
             在 Swift 中,指针都使用一个特殊的类型来表示,那就是UnsafeRawPointer。对应地它还有一个可变变体 UnsafeMutableRawPointer 。在创建该指针时,向系统申请了为一定大小的UInt8泛型类型的内存。

  • kCCKeySize3DES 的介绍
             kCCKeySize3DES 是指Triple DES加解密的Key的大小,其值为24。要注意了,这里必须是24位,切记,切记。

  • 获取可变数据的指针对象
    在获取可变数据的指针对想的时候,要注意,必须使用 mutableBytes ,而不能使用 bytes。例如:

    // 获取返回数据(cryptData)的指针
    let cryptPointer = UnsafeMutableRawPointer(mutating: cryptData!.mutableBytes)

  • CCCrypt 函数的介绍

1、参数1: 是指定加密还是解密的枚举类型(kCCEncrypt 、kCCDecrypt)。
2、参数2: 是指加密算法的类型。在CommonCryptor.h中提供了kCCAlgorithmAES128、kCCAlgorithmAES、kCCAlgorithmDES、kCCAlgorithm3DES、kCCAlgorithmCAST、kCCAlgorithmRC4、kCCAlgorithmRC2、kCCAlgorithmBlowfish等多种类型的加密算法。
3、 参数3:用来设置密码的填充规则(表示在使用密钥和算法对文本进行加密时的方法)的选项,该选项可以是kCCOptionPKCS7Padding或kCCOptionECBMode两者中的任一个。
4、参数4:密钥的数据指针。
5、参数5: 是密钥的长度 ,必须是 24 位。
6、参数6: 加密或者解密的偏移对象。
7、参数7: 要解密或者解密的数据指针对象。
8、参数8: 要解密或者解密的数据字符长度。
9、参数9: 加密或者解密的数据指针
10、参数10: 接受加密或者解密的数据长度。
11、参数11: 这是加密或者解密的数据长度。
注意::::
在加密或者解密的结果输出的时候,要重新设置接受解密或者加密的数据对象的长度为真实长度。

  • CCCrypt 的返回结果
    1、kCCSuccess
    加解密操作正常结束
    2、kCCParamError
    非法的参数值
    3、kCCBufferTooSmall
    选项设置的缓存不够大
    4、kCCMemoryFailure
    内存分配失败
    5、kCCAlignmentError
    输入大小匹配不正确
    6、kCCDecodeError
    输入数据没有正确解码或解密
    7、kCCUnimplemented
    函数没有正确执行当前的算法
5、3DES 的测试
  • 测试代码
let str = "NetWork小贱".threeDESEncryptingToString()!
print("3des加密输出"+"----" + str)
let str3des = str.threeDESDecryptionToString()
print("3des解密输出"+"----"+str3des!)
  • 测试结果


    4D91B6E9-3296-4F3F-B9A1-0CB1D75DA432.png

Swift 常用加密的封装

            针对Swift 的开发中常用的加密方式进行了封装。让开发者使用简单,不用在考虑如何编写实现加密的功能。本次封装的类是 ZSJEncryptingManager.swift。本类含有 MD5\Base64\3DES加密和解密,使用简单方便。避免一个个的功能开发带来的麻烦。该类的方法:

    // MARK: md5 加密区
    
    // TODO: md5小写加密(32位)
    class func md5ToLower32String(encrypted object:String?)->String? {
        return self.md5ToString(string: object, type: .Lower32)
    }
    
    // TODO: md5大写加密(32位)
    class func md5ToCapitalize32String(encrypted object:String?)->String? {
        return self.md5ToString(string: object, type: .Capitalize32)
    }

    // MARK: 3des 加密区
    
    // TODO: 3des 加密处理
    class func threeDESEncryptingToString(encrypting object:String? ,encryptedPublickey:String ) -> String? {
         return self.threeDESCodingToString(coding: object, key: TripleDESKey, type: .Encrypting)
    }
    
    // TODO: 3des 解密处理
    class func threeDESDecryptionToString(decryption object:String? ,decryptionSecretKey:String ) -> String? {
        return self.threeDESCodingToString(coding: object, key: TripleDESKey, type: .Decryption)
    }

    // MARK: base64 加密区
    
    // TODO: base64 加密处理
    class  func base64EncryptingToString(encrypting object:String?) -> String? {
        return self.base64CodingToString(object: object,type:.Encrypting)
    }
    // TODO: base64 解密处理
    class  func base64DecryptionToString(decryption object:String?) -> String? {
        return self.base64CodingToString(object: object, type: .Decryption)
    }

好消息,本次的基础上,再次对加密功能再次封装和扩展:

// MARK: 字符串的扩展
extension String {
    // TODO: md5加密
    func md5ToLower32String() -> String? {
        return ZSJEncryptingManager.md5ToLower32String(encrypted: self)
    }
    func md5ToCapitalize32String() -> String? {
        return ZSJEncryptingManager.md5ToCapitalize32String(encrypted: self)
    }

    
    // TODO: 3des加密
    func threeDESEncryptingToString() -> String? {
        return ZSJEncryptingManager.threeDESEncryptingToString(encrypting: self, encryptedPublickey: TripleDESKey)
    }
    func threeDESDecryptionToString() -> String? {
        return ZSJEncryptingManager.threeDESDecryptionToString(decryption: self, decryptionSecretKey: TripleDESKey)
    }
    
    // TODO: base64 加密和解密
    func base64EncryptingToString() -> String? {
        return ZSJEncryptingManager.base64EncryptingToString(encrypting: self)
    }
    func base64DecryptionToString() -> String? {
        return ZSJEncryptingManager.base64DecryptionToString(decryption: self)
    }

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

推荐阅读更多精彩内容

  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 2,997评论 0 14
  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,323评论 0 6
  • 本文主要介绍移动端的加解密算法的分类、其优缺点特性及应用,帮助读者由浅入深地了解和选择加解密算法。文中会包含算法的...
    苹果粉阅读 11,425评论 5 29
  • 打开了音乐,传出了李行亮的这首《愿得一人心,白首不分离》的歌。:只愿得一人心,白首不分离。不由感慨万分。 ...
    风竹禅玉阅读 431评论 0 2
  • 矫情而幸运的泰山挑夫# 李笑来就是这样一个挑夫,他很幸运,也很矫情。 但是他勤勤恳恳,默默的前进,日拱一卒。 王福...
    路建华阅读 129评论 0 0