added iOS source code
[wl-app.git] / iOS / Pods / Kingfisher / Sources / String+MD5.swift
1 //
2 //  String+MD5.swift
3 //  Kingfisher
4 //
5 // To date, adding CommonCrypto to a Swift framework is problematic. See:
6 // http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework
7 // We're using a subset and modified version of CryptoSwift as an alternative.
8 // The following is an altered source version that only includes MD5. The original software can be found at:
9 // https://github.com/krzyzanowskim/CryptoSwift
10 // This is the original copyright notice:
11
12 /*
13 Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
14 This software is provided 'as-is', without any express or implied warranty.
15 In no event will the authors be held liable for any damages arising from the use of this software.
16 Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
17 - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
18 - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
19 - This notice may not be removed or altered from any source or binary distribution.
20 */
21
22 import Foundation
23
24 public struct StringProxy {
25     fileprivate let base: String
26     init(proxy: String) {
27         base = proxy
28     }
29 }
30
31 extension String: KingfisherCompatible {
32     public typealias CompatibleType = StringProxy
33     public var kf: CompatibleType {
34         return StringProxy(proxy: self)
35     }
36 }
37
38 extension StringProxy {
39     var md5: String {
40         if let data = base.data(using: .utf8, allowLossyConversion: true) {
41
42             let message = data.withUnsafeBytes { bytes -> [UInt8] in
43                 return Array(UnsafeBufferPointer(start: bytes, count: data.count))
44             }
45
46             let MD5Calculator = MD5(message)
47             let MD5Data = MD5Calculator.calculate()
48
49             var MD5String = String()
50             for c in MD5Data {
51                 MD5String += String(format: "%02x", c)
52             }
53             return MD5String
54
55         } else {
56             return base
57         }
58     }
59 }
60
61
62 /** array of bytes, little-endian representation */
63 func arrayOfBytes<T>(_ value: T, length: Int? = nil) -> [UInt8] {
64     let totalBytes = length ?? (MemoryLayout<T>.size * 8)
65     
66     let valuePointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
67     valuePointer.pointee = value
68
69     let bytes = valuePointer.withMemoryRebound(to: UInt8.self, capacity: totalBytes) { (bytesPointer) -> [UInt8] in
70         var bytes = [UInt8](repeating: 0, count: totalBytes)
71         for j in 0..<min(MemoryLayout<T>.size, totalBytes) {
72             bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
73         }
74         return bytes
75     }
76
77     #if swift(>=4.1)
78     valuePointer.deinitialize(count: 1)
79     valuePointer.deallocate()
80     #else
81     valuePointer.deinitialize()
82     valuePointer.deallocate(capacity: 1)
83     #endif
84     
85     return bytes
86 }
87
88 extension Int {
89     /** Array of bytes with optional padding (little-endian) */
90     func bytes(_ totalBytes: Int = MemoryLayout<Int>.size) -> [UInt8] {
91         return arrayOfBytes(self, length: totalBytes)
92     }
93     
94 }
95
96 extension NSMutableData {
97     
98     /** Convenient way to append bytes */
99     func appendBytes(_ arrayOfBytes: [UInt8]) {
100         append(arrayOfBytes, length: arrayOfBytes.count)
101     }
102     
103 }
104
105 protocol HashProtocol {
106     var message: Array<UInt8> { get }
107     
108     /** Common part for hash calculation. Prepare header data. */
109     func prepare(_ len: Int) -> Array<UInt8>
110 }
111
112 extension HashProtocol {
113     
114     func prepare(_ len: Int) -> Array<UInt8> {
115         var tmpMessage = message
116         
117         // Step 1. Append Padding Bits
118         tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message
119         
120         // append "0" bit until message length in bits ≡ 448 (mod 512)
121         var msgLength = tmpMessage.count
122         var counter = 0
123         
124         while msgLength % len != (len - 8) {
125             counter += 1
126             msgLength += 1
127         }
128         
129         tmpMessage += Array<UInt8>(repeating: 0, count: counter)
130         return tmpMessage
131     }
132 }
133
134 func toUInt32Array(_ slice: ArraySlice<UInt8>) -> Array<UInt32> {
135     var result = Array<UInt32>()
136     result.reserveCapacity(16)
137     
138     for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout<UInt32>.size) {
139         let d0 = UInt32(slice[idx.advanced(by: 3)]) << 24
140         let d1 = UInt32(slice[idx.advanced(by: 2)]) << 16
141         let d2 = UInt32(slice[idx.advanced(by: 1)]) << 8
142         let d3 = UInt32(slice[idx])
143         let val: UInt32 = d0 | d1 | d2 | d3
144                          
145         result.append(val)
146     }
147     return result
148 }
149
150 struct BytesIterator: IteratorProtocol {
151     
152     let chunkSize: Int
153     let data: [UInt8]
154     
155     init(chunkSize: Int, data: [UInt8]) {
156         self.chunkSize = chunkSize
157         self.data = data
158     }
159     
160     var offset = 0
161     
162     mutating func next() -> ArraySlice<UInt8>? {
163         let end = min(chunkSize, data.count - offset)
164         let result = data[offset..<offset + end]
165         offset += result.count
166         return result.count > 0 ? result : nil
167     }
168 }
169
170 struct BytesSequence: Sequence {
171     let chunkSize: Int
172     let data: [UInt8]
173     
174     func makeIterator() -> BytesIterator {
175         return BytesIterator(chunkSize: chunkSize, data: data)
176     }
177 }
178
179 func rotateLeft(_ value: UInt32, bits: UInt32) -> UInt32 {
180     return ((value << bits) & 0xFFFFFFFF) | (value >> (32 - bits))
181 }
182
183 class MD5: HashProtocol {
184     
185     static let size = 16 // 128 / 8
186     let message: [UInt8]
187     
188     init (_ message: [UInt8]) {
189         self.message = message
190     }
191     
192     /** specifies the per-round shift amounts */
193     private let shifts: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
194                                     5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
195                                     4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
196                                     6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
197     
198     /** binary integer part of the sines of integers (Radians) */
199     private let sines: [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
200                                0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
201                                0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
202                                0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
203                                0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
204                                0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
205                                0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
206                                0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
207                                0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
208                                0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
209                                0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
210                                0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
211                                0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
212                                0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
213                                0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
214                                0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391]
215     
216     private let hashes: [UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
217     
218     func calculate() -> [UInt8] {
219         var tmpMessage = prepare(64)
220         tmpMessage.reserveCapacity(tmpMessage.count + 4)
221         
222         // hash values
223         var hh = hashes
224         
225         // Step 2. Append Length a 64-bit representation of lengthInBits
226         let lengthInBits = (message.count * 8)
227         let lengthBytes = lengthInBits.bytes(64 / 8)
228         tmpMessage += lengthBytes.reversed()
229
230         // Process the message in successive 512-bit chunks:
231         let chunkSizeBytes = 512 / 8 // 64
232
233         for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
234             // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
235             var M = toUInt32Array(chunk)
236             assert(M.count == 16, "Invalid array")
237             
238             // Initialize hash value for this chunk:
239             var A: UInt32 = hh[0]
240             var B: UInt32 = hh[1]
241             var C: UInt32 = hh[2]
242             var D: UInt32 = hh[3]
243             
244             var dTemp: UInt32 = 0
245             
246             // Main loop
247             for j in 0 ..< sines.count {
248                 var g = 0
249                 var F: UInt32 = 0
250                 
251                 switch j {
252                 case 0...15:
253                     F = (B & C) | ((~B) & D)
254                     g = j
255                     break
256                 case 16...31:
257                     F = (D & B) | (~D & C)
258                     g = (5 * j + 1) % 16
259                     break
260                 case 32...47:
261                     F = B ^ C ^ D
262                     g = (3 * j + 5) % 16
263                     break
264                 case 48...63:
265                     F = C ^ (B | (~D))
266                     g = (7 * j) % 16
267                     break
268                 default:
269                     break
270                 }
271                 dTemp = D
272                 D = C
273                 C = B
274                 B = B &+ rotateLeft((A &+ F &+ sines[j] &+ M[g]), bits: shifts[j])
275                 A = dTemp
276             }
277             
278             hh[0] = hh[0] &+ A
279             hh[1] = hh[1] &+ B
280             hh[2] = hh[2] &+ C
281             hh[3] = hh[3] &+ D
282         }
283         
284         var result = [UInt8]()
285         result.reserveCapacity(hh.count / 4)
286         
287         hh.forEach {
288             let itemLE = $0.littleEndian
289             let r1 = UInt8(itemLE & 0xff)
290             let r2 = UInt8((itemLE >> 8) & 0xff)
291             let r3 = UInt8((itemLE >> 16) & 0xff)
292             let r4 = UInt8((itemLE >> 24) & 0xff)
293             result += [r1, r2, r3, r4]
294         }
295         return result
296     }
297 }