使用Swift 3.0实现原生的3DES加密和解密
DES(Data EncryptionStandard)又叫数据加密标准,是1973年5月15日美国国家标准局(现在是美国标准技术研究所,即NIST)在联邦记录中公开征集密码体制时出现的。DES加密算法是一种对称加密技术,该算法的要求主要为以下四点:
而3DES(或称为TripleDES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
创建项目并建立桥接文件 接着我们来创建一个示例项目,对一个字符串进行3DES加密和解密。首先创建一个基于[Single View Applicaton]模板的空白项目,然后在左侧的项目名称文件夹上点击鼠标右键,并选择右键菜单中的[New File...]选项,创建一个桥接头文件,这是因为我们需要使用到Object-C的CommonCrypto。 图 1 桥接头文件创建完成后,打开并编辑该文件,以引入相关的头文件,如图2所示: 图 2 接着还需要在Build Settings面板中设置Objective-C Bridging Header,在进入Build Settings面板之后,在搜索输入框内输入objective-c bridging进行搜索,以定位Objective-C Bridging Header选项,并设置该选项的值为桥接文件所在的位置,如图3所示: 图 3 实现3DES加解密功能完成项目的配置之后,在左侧的项目导航区打开并编辑[ViewController.swift]文件,开始3DES加解密功能的实现。在该文件中首先创建一个集合,用来生成随机的公用key值: private let randomStringArray: [Character] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".characters.map({$0}) var key:String = "" 然后添加一个名为randomStringOfLength方法,用来获得指定长度的随机字符串,该字符串从randomStringArray集合中获得英文大小写字母和0至9之间的数字,然后由这些字符通过一个for–in 循环组成指定长度的随机字符串。其中uniform方法可以用来产生0~(n-1)范围内的随机数,不需要再进行取模运算。如果要生成1至n的随机数,可以这么写:arc4random_uniform(n)+1: func randomStringOfLength(_ length:Int) -> String { var string = "" for _ in (1...length) { string.append(randomStringArray[Int(arc4random_uniform( UInt32(randomStringArray.count) - 1))]) } return string } 然后添加一个名为encrypt方法,对字符串参数encryptData进行加密: func encrypt(encryptData:String){ key = randomStringOfLength(kCCKeySize3DES) let inputData : Data = encryptData.data(using: String.Encoding.utf8)! let keyData: Data = key.data(using: String.Encoding.utf8,allowLossyConversion: false)! let keyBytes = UnsafeMutableRawPointer(mutating: (keyData as NSData).bytes) let keyLength = size_t(kCCKeySize3DES) let dataLength = Int(inputData.count) let dataBytes = UnsafeRawPointer((inputData as NSData).bytes) let bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)! let bufferPointer = UnsafeMutableRawPointer(bufferData.mutableBytes) let bufferLength = size_t(bufferData.length) var bytesDecrypted = Int(0) let cryptStatus = CCCrypt( UInt32(kCCEncrypt),UInt32(kCCAlgorithm3DES),UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding),keyBytes,keyLength,nil,dataBytes,dataLength,bufferPointer,bufferLength,&bytesDecrypted) if Int32(cryptStatus) == Int32(kCCSuccess) { bufferData.length = bytesDecrypted decrypt(inputData: bufferData as Data) } else { print("加密过程出错: (cryptStatus)") } } CCCrypt参数的配置在该方法中的第2行至14行的代码,都是用来生成CCCrypt方法中的各种参数的值。 首先在第2行的代码中,通过randomStringOfLength方法,生成一个随机字符串作为3DES加解密的key值。其中kCCKeySize3DES是指Triple DES加解密的key的大小,其值为24,因此这里将生成一个长度为24的包含英文大小写字母和数字的随机字符串。 接着在第3行的代码中,将待加密的字符串转换为Data类型。 在第5行的代码中,将作为随机字符串的key值同样转换为Data类型。 在第6行的代码中,创建一个UnsafeMutableRawPointer指针。在 Swift 中,指针都使用一个特殊的类型来表示,那就是UnsafeRawPointer。对应地它还有一个可变变体, UnsafeMutableRawPointer 。在创建该指针时,向系统申请了个数为(keyData as NSData).bytes的UInt8泛型类型的内存。 在第7行的代码中,创建一个名为keyLength的常量,表示key值的长度。根据kCCKeySize3DES的大小可以得知,keyLenght的值为24。 然后在第9行的代码中,获得待加密的Data类型对象的长度。并在第20行的代码中,创建一个UnsafePointer指针,并从系统中分配相应的内存作为加密的input buffer。 在第11行的代码中,创建一个指定长度的NSMutableData可变的二进制数据对象,该对象将作为加密的outputbuffer,用来存储加密后的数据。其长度为input buffer的长度和3DES加密的kCCBlockSize3DES块大小之和,kCCBlockSize3DES块的大小为8。 接着在第12行的代码中,创建一个UnsafeMutablePointer类型的指针,并根据output buffer即bufferData的大小分配相应的内存。 然后在第13行的代码中,获得outputbuffer的长度。最后在第14行的代码中,创建一个变量bytesDecrypted,用来存储加密后的output buffer的最终字节数。
执行CCCrypt方法完成所有的参数设置之后,在第16至27行的代码中,调用CommonCryptor.h中的CCCrypt方法对数据进行加密操作。 其中CCCrypt方法的第一个参数表示进行加密操作,还是进行解密操作,这里使用kCCEncrypt表示进行加密操作。 第二个参数表示进行加密的算法,在CommonCryptor.h中提供了kCCAlgorithmAES128、kCCAlgorithmAES、kCCAlgorithmDES、kCCAlgorithm3DES、kCCAlgorithmCAST、kCCAlgorithmRC4、kCCAlgorithmRC2、kCCAlgorithmBlowfish等多种类型的加密算法。 第三个参数用来设置block ciphers(block cipher表示在使用密钥和算法对文本进行加密时的方法)的选项,该选项可以是kCCOptionPKCS7Padding或kCCOptionECBMode两者中的任一个。假如使用PKCS7Padding,它的密钥可以是8个字节,也可以不是。 CCCrypt方法的其它几个参数就是我们在第2行至14行号配置好的参数。
判断CCCrypt方法执行的结果 当执行完CCCrypt方法后,会返回一个cryptStatus状态,通过cryptStatus判断是否加密成功。其中kCCSuccess表示加密成功,除此之外还有其它几种状态,如表1所示:
当判断加密操作正确完成后,设置output data的length为bytesDecrypted,以调整输出buffer的大小为最终输出加密数据的尺寸。 对密文进行解密操作至此就完成了数据的加密操作,接着使用相同的密钥对密文进行解密操作。该功能通过调用decrypt方法来实现: func decrypt(inputData : Data){ let keyData: Data = key.data(using: String.Encoding.utf8,allowLossyConversion: false)! let keyBytes = UnsafeMutableRawPointer(mutating: (keyData as NSData).bytes) let keyLength = size_t(kCCKeySize3DES) let dataLength = Int(inputData.count) let dataBytes = UnsafeRawPointer((inputData as NSData).bytes) let bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)! let bufferPointer = UnsafeMutableRawPointer(bufferData.mutableBytes) let bufferLength = size_t(bufferData.length) var bytesDecrypted = Int(0) let cryptStatus = CCCrypt( UInt32(kCCDecrypt),&bytesDecrypted) if Int32(cryptStatus) == Int32(kCCSuccess) { bufferData.length = bytesDecrypted let clearDataAsString = NSString(data: bufferData as Data,encoding: String.Encoding.utf8.rawValue) print("解密后的内容:(clearDataAsString as! String)") } else { print("解密过程出错: (cryptStatus)") } } 解密的方法与加密的方法大体相似,需要注意不同的地方是,在第13行使用kCCDecrypt进行解密运算。然后在72行的代码中,将解密后的数据转换为NSString对象,并通过print语句在日志区进行打印输出。 修改viewDidLoad方法最后一步是修改ViewController类的viewDidLoad方法,在该方法中调用加密方法encrypt,对明文coolketang.com进行加密操作: override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view,typically from a nib. encrypt(encryptData: "coolketang.com"); }
现在已经完成了所有的加解密的编码工作,点击Xcode界面左上角的[编译并运行]按钮 ,打开模拟器运行项目。项目运行后,将弹出一个空白的模拟器,并在日志区输出解密后的结果,如图4所示: 图 4
新 作 iOS开发中的神兵利器 共140节课程,讲解GitHub中近百个过千star的iOS热门开源项目 视频观看地址:http://study.163.com/course/courseMain.htm?courseId=1003657013 互动教程下载地址:https://itunes.apple.com/cn/app/id1209739676 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |