You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

510 lines
20 KiB

  1. [![Platform](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android%20%7CmacOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=28a745)](#installation)
  2. [![Swift support](https://img.shields.io/badge/Swift-3.1%20%7C%203.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0-lightgrey.svg?colorA=28a745&colorB=4E4E4E)](#swift-versions-support)
  3. [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/CryptoSwift.svg?style=flat&label=CocoaPods&colorA=28a745&&colorB=4E4E4E)](https://cocoapods.org/pods/CryptoSwift)
  4. [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/Carthage/Carthage)
  5. [![Accio supported](https://img.shields.io/badge/Accio-supported-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/JamitLabs/Accio)
  6. [![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/apple/swift-package-manager)
  7. [![Twitter](https://img.shields.io/badge/Twitter-@krzyzanowskim-blue.svg?style=flat)](http://twitter.com/krzyzanowskim)
  8. # CryptoSwift
  9. Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift))
  10. **Note**: The `master` branch follows the latest currently released **version of Swift**. If you need an earlier version for an older version of Swift, you can specify its version in your `Podfile` or use the code on the branch for that version. Older branches are unsupported. Check [versions](#swift-versions-support) for details.
  11. ---
  12. [Requirements](#requirements) | [Features](#features) | [Contribution](#contribution) | [Installation](#installation) | [Swift versions](#swift-versions-support) | [How-to](#how-to) | [Author](#author) | [License](#license) | [Changelog](#changelog)
  13. ## Sponsorship
  14. If you (or your Company) use this work, please consider [Sponsorship](https://github.com/users/krzyzanowskim/sponsorship). This is the only option to keep the project alive, that is in your own best interrest.
  15. CryptoSwift isn't backed by a big company and is developer in my spare time that I also use to as a freelancer.
  16. ## Requirements
  17. Good mood
  18. ## Features
  19. - Easy to use
  20. - Convenient extensions for String and Data
  21. - Support for incremental updates (stream, ...)
  22. - iOS, Android, macOS, AppleTV, watchOS, Linux support
  23. #### Hash (Digest)
  24. [MD5](http://tools.ietf.org/html/rfc1321)
  25. | [SHA1](http://tools.ietf.org/html/rfc3174)
  26. | [SHA224](http://tools.ietf.org/html/rfc6234)
  27. | [SHA256](http://tools.ietf.org/html/rfc6234)
  28. | [SHA384](http://tools.ietf.org/html/rfc6234)
  29. | [SHA512](http://tools.ietf.org/html/rfc6234)
  30. | [SHA3](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
  31. #### Cyclic Redundancy Check (CRC)
  32. [CRC32](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
  33. | [CRC32C](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
  34. | [CRC16](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
  35. #### Cipher
  36. [AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf)
  37. | [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf)
  38. | [Rabbit](https://tools.ietf.org/html/rfc4503)
  39. | [Blowfish](https://www.schneier.com/academic/blowfish/)
  40. #### Message authenticators
  41. [Poly1305](http://cr.yp.to/mac/poly1305-20050329.pdf)
  42. | [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt)
  43. | [CMAC](https://tools.ietf.org/html/rfc4493)
  44. | [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
  45. #### Cipher mode of operation
  46. - Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))
  47. - Cipher-block chaining ([CBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29))
  48. - Propagating Cipher Block Chaining ([PCBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29))
  49. - Cipher feedback ([CFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29))
  50. - Output Feedback ([OFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29))
  51. - Counter Mode ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29))
  52. - Galois/Counter Mode ([GCM](https://csrc.nist.gov/publications/detail/sp/800-38d/final))
  53. - Counter with Cipher Block Chaining-Message Authentication Code ([CCM](https://csrc.nist.gov/publications/detail/sp/800-38c/final))
  54. #### Password-Based Key Derivation Function
  55. - [PBKDF1](http://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1)
  56. - [PBKDF2](http://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2)
  57. - [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function)
  58. - [Scrypt](https://tools.ietf.org/html/rfc7914) (The scrypt Password-Based Key Derivation Function)
  59. #### Data padding
  60. PKCS#5
  61. | [PKCS#7](http://tools.ietf.org/html/rfc5652#section-6.3)
  62. | [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding)
  63. | No padding
  64. #### Authenticated Encryption with Associated Data (AEAD)
  65. - [AEAD\_CHACHA20\_POLY1305](https://tools.ietf.org/html/rfc7539#section-2.8)
  66. ## Why
  67. [Why?](https://github.com/krzyzanowskim/CryptoSwift/issues/5) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/issues/5#issuecomment-53379391).
  68. ## How do I get involved?
  69. You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request.
  70. ## Contribution
  71. Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to help with CryptoSwift.
  72. - If you found a bug, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
  73. - If you have a feature request, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
  74. ## Installation
  75. To install CryptoSwift, add it as a submodule to your project (on the top level project directory):
  76. git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
  77. It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance.
  78. #### Embedded Framework
  79. Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9). Drag the `CryptoSwift.xcodeproj` file into your Xcode project, and add appropriate framework as a dependency to your target. Now select your App and choose the General tab for the app target. Find *Embedded Binaries* and press "+", then select `CryptoSwift.framework` (iOS, OS X, watchOS or tvOS)
  80. ![](https://cloud.githubusercontent.com/assets/758033/10834511/25a26852-7e9a-11e5-8c01-6cc8f1838459.png)
  81. Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target
  82. ![](https://cloud.githubusercontent.com/assets/758033/18415615/d5edabb0-77f8-11e6-8c94-f41d9fc2b8cb.png)
  83. ##### iOS, macOS, watchOS, tvOS
  84. In the project, you'll find [single scheme](https://mxcl.dev/PromiseKit/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms:
  85. - CryptoSwift
  86. #### Swift versions support
  87. - Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13
  88. - Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3
  89. - Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2
  90. - Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9
  91. - Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0
  92. - Swift 4.0, branch [swift4](https://github.com/krzyzanowskim/CryptoSwift/tree/swift4) version <= 0.12.0
  93. - Swift 4.2, branch [swift42](https://github.com/krzyzanowskim/CryptoSwift/tree/swift42) version <= 0.15.0
  94. - Swift 5.0, 5.1, branch [master](https://github.com/krzyzanowskim/CryptoSwift/tree/master)
  95. #### CocoaPods
  96. You can use [CocoaPods](https://cocoapods.org/pods/CryptoSwift).
  97. ```ruby
  98. pod 'CryptoSwift', '~> 1.0'
  99. ```
  100. Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that may impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin.
  101. #### Carthage
  102. You can use [Carthage](https://github.com/Carthage/Carthage).
  103. Specify in Cartfile:
  104. ```ruby
  105. github "krzyzanowskim/CryptoSwift"
  106. ```
  107. Run `carthage` to build the framework and drag the built CryptoSwift.framework into your Xcode project. Follow [build instructions](https://github.com/Carthage/Carthage#getting-started). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/issues/492#issuecomment-330822874).
  108. #### Swift Package Manager
  109. You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
  110. ```swift
  111. .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))
  112. ```
  113. See: [Package.swift - manual](http://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/)
  114. #### Accio
  115. You can use [Accio](https://github.com/JamitLabs/Accio). Specify in `Package.swift`:
  116. ```swift
  117. .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.0.0")),
  118. ```
  119. Then run `accio update`.
  120. ---
  121. ## How-to
  122. * [Basics (data types, conversion, ...)](#basics)
  123. * [Digest (MD5, SHA...)](#calculate-digest)
  124. * [Message authenticators (HMAC, CMAC...)](#message-authenticators-1)
  125. * [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions)
  126. * [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function)
  127. * [Data Padding](#data-padding)
  128. * [ChaCha20](#chacha20)
  129. * [Rabbit](#rabbit)
  130. * [Blowfish](#blowfish)
  131. * [AES - Advanced Encryption Standard](#aes)
  132. * [AES-GCM](#aes-gcm)
  133. * [Authenticated Encryption with Associated Data (AEAD)](#aead)
  134. also check [Playground](/CryptoSwift.playground/Contents.swift)
  135. ##### Basics
  136. ```swift
  137. import CryptoSwift
  138. ```
  139. CryptoSwift uses array of bytes aka `Array<UInt8>` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes.
  140. ##### Data types conversion
  141. For your convenience, **CryptoSwift** provides two functions to easily convert an array of bytes to `Data` or `Data` to an array of bytes:
  142. Data from bytes:
  143. ```swift
  144. let data = Data( [0x01, 0x02, 0x03])
  145. ```
  146. `Data` to `Array<UInt8>`
  147. ```swift
  148. let bytes = data.bytes // [1,2,3]
  149. ```
  150. [Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding:
  151. ```swift
  152. let bytes = Array<UInt8>(hex: "0x010203") // [1,2,3]
  153. let hex = bytes.toHexString() // "010203"
  154. ```
  155. Build bytes out of `String`
  156. ```swift
  157. let bytes: Array<UInt8> = "cipherkey".bytes // Array("cipherkey".utf8)
  158. ```
  159. Also... check out helpers that work with **Base64** encoded data:
  160. ```swift
  161. "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
  162. "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
  163. bytes.toBase64()
  164. ```
  165. ##### Calculate Digest
  166. Hashing a data or array of bytes (aka `Array<UInt8>`)
  167. ```swift
  168. /* Hash struct usage */
  169. let bytes:Array<UInt8> = [0x01, 0x02, 0x03]
  170. let digest = input.md5()
  171. let digest = Digest.md5(bytes)
  172. ```
  173. ```swift
  174. let data = Data( [0x01, 0x02, 0x03])
  175. let hash = data.md5()
  176. let hash = data.sha1()
  177. let hash = data.sha224()
  178. let hash = data.sha256()
  179. let hash = data.sha384()
  180. let hash = data.sha512()
  181. ```
  182. ```swift
  183. do {
  184. var digest = MD5()
  185. let partial1 = try digest.update(withBytes: [0x31, 0x32])
  186. let partial2 = try digest.update(withBytes: [0x33])
  187. let result = try digest.finish()
  188. } catch { }
  189. ```
  190. Hashing a String and printing result
  191. ```swift
  192. let hash = "123".md5() // "123".bytes.md5()
  193. ```
  194. ##### Calculate CRC
  195. ```swift
  196. bytes.crc16()
  197. data.crc16()
  198. bytes.crc32()
  199. data.crc32()
  200. ```
  201. ##### Message authenticators
  202. ```swift
  203. // Calculate Message Authentication Code (MAC) for message
  204. let key:Array<UInt8> = [1,2,3,4,5,6,7,8,9,10,...]
  205. try Poly1305(key: key).authenticate(bytes)
  206. try HMAC(key: key, variant: .sha256).authenticate(bytes)
  207. try CMAC(key: key).authenticate(bytes)
  208. ```
  209. ##### Password-Based Key Derivation Functions
  210. ```swift
  211. let password: Array<UInt8> = Array("s33krit".utf8)
  212. let salt: Array<UInt8> = Array("nacllcan".utf8)
  213. let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate()
  214. ```
  215. ```swift
  216. let password: Array<UInt8> = Array("s33krit".utf8)
  217. let salt: Array<UInt8> = Array("nacllcan".utf8)
  218. // Scrypt implementation does not implement work parallelization, so `p` parameter will
  219. // increase the work time even in multicore systems
  220. let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate()
  221. ```
  222. ##### HMAC-based Key Derivation Function
  223. ```swift
  224. let password: Array<UInt8> = Array("s33krit".utf8)
  225. let salt: Array<UInt8> = Array("nacllcan".utf8)
  226. let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate()
  227. ```
  228. ##### Data Padding
  229. Some content-encryption algorithms assume the input length is a multiple of `k` octets, where `k` is greater than one. For such algorithms, the input shall be padded.
  230. ```swift
  231. Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize)
  232. ```
  233. #### Working with Ciphers
  234. ##### ChaCha20
  235. ```swift
  236. let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message)
  237. let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted)
  238. ```
  239. ##### Rabbit
  240. ```swift
  241. let encrypted = try Rabbit(key: key, iv: iv).encrypt(message)
  242. let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
  243. ```
  244. ##### Blowfish
  245. ```swift
  246. let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message)
  247. let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
  248. ```
  249. ##### AES
  250. Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need to manually disable/enable padding, you can do this by setting parameter for __AES__ class*
  251. Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length:
  252. - AES-128 = 16 bytes
  253. - AES-192 = 24 bytes
  254. - AES-256 = 32 bytes
  255. AES-256 example
  256. ```swift
  257. try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7)
  258. ```
  259. ###### All at once
  260. ```swift
  261. do {
  262. let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128
  263. let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8))
  264. } catch { }
  265. ```
  266. ###### Incremental updates
  267. Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files.
  268. ```swift
  269. do {
  270. var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor()
  271. var ciphertext = Array<UInt8>()
  272. // aggregate partial results
  273. ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
  274. ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
  275. ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8))
  276. // finish at the end
  277. ciphertext += try encryptor.finish()
  278. print(ciphertext.toHexString())
  279. } catch {
  280. print(error)
  281. }
  282. ```
  283. See [Playground](/CryptoSwift.playground/Contents.swift) for sample code that work with stream.
  284. ###### AES Advanced usage
  285. ```swift
  286. let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
  287. let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
  288. let iv: Array<UInt8> = // Random bytes of `AES.blockSize` length
  289. do {
  290. let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input)
  291. let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
  292. } catch {
  293. print(error)
  294. }
  295. ```
  296. AES without data padding
  297. ```swift
  298. let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
  299. let encrypted: Array<UInt8> = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)
  300. ```
  301. Using convenience extensions
  302. ```swift
  303. let plain = Data( [0x01, 0x02, 0x03])
  304. let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv))
  305. let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
  306. ```
  307. ##### AES-GCM
  308. The result of Galois/Counter Mode (GCM) encryption is ciphertext and **authentication tag**, that is later used to decryption.
  309. encryption
  310. ```swift
  311. do {
  312. // In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
  313. let gcm = GCM(iv: iv, mode: .combined)
  314. let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
  315. let encrypted = try aes.encrypt(plaintext)
  316. let tag = gcm.authenticationTag
  317. catch {
  318. // failed
  319. }
  320. ```
  321. decryption
  322. ```swift
  323. do {
  324. // In combined mode, the authentication tag is appended to the encrypted message. This is usually what you want.
  325. let gcm = GCM(iv: iv, mode: .combined)
  326. let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
  327. return try aes.decrypt(encrypted)
  328. } catch {
  329. // failed
  330. }
  331. ```
  332. **Note**: GCM instance is not intended to be reused. So you can't use the same `GCM` instance from encoding to also perform decoding.
  333. ##### AES-CCM
  334. The result of Counter with Cipher Block Chaining-Message Authentication Code encryption is ciphertext and **authentication tag**, that is later used to decryption.
  335. ```swift
  336. do {
  337. // The authentication tag is appended to the encrypted message.
  338. let tagLength = 8
  339. let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data)
  340. let aes = try AES(key: key, blockMode: ccm, padding: .noPadding)
  341. return try aes.decrypt(encrypted)
  342. } catch {
  343. // failed
  344. }
  345. ```
  346. Check documentation or CCM specification for valid parameters for CCM.
  347. ##### AEAD
  348. ```swift
  349. let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header)
  350. let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag)
  351. ```
  352. ## Author
  353. CryptoSwift is owned and maintained by [Marcin Krzyżanowski](http://www.krzyzanowskim.com)
  354. You can follow me on Twitter at [@krzyzanowskim](http://twitter.com/krzyzanowskim) for project updates and releases.
  355. # Cryptography Notice
  356. This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/ for more information.
  357. ## License
  358. Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  359. This software is provided 'as-is', without any express or implied warranty.
  360. In no event will the authors be held liable for any damages arising from the use of this software.
  361. 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:
  362. - 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**.
  363. - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  364. - This notice may not be removed or altered from any source or binary distribution.
  365. - Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).'
  366. ## Changelog
  367. See [CHANGELOG](./CHANGELOG) file.