Skip to content

Instantly share code, notes, and snippets.

@acalism
Last active March 1, 2018 11:09
Show Gist options
  • Save acalism/0a1c16cab2be8630507df8fb0a8c6b0f to your computer and use it in GitHub Desktop.
Save acalism/0a1c16cab2be8630507df8fb0a8c6b0f to your computer and use it in GitHub Desktop.
md5 计算。被注释掉的部分是较冗长的写法
// 需要在 xxx-Bridging-Header.h 中引入 CommonCrypto
// #import <CommonCrypto/CommonCrypto.h> // add to your xxx-Bridging-Header.h
// 所以在 playground 中无法测试下面的代码 ( NOT work with Playground )
// 阅读代码时注意以下几点:
// 1. Data 本质是 UInt8 数组,所以 String.utf8.count 与 Data.count 是相等的(String 转换成 Data 前后)
// 2. 如果一个C方法接受的参数类型是 void*,即 Swift 里的 UnsafeRawPointer,那么它也接受 UnsafePointer<T> 类型
// 3. 如果某个方法接受 UnsafePointer<UInt8> 类型参数,那么直接填入 String 也是可以的
class Digest {
static func md5(_ data: Data) -> Data {
// var digestData = Data(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
// digestData.withUnsafeMutableBytes { (digestBytes: UnsafeMutablePointer<UInt8>) -> Void in
// data.withUnsafeBytes { (messageBytes: UnsafePointer<Int8>) -> Void in
// CC_MD5(messageBytes, CC_LONG(data.count), digestBytes)
// }
// }
// return digestData
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5((data as NSData).bytes, CC_LONG(data.count), &digest)
return Data.init(bytes: digest)
}
static func md5(_ string: String) -> Data {
// var data = Data(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
// data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
// CC_MD5(string, CC_LONG(string.utf8.count), bytes)
// }
// return data
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5(string, CC_LONG(string.utf8.count), &digest)
return Data.init(bytes: digest)
}
static func md5(contentOf url: URL) throws -> Data {
let handle = try FileHandle(forReadingFrom: url)
var ctx = CC_MD5_CTX()
CC_MD5_Init(&ctx)
var count = 0
repeat {
let fileData = handle.readData(ofLength: 256) // CHUNK_SIZE, or 1024 * 1024
count = fileData.count
fileData.withUnsafeBytes({ (bytes: UnsafePointer<CChar>) -> Void in
CC_MD5_Update(&ctx, bytes, CC_LONG(count))
})
} while count > 0
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5_Final(&digest, &ctx)
return Data.init(bytes: digest)
}
}
extension Data {
var md5: Data {
return Digest.md5(self)
}
// 事实上 hexDescription 和 hexEncodedString 结果是一致的
// 前者取巧复用了 NSData 在 po 输出时就是16进制的特点
// 后者对data的每个uint8转为16进制字符串并拼接在一起,更符合直观定义
var hexDescription: String {
// 删除首尾的<>符号;删除空格
return (self as NSData).description.trimmingCharacters(in: CharacterSet(charactersIn: "<>")).replacingOccurrences(of: " ", with: "")
}
var hexEncodedString: String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
extension String {
var md5: Data {
return Digest.md5(self)
}
}
extension URL {
var md5: Data? {
return try? Digest.md5(contentOf: self)
}
}
// just a test function
func testMD5() {
let s = "A quick brown fox jumps over the lazy dog."
var ctx = CC_MD5_CTX()
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5_Init(&ctx)
CC_MD5_Update(&ctx, s, CC_LONG(s.utf8.count))
CC_MD5_Final(&digest, &ctx)
print(digest.map { String(format:"%02x", $0) }.reduce("", +))
print(Data.init(bytes: digest) as NSData)
print(s.md5.hexDescription)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment