3DES加密和解密

使用3DES加密时,遇到后端加解密数据与iOS加解密数据不一致的问题,特此记录下。

后端使用的算法algorithm参数是ecb,iOS端使用kCCOptionECBMode或者kCCOptionPKCS7Padding时,如果加密的原始数据全是数字类型时,可以得到相同的加解密结果。但是,当原始数据包含特殊字符或者字母时就跟后端得到的不一致了,正确的设置是使用(kCCOptionECBMode + kCCOptionPKCS7Padding)

在3DES加密中,key值是24位字符串,一般我们是将原始key值经过md5加密后截取前24位作为3DES加解密的key来使用。

加解密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    func tripleDESEncryptOrDecrypt(op: CCOperation,key: String) -> String? {

let iv:String? = ""
// Key
let keyData: NSData = (key as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
let keyBytes = UnsafeRawPointer(keyData.bytes)

// 加密或解密的内容
var data: NSData = NSData()
if op == CCOperation(kCCEncrypt) {
data = (self as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
}
else {
data = NSData(base64Encoded: self, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)!
}

let dataLength = size_t(data.length)
let dataBytes = UnsafeRawPointer(data.bytes)

// 返回数据
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)
let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)

// 可选 的初始化向量
let viData :NSData = (iv! as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
let viDataBytes = UnsafeRawPointer(viData.bytes)

// 特定的几个参数
let keyLength = size_t(kCCKeySize3DES)
let operation: CCOperation = UInt32(op)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)

var numBytesCrypted :size_t = 0

let cryptStatus = CCCrypt(operation, // 加密还是解密
algoritm, // 算法类型
options, // 密码块的设置选项
keyBytes, // 秘钥的字节
keyLength, // 秘钥的长度
viDataBytes, // 可选初始化向量的字节
dataBytes, // 加解密内容的字节
dataLength, // 加解密内容的长度
cryptPointer, // output data buffer
cryptLength, // output data length available
&numBytesCrypted) // real output data length
if UInt32(cryptStatus) == UInt32(kCCSuccess) {

cryptData!.length = Int(numBytesCrypted)
if op == CCOperation(kCCEncrypt) {
let base64cryptString = cryptData?.base64EncodedString(options: [])
return base64cryptString
}
else {
let base64cryptString = String.init(data: cryptData! as Data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
return base64cryptString
}
}
return nil
}
}

测试数据:

1
2
3
4
5
6
7
8
9
10
11
12
var key = "012438BF-4E53-458F-8A07-D7DDFC8FA1F8190808173932337_"
let keyStr = md5String(text: key)
key = String(keyStr.prefix(24))


let text = "1234qwer"
var encryptText:String?
var decrptText:String?
encryptText = text.tripleDESEncryptOrDecrypt(op: CCOperation(kCCEncrypt), key: key)
decrptText = "labWVwRfO4BSWJA2swHTOg==".tripleDESEncryptOrDecrypt(op: CCOptions(kCCDecrypt), key: key)
print("加密结果:"+(encryptText ?? "加密失败"))
print("解密结果:"+(decrptText ?? "解密失败"))