Compare commits

...

63 Commits

Author SHA1 Message Date
Peter Siegesmund 0086c768d5
Merge pull request #119 from sjkummer/bugfix/crash-in-ddpclient-sub-sendmessage
Bugfix:  'self' may be nil when code is executed in a background thread
2019-06-16 12:03:05 -04:00
Sebastian Kummer b88fb1981f Bugfix: 'self' may be nil when code is executed in a background thread 2019-06-04 14:45:47 +02:00
Peter Siegesmund 9c2497df1e
Merge pull request #115 from jmaratt/jmaratt-podspec-SwiftWebSocket
Update SwiftDDP.podspec
2019-02-19 14:13:05 -05:00
jmaratt 7b9a626cd9
Update SwiftDDP.podspec
Removing the address for SwiftWebSocket resolved the 'unsupported version requirements' error.
2019-01-27 11:35:24 -05:00
Peter Siegesmund bcab1fca16
Merge pull request #113 from sam961/swift-4.2
Swift 4.2 compatibility
2019-01-23 09:56:30 -05:00
Sam 51e01158a9
Update SwiftDDP.podspec 2018-12-24 13:23:21 +02:00
Sam Kad 401debd079 Swift 4.2 compatibility 2018-12-24 00:27:37 +02:00
Peter Siegesmund bc0858f8b3
Merge pull request #111 from y-ich/master
a few changes for macOS and SwiftPM
2018-10-31 20:24:57 -04:00
Yuji Ichikawa fb47728c0f modified README.md 2018-10-09 16:06:25 +09:00
Yuji Ichikawa 58cf3410eb made _id and propertyNames public for sub class 2018-10-09 13:38:53 +09:00
Yuji Ichikawa b8c954ef74 swift package manager 2018-10-07 12:03:12 +09:00
Yuji Ichikawa efc2d67c9e split Cartfile for test 2018-10-07 11:14:33 +09:00
Yuji Ichikawa a8107517be split a file to support macOS 2018-10-07 11:14:01 +09:00
Peter Siegesmund a33e668667
Merge pull request #108 from ajijoyo/master
support swift 4.0
2018-04-16 20:22:25 -04:00
ajiejoy-Macbook Pro 5a4892f265 support swift 4.0 2018-04-15 17:19:10 +07:00
Peter Siegesmund e7197254ff
Merge pull request #100 from ktorimaru/Issue98Ambiguous
Fix Issue 98
2018-01-27 14:57:13 -05:00
ktorimaru 8074ddcd3d Fix Issue 98 2017-07-20 16:40:41 -07:00
Peter Siegesmund 5765ce10c2 Merge pull request #97 from yvdorofeev/master
resume() fix for expired login tokens;
2017-05-08 18:09:59 -04:00
yury 0c0f0da5b9 resume() fix for expired login tokens;
https://github.com/siegesmund/SwiftDDP/issues/96
2017-05-07 13:22:03 -07:00
Peter Siegesmund 420eeb9c69 Merge pull request #93 from smyrgl/master
Fix for Swift 3.1
2017-03-29 17:54:07 -04:00
John Tumminaro 50216dc451 Fix for Swift 3.1 2017-03-28 13:37:13 -06:00
Peter Siegesmund b8c108e822 Merge pull request #90 from mjgaylord/patch-2
Remove force-unwrap of self.user()
2017-01-11 08:15:00 -05:00
Michael Gaylord 36a68052bd Remove force-unwrap of self.user()
Duplicate calls that happen in quick succession of `func logout(:)` result in a crash because `self.user()!` is force-unwrapped. Checking for existence of the user object seems to prevent the crash.
2017-01-11 11:48:12 +02:00
Peter Siegesmund f1c4ef9216 Updated readme 2016-12-20 11:08:43 -05:00
Peter Siegesmund f6b9d8f735 Update README.md 2016-12-20 11:07:43 -05:00
Peter Siegesmund 5e75addb62 version 0.4.1 2016-12-20 10:24:22 -05:00
Peter Siegesmund ae3aff1f76 Merge pull request #86 from QOX/master
PR: export DDPClient.login function with any parameters
2016-12-03 21:12:54 -05:00
Katsumi Honda 9b81684542 export DDPClient.login function
login function with any parameters using for custom auth provider.
It's like a asteroid style.
https://github.com/mondora/asteroid#loginparams
2016-12-04 10:59:45 +09:00
Peter Siegesmund 5407f6d03b Merge pull request #84 from yvdorofeev/master
Added global events for connection failures
2016-12-03 20:40:39 -05:00
Peter Siegesmund c4bf094d57 Merge pull request #85 from louis49/master
Back of Unsub Callback
2016-12-03 20:40:02 -05:00
yvdorofeev f62a3ed49c updated docs 2016-12-03 13:57:21 -08:00
Benoît Desnos 1253f6ee58 Log info correction (replace print) 2016-11-30 17:53:10 +01:00
Benoît Desnos 025eaaf283 Back of Unsub Callback 2016-11-30 17:42:03 +01:00
yvdorofeev e2def57366 Added global events for connection failures 2016-11-27 12:30:01 -08:00
Peter Siegesmund 0d4761160d updated docs 2016-11-18 11:23:54 -05:00
Peter Siegesmund 1b91647f20 updated docs 2016-11-18 11:06:14 -05:00
Peter Siegesmund c04800d1bf updated docs 2016-11-18 11:05:32 -05:00
Peter Siegesmund 28939ffbf2 Version 0.4.0 2016-11-18 11:03:31 -05:00
Peter Siegesmund bd514a6979 Merge pull request #82 from mjgaylord/master
Upgraded to Swift 3
2016-11-18 11:01:26 -05:00
Michael Gaylord 072e532285 Make result of method calls @discardableResult 2016-11-18 15:44:58 +02:00
Michael Gaylord 35520266d2 Use Any rather than AnyObject 2016-11-18 14:28:05 +02:00
Michael Gaylord a87499dd6f Update podspec to use Swift3 dependencies 2016-11-18 12:19:38 +02:00
Michael Gaylord 8a344222dc Tests failing but project is compiling 2016-11-18 12:17:41 +02:00
Peter Siegesmund c6542fe796 Update SwiftDDP.podspec 2016-09-13 13:36:21 -04:00
Peter Siegesmund 180da50636 Merge pull request #69 from spunkedy/master
tvOS carthage scheme
2016-08-27 07:50:22 -04:00
Ed Bond a573e193e0 commenting out because files don't exist 2016-08-22 23:05:42 -05:00
Ed Bond 52ac2ce19a new schemes for tvos and osx to have it work with carthage 2016-08-22 23:05:14 -05:00
Peter Siegesmund de60d19492 Merge pull request #68 from Gigha/master
Support tvos on CocoaPods #67
2016-08-18 18:38:55 -04:00
Gigha a23ea2cf42 Support tvos on CocoaPods 2016-08-16 14:29:51 +02:00
Peter Siegesmund eea2668a6a Removed OAuth in favor or using provider SDKs 2016-08-14 12:46:54 -04:00
Peter Siegesmund 7381b50aab Removed OAuth in favor or using provider SDKs 2016-08-14 12:46:39 -04:00
Peter Siegesmund b99bcf27f1 Removed OAuth in favor or using provider SDKs 2016-08-14 12:46:24 -04:00
Peter Siegesmund 1bcaf2377c Update README.md 2016-08-10 21:29:38 -04:00
Peter Siegesmund 660026d209 Update README.md 2016-08-10 21:29:13 -04:00
Peter Siegesmund 5a1261f573 Update README.md 2016-08-10 10:04:56 -04:00
Peter Siegesmund 6032739399 Merge pull request #63 from yvdorofeev/master
Make sure that user has been reset before user logout notification is posted.
2016-08-01 14:00:40 -04:00
yvdorofeev 98d4b71bff Update DDPExtensions.swift
Issue #62
2016-07-31 22:27:54 -07:00
Peter ebbf424711 podfile updated 2016-06-26 09:23:32 -04:00
Peter 00e60a9fa8 updated docs 2016-06-26 09:21:57 -04:00
Peter 50d24741cd updated docs 2016-06-26 09:21:08 -04:00
Peter ffffcd74f9 updated docs 2016-06-26 09:20:02 -04:00
Peter 7a2f408762 updated docs 2016-06-26 09:11:12 -04:00
Peter c28ab57d02 removed outdated examples 2016-06-26 09:08:13 -04:00
274 changed files with 1384 additions and 47051 deletions

3
.gitignore vendored
View File

@ -24,3 +24,6 @@ DerivedData
Carthage
Cartfile.resolved
# SPM
.build/

View File

@ -1,5 +1,3 @@
github "krzyzanowskim/CryptoSwift"
# github "Quick/Nimble" # Not building with Swift 2.2
# github "Quick/Quick" # Not building with Swift 2.2
github "tidwall/SwiftWebSocket"
github "DaveWoodCom/XCGLogger"

2
Cartfile.private Normal file
View File

@ -0,0 +1,2 @@
github "Quick/Nimble" # Not building with Swift 2.2
github "Quick/Quick" # Not building with Swift 2.2

View File

@ -1,68 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "lock-22.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "lock-44.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "lock-66.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "unlock-22.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "unlock-44.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "unlock-66.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "user_icon.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,666 +0,0 @@
%PDF-1.4 %âãÏÓ
1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 37692/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c011 79.156289, 2014/03/31-23:39:12 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/"
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/"
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Deelnemers icon</rdf:li>
</rdf:Alt>
</dc:title>
<xmp:CreatorTool>Adobe Illustrator CC 2014 (Macintosh)</xmp:CreatorTool>
<xmp:CreateDate>2014-09-24T18:42:19+02:00</xmp:CreateDate>
<xmp:ModifyDate>2014-09-24T18:42:19+02:00</xmp:ModifyDate>
<xmp:MetadataDate>2014-09-24T18:42:19+02:00</xmp:MetadataDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>40</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAKAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A6J5d8ueefLXnm0Edin1G&#xA;ZIIr65gieeCcNFBDM5n9RZI2DRNJR4ePLf8A3a7Iqi/zv8r+dbu3fWfK+nQatfQLbRwWzuwmQA3K&#xA;TsiExoRwuEI+KvNQ1KqMVT31POmr/lPay6rpxHmSWGB9U0m3IjaT05lM8Kmc8avGpqrEq32d1NcV&#xA;QH5S6VqFrdXUo0+bTbEQqkyyJcQxzXDJD9iO7jhnJidJqyMtCJFVWZUARV5r+a35T+fde88eatRg&#xA;g+s39yNNfyTqXqXamz9Ap9YSJ4FMEBJBqZiP5h1JxV6j+cNj52b8vof0DbjWNXspIpb2zCrS6RYX&#xA;R6RsGVqSssgWn7O29MVS/wD5x403zvZ+U5X80WDaSHMUdjp0tBKFhQo08gABDy/Dy5fEzAsdzUqs&#xA;Mk/JjX387XHmUahfJ5wOtfWraX0XNuLL6zQN9d+wIhas1beu9OHHvir2zzxp/mfUfKmo2Xle/TTN&#xA;fmjC2F9KKpG/NSSfgk6qCPsnFUT5Zs9es9BsrbX9QTVdZijpe6hFCLdJXqTURKSFoKDbr1oOmKpn&#xA;irEvzQ0nzZqnlZrTyvcSW2pmZG9SGY27+mA1aSBk/aKmnIVxVNvKNrq1p5Z0y21d2k1OG3RLt3kM&#xA;zGQDflISS5964qhdP07znH501S+vdUgm8rTwRR6XpaRcZoZkoZJHkp8XIlu/SmKpJ530DUr/AM16&#xA;ZdL5ct/M2lrY3UE1vqEsCW1tO0kTRSIkqyktKodXPpmiqKEbhlU60Ly/qGmeR10V5yt5HbTRxNaM&#xA;x9D1C7RQ2zzmpW3VljiZ6bKCadMVeOf846fkT+YPkXzRf6/5k1CBYb21ML2EE0k7yzSOsnqTEqqV&#xA;TidwWNSe3VV6r5x8rJqGopftotvrpeJLdLe4ZYvRkjaRlkZm+1A/rMs6AMSAPgfcYqpea/y6Osfl&#xA;Pc+RLa9Nu7afFY295RgOduE4FlBYhGaMBlBPwmmKsQ/5xu/KXzT5D0vWLzzTderrGsywq1sJfXWK&#xA;GzDpExkqQzOH+hQveoCqfxeSNVuPNT6rJaLbyxXjumpSTKZHhF4s6usaCQ8/RX6unJl/dkhtqJir&#xA;0XFWJLqOs+apWGiXR0zy4jFTrMao9zeFSQwsxIGSOEEU9dlYv+wAKSFVExflz5JHx3WkQalcHZrv&#xA;UwdQuD41mujNJT2rTFXS/lz5L+3Z6VDpVwN1u9Lrp84Pb95amJmH+S1R4jFVD9K6z5ZuoodeuP0h&#xA;oNw4ig1wosc1tI5CpHfLGFjKOxos6KoBorqPtFVleKsX/MX8xfLnkHy3NruuS0jX4LW1SnrXExFV&#xA;iiU9+5PQDc4q+I/zF/5yK/MnzpdSqdQk0fR2JEWlWEjRJwrsJZV4ySnx5Hj4KMVeYs7s5kZizseT&#xA;MTUknepOKvQPIP57/mV5JuYzp+rS3mnKR6mlXzNcWzKOyhjyi+cZXFX23+U35s+XfzJ8u/pPTP8A&#xA;R7634pqemOwaS3kYGm9BzR6Hg9N/YggKs3xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxVjXnZpbuGw8uwu0ba9cG2upEJV0soo2muiCNx6kaegGG6mQEdMVRGo+ZNN0e9tNFtrG&#xA;5urp4DLDZWEAZYreIiMMxJjijWpCqOVT2GxxVAG480a5dySCS68q6LZggyulo15cyEVJpMt1DFAg&#xA;PWnN2/lVfjVbFz5p0K9USm680aNeCsVzGlqt5bSBa0dYhawyQSAfCyjkrbHkGBVVG2GvaV5gl1HQ&#xA;rqxuIJo4F+u6ffw8BJbXQdAykF45Ebg6tRjToaYqp+SZ7iOyvNEunaW40C5NgJnYs8lv6aTWsjM2&#xA;7N9XmRXY9XVsVfF3/OUnn268z/mhfacspOleXGbT7SEH4RMlBdPT+Yyrx+SjFUg0D8gPzd12ysr/&#xA;AE/y7MbDUAj211K8MSmNz8MhDurhab149Nxir6FsP+cMvIa6BHZX+sXjeZmtyZLqF4xAJj+0luyc&#xA;2jVtt2BPtXZV4Prv/ONn5x6TNej9ASXtrZFz9ctZIpEljSp5xpy9VuQ3C8OXalcVQX5D+frnyV+Z&#xA;ek6gJOOn3kq2GqITRWtrhgpZv+MTUkH+rir9EsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVY3qPIfmHoLNT0jpeqoKjf1TPp7LQ9AeCyYqtubOK8863ltM0ixy6TAGaCWSCQf6&#xA;TKfhlhZJF/2LDFUg/MPVNIsfN3l+PzPaNdeW5kkWAOjTWyXvVZJoQr+q6qqiIUPHk7/sllVb/LTU&#xA;9NvvMfmYeXbQ2nlaFoEgCK0Vu95RjcSQwlUMLNUCRKUNFk6uaqp/p9pDZ+dGtYOXowaPbRx+o7yt&#xA;xW4lA5PIWdjTuxJxVfo1D508yFacBHYI9BT94I5Wap7ngyYq/Oz8wUnTz75lS4/3oXVb0TbEfGLh&#xA;+Wx3G+Kv0O/LuzhHk3y5eBpfWfRrCIqZZTFxWBGqIS3pBt/tBeXauKvK7TzN5DHkm4PmHSn/AMcp&#xA;MI9Sf0pDqH6SLACaK9WNjG8fKqKrfBT00qOPJV7No1peXGl6Nd6yGXWbe2ja6VJGWMXEkIWfkiN6&#xA;b/FWnIGnbFX5hRiRpFEYJkJAQLXkWrtSnfFX6pYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYqx3zpa3gtLPWrCFri+0K4F6ltGCXmgMbw3UKAfadoJXaNe8gX54qoz6ff6rqNl5&#xA;o8s61bRW91ZCFlntTeW88LN6sMqGOa1dGXk37RBB6VGKr7nR/Ot3A0F1qejTwP8Abil0id0PfdW1&#xA;Ag4q3b6T52toEgttU0eCCMUSKPSZ0RR1oFXUABiqnBZ3mh3Wq+afM+sQTxJaRxAW9q1rDBBAXkY8&#xA;WmupJJHaT+bsAFr1VRHkuxvYtOudS1CJrfUtbuX1G7t3+1CHVYoIWptyitookem3IE4q+Ov+csPy&#xA;6uvLn5iTeYIIj+h/MhNzHIoPFLoAC4jY+LN+8Hjy9jiqJ8t/85g+f9E0DT9HGl6bdpp1vHax3Eqz&#xA;K7pEoROQSRVrxAGwxVEv/wA5jebHvVvn8r6G16gol0YpjKB4B/U5d/HFVS6/5zV/MWW2lih0jS7e&#xA;Z0ZY7hVnYxsRQOFaUqSvXcUxVhX/ADjr+XV150/MnTw0RbR9Hkjv9VlIPDhE3KKInxlkULT+Xke2&#xA;Kv0ExV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KsWm0PWdCu577yyI7ix&#xA;uHaa88vzP6aGV2LyTWcp5CGRyxLxsPTdt6oSzMqqDz9pESsNTtNR0qaMEyR3VlcFFA60uIFmtn/2&#xA;EpxVzefdLlCrpdlqOrTvT047aynRDXxuLlYLZf8AZSjFVtroWsavfw6l5m9KOC1YS6foMDGSGOVT&#xA;VJ7mUhfXlTqgChEO45MFcKsnxVJPOXk3y/5x8v3Oga/bC50+5AJAPF43XdJI3G6up6H6DUEjFXxr&#xA;+Yv/ADif+Ynly6ln8vwnzJo9S0clsALpFrssluTyY+8fKvt0xV5e/wCX3n1J/q7+WtVW43/cmyuA&#xA;+xofh4V2OKvQvIP/ADi3+aHme5ifUbJvLmlkj1bvUFKTBe/C1JEpb/W4j3xV9mfl3+XXlryD5di0&#xA;TQYSsYPO6upKGa4lpQySsAKnwA2A2GKv/9k=</xmpGImg:image>
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:OriginalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</xmpMM:OriginalDocumentID>
<xmpMM:DocumentID>xmp.did:942758b8-75d1-423d-8b0d-f9ef846649f7</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:4fc7e4f0-271c-f949-a042-53711c801259</xmpMM:InstanceID>
<xmpMM:DerivedFrom rdf:parseType="Resource">
<stRef:instanceID>uuid:f9f8ddc6-5d6d-944b-a129-52a52fb086b9</stRef:instanceID>
<stRef:documentID>xmp.did:cfe4c0cb-aa94-4b90-b875-386c79ddd292</stRef:documentID>
<stRef:originalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</stRef:originalDocumentID>
<stRef:renditionClass>proof:pdf</stRef:renditionClass>
</xmpMM:DerivedFrom>
<xmpMM:History>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:a14d73b1-4718-4821-9702-88ea339373cf</stEvt:instanceID>
<stEvt:when>2014-09-24T13:45:07+02:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CC 2014 (Macintosh)</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:942758b8-75d1-423d-8b0d-f9ef846649f7</stEvt:instanceID>
<stEvt:when>2014-09-24T18:42:19+02:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CC 2014 (Macintosh)</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
</rdf:Seq>
</xmpMM:History>
<illustrator:StartupProfile>Web</illustrator:StartupProfile>
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>25.000000</stDim:w>
<stDim:h>25.000000</stDim:h>
<stDim:unit>Pixels</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>Wit</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>Zwart</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-rood</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-geel</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-groen</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-cyaan</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-blauw</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-magenta</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>193</xmpG:red>
<xmpG:green>39</xmpG:green>
<xmpG:blue>45</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>237</xmpG:red>
<xmpG:green>28</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>241</xmpG:red>
<xmpG:green>90</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>247</xmpG:red>
<xmpG:green>147</xmpG:green>
<xmpG:blue>30</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>251</xmpG:red>
<xmpG:green>176</xmpG:green>
<xmpG:blue>59</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>252</xmpG:red>
<xmpG:green>238</xmpG:green>
<xmpG:blue>33</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>217</xmpG:red>
<xmpG:green>224</xmpG:green>
<xmpG:blue>33</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>140</xmpG:red>
<xmpG:green>198</xmpG:green>
<xmpG:blue>63</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>57</xmpG:red>
<xmpG:green>181</xmpG:green>
<xmpG:blue>74</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>146</xmpG:green>
<xmpG:blue>69</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>104</xmpG:green>
<xmpG:blue>55</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>34</xmpG:red>
<xmpG:green>181</xmpG:green>
<xmpG:blue>115</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>169</xmpG:green>
<xmpG:blue>157</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>41</xmpG:red>
<xmpG:green>171</xmpG:green>
<xmpG:blue>226</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>113</xmpG:green>
<xmpG:blue>188</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>46</xmpG:red>
<xmpG:green>49</xmpG:green>
<xmpG:blue>146</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>27</xmpG:red>
<xmpG:green>20</xmpG:green>
<xmpG:blue>100</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>102</xmpG:red>
<xmpG:green>45</xmpG:green>
<xmpG:blue>145</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>147</xmpG:red>
<xmpG:green>39</xmpG:green>
<xmpG:blue>143</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>158</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>93</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>212</xmpG:red>
<xmpG:green>20</xmpG:green>
<xmpG:blue>90</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>237</xmpG:red>
<xmpG:green>30</xmpG:green>
<xmpG:blue>121</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>199</xmpG:red>
<xmpG:green>178</xmpG:green>
<xmpG:blue>153</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>153</xmpG:red>
<xmpG:green>134</xmpG:green>
<xmpG:blue>117</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>115</xmpG:red>
<xmpG:green>99</xmpG:green>
<xmpG:blue>87</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>83</xmpG:red>
<xmpG:green>71</xmpG:green>
<xmpG:blue>65</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>198</xmpG:red>
<xmpG:green>156</xmpG:green>
<xmpG:blue>109</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>166</xmpG:red>
<xmpG:green>124</xmpG:green>
<xmpG:blue>82</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>140</xmpG:red>
<xmpG:green>98</xmpG:green>
<xmpG:blue>57</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>117</xmpG:red>
<xmpG:green>76</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>96</xmpG:red>
<xmpG:green>56</xmpG:green>
<xmpG:blue>19</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>66</xmpG:red>
<xmpG:green>33</xmpG:green>
<xmpG:blue>11</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Grijswaarden</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>26</xmpG:red>
<xmpG:green>26</xmpG:green>
<xmpG:blue>26</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>51</xmpG:red>
<xmpG:green>51</xmpG:green>
<xmpG:blue>51</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>77</xmpG:red>
<xmpG:green>77</xmpG:green>
<xmpG:blue>77</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>102</xmpG:red>
<xmpG:green>102</xmpG:green>
<xmpG:blue>102</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>128</xmpG:red>
<xmpG:green>128</xmpG:green>
<xmpG:blue>128</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>153</xmpG:red>
<xmpG:green>153</xmpG:green>
<xmpG:blue>153</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>179</xmpG:red>
<xmpG:green>179</xmpG:green>
<xmpG:blue>179</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>204</xmpG:red>
<xmpG:green>204</xmpG:green>
<xmpG:blue>204</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>230</xmpG:red>
<xmpG:green>230</xmpG:green>
<xmpG:blue>230</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>242</xmpG:red>
<xmpG:green>242</xmpG:green>
<xmpG:blue>242</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Kleurgroep voor web</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=63 G=169 B=245</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>63</xmpG:red>
<xmpG:green>169</xmpG:green>
<xmpG:blue>245</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=122 G=201 B=67</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>122</xmpG:red>
<xmpG:green>201</xmpG:green>
<xmpG:blue>67</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=147 B=30</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>147</xmpG:green>
<xmpG:blue>30</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=29 B=37</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>29</xmpG:green>
<xmpG:blue>37</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=123 B=172</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>123</xmpG:green>
<xmpG:blue>172</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=189 G=204 B=212</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>189</xmpG:red>
<xmpG:green>204</xmpG:green>
<xmpG:blue>212</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
<pdf:Producer>Adobe PDF library 11.00</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[0.0 0.0 25.0 25.0]/BleedBox[0.0 0.0 25.0 25.0]/Contents 6 0 R/MediaBox[0.0 0.0 25.0 25.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0 8 0 R/MC1 9 0 R/MC2 10 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 25.0 25.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 649>>stream
H‰TTÁŽ[! ¼óüÀ#ØÇí¶ª*u«z®¢í^•6í¥ß±ám%yyÆŒg ‡ï¿þ½\âáé1ÇOŸcx9rµï†ßå%üŒo²Ïå5¾þÈñõOx<4F>äC¢K<ž=ê6MRlv#ÂÔVձÎZê]+6[…ç1\Gî"ïܦß÷´Ï1X2©ô!6ç¹QOb# íl•¤¹Åµ†¼8#2ÑmÈÝ⻼×ý&…cøžoÄ*‰¹(þjæq•Œ1lÕ&n#¢ ÄHìª;ðÍú;¦šºhÜrjeDÒTkÌ)gÛˆ{¬DH`dŒ (塘9©¶x2È<32>›Ô@E· Jú:®%5šË¨ £…*¨#£K/ÝŠRšP/€£i$Iv寈í<CB86>-Ê‘$Ý,§ÌÆzŒ¶ôXàj*Vù„bÖªù¾çsduPç6P¤"³85u§œÀüÐNÝj$ƒ¼ÌîA%ûNpñäh˜<æ<·]6MYËRÅ$ÁÒ)÷)À+ÈaN G\'X”ëjÜewq{Ï»Þ!Á's>ws|X«B[—aCvÃ<>ˆÙÊÊÖ8&Íž Œ…§mvʼm8åR§¬˜±&cP®P @«õ- NZMÕÃu­h4¾|"t»õD7õÖ>]öÁ[­¼cÄ—µh¾~´Cñ>©Ý›‚ ¶—Ù¥;³uèï´É8êªéd¢Zf”æon¶U] ¨»aýŠ4€ÕOUÖ9)ÃÛh8c>'µÍØÊî‡XàŽD˯;/çEðå ìáãÆ¥yãN¾uá9âqþxÿtnî endstream endobj 11 0 obj <</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 3/Length 20/Width 3>>stream
8;Ue`J-(6$!rr<-!!*~> endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 8 0 obj <</Color[20224 32768 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Laag 1)/Visible true>> endobj 9 0 obj <</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed false/Title(nyt_exporter_info)/Visible false>> endobj 10 0 obj <</AIType/HiddenLayer/Contents 14 0 R/Resources<</ExtGState<</GS0 15 0 R>>/Font<</T1_0 16 0 R>>/ProcSet[/PDF/Text]>>>> endobj 14 0 obj <</Length 653>>stream
q
0 25 25 -25 re
W n
BT
0 0 0 rg
/GS0 gs
/T1_0 1 Tf
12 0 0 12 -84 25 Tm
[(<n)13(yt_pr)10(ef)9.1(s>)]TJ
0 -1.2 TD
[( <n)13(yt_pr)10(e\037x/>)]TJ
0 -1.2 TD
[( <n)13(yt_su\036x/>)]TJ
0 -1.2 TD
[( <n)13(yt_base_pa)4(th>~/D)-4(eskt)6(op</n)13(yt_base_pa)4(th>)]TJ
0 -1.2 TD
[( <n)13(yt_scaling>100%</n)12.9(yt_scaling>)]TJ
0 -1.2 TD
[( <n)13(yt_tr)5.1(anspar)9.9(enc)-18(y>true</n)13(yt_tr)5(anspar)10(enc)-18(y>)]TJ
T*
[( <n)13(yt_f)12.9(or)-3.9(ma)3.9(t>PNG 24</n)13(yt_f)13(or)-3.9(ma)4.1(t>)]TJ
0 -1.2 TD
[( <n)13(yt_e)2.9(xpor)-24(t_c)6(ode>ar)-24(tboar)10(ds</n)13(yt_e)3(xpor)-24(t_c)5.9(ode>)]TJ
0 -1.2 TD
[(</n)13(yt_pr)10(ef)8.9(s>)]TJ
ET
Q
endstream endobj 16 0 obj <</BaseFont/GSWOXJ+MyriadPro-Regular/Encoding 17 0 R/FirstChar 30/FontDescriptor 18 0 R/LastChar 126/Subtype/Type1/Type/Font/Widths[815 523 212 0 0 0 0 792 0 0 0 0 0 0 0 0 0 343 513 513 513 0 513 0 0 0 0 0 0 0 596 0 596 0 0 0 0 0 666 0 0 646 0 0 0 0 0 0 658 0 532 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 0 482 569 448 564 501 292 559 555 234 0 469 236 834 555 549 569 0 327 396 331 551 0 0 463 471 0 0 0 0 596]>> endobj 17 0 obj <</BaseEncoding/WinAnsiEncoding/Differences[30/f_f_i/f_i]/Type/Encoding>> endobj 18 0 obj <</Ascent 952/CapHeight 674/CharSet(/f_f_i/f_i/space/percent/slash/zero/one/two/four/less/greater/D/G/N/P/underscore/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/r/s/t/u/x/y/asciitilde)/Descent -250/Flags 32/FontBBox[-157 -250 1126 952]/FontFamily(Myriad Pro)/FontFile3 19 0 R/FontName/GSWOXJ+MyriadPro-Regular/FontStretch/Normal/FontWeight 400/ItalicAngle 0/StemV 88/Type/FontDescriptor/XHeight 484>> endobj 19 0 obj <</Filter/FlateDecode/Length 3217/Subtype/Type1C>>stream
H‰|”iTÔXÇBP&£ä¤ÔÊ<C394>ÔàNÛ*ˆ-Š8¨(
Š´à´"R¥”,nMUà±m<15>Á}GFEeQ¤Jiul@d\èVgæxƒ¯<3)úKš“œûÞÿ޼߽¹//8æêá8>bvìèø¹ŸÍ_¯×&©côéŸ/Ò¬ÎÑ%é<>AQòÂ¥á®àÁ!?TôñãÇ(l¿—\‡^üÃï´ž˜+ŽSî]oW%®JÔÊ÷Ìô ™²zM¶Ê/$ÄœÓØàq*ÿ‰'Ø@Õ uúJ<C3BA>*v}V¶fm*2-9]Ÿ®OÊ֨ǫfètªDJ¯ÉÒè N篵©´Y*<2A>6{<7B>F¯Jƒ«µòz½F­ÊÖ'©5k“ô©ªtgä7rÕÿI¥Ò¦©d*.MëT±Ù²3K•”¦ž SÒ²$§ç¤e뵚¬ñfÅ.^Ÿ¡QMV©5«0 —/ŒÂ°!Æa˜†‰6Ã|1l†ùaX†…»aQ$K` 8ˆáßà˜<C3A0>Ünl>ƒ¸¾7ã-.¬KˆKK ¡$tÄ÷Dk¸ë×ÿ<C397>ÉäeR¢
¨fÚ…¥cèF·!nÜêÝi÷eîî¯M´{PÇ`Íà㋠륾z\¶£ê‰BW© ?ÆQ@AºÉ¡ið- /)¤B 8…cí –Ìa5%]åœ3äT zÃ@þ¶†Õ8Úp¸t ž'í0Õn6µ±FˆîËý9)Döª ³Øç¶ñ϶€—茉¶O
¾äENu>”9áb]S‡U<E280A1>£í'î]ØDc­ã¿œäÙHÆRÏO<C38F>¤4[ò`s2<73>b€Ùñ+3QfÆüY1ÀŒKmê°8Yí'e&ƒÖôÏÈÅÍðhNæàL¿œM¡ÓŸ´$clδàUÝPÞMÀ~¹v4üsä<73>ÒD”j}ŽËèv` C<E28099>A^âŽÙ\oµ7
DSVxû}±ä „BÄõWODæ€Aº×^˜ë ÆNöo`Ttö akCÞÓËæÙHZ)¦°UÚÛŠƒÔMH+­¨ÆJ_­ †wõ<77>‡òe̤
—®Y.ŸO9YwòßwzA¤hŒ¦ ÿYs†ÇÑrˆ°ÁÃN|h;i”"zm%ßq4ºä Â5A#-˜9+ <01>Y~²ôxŹE”IkÖj•h-ÍT0àÍ­D3lå$5ÚJÚhñ¤•œƒ¬œÎ<C593>§¤vB:W8‡<>³hI@ñ¤‰v8Y9<59> ÛíÒ%þ¸KÜK<¶r;._-¸ÃðW65‰Mw*_€ð5ÿˆ¾&\‹ñ?<3F>†ò³¢¶oýRìšÇí<TY\ÃCÔ1(À,¢¹cF¢ÚTKqŽÀôn{évØÕªËõ¬ú§äÑÉöIÏá‡ôà…Qù¹ê­xä7êL‡ÐïarKͦ¯«D¶íÀ’í+I[PÊ#<12>Zf½«ünÆ
QÍÏ2ßó½O•œ™5Þ Ýý oÛãvxÝÎ~þ
¨¦Y¸šÚvt
EÊðšiWÂF@
zMv÷O
Ag)¶ÌÛò­Ÿ`2§ÚÔžŽ@:xEŽû4‰b²åÝ)³Ã g3`{ñXч¨‡ÍGùÎGGêþ.Vž-¯mTÞΩ[uZ¨JŽªâ#$vEqÅûO<14>ãß4­ð?/Þ;-˺s<C2BA>È,FCå£+a® RA=̈́怒°˜{žg»!©“Í“BÛϘª/*!’î[ýù.X¸!3Y¨XH¬¼RRÃÿ²gf²˜O£hËÈyÈ]ÉÖEÔÏúÙvµòÜ1¡ˆbóv- 7A0ÇÖm1ålVnLNŽâ—kŽÝx“È”íƒj‡Ô\ÏÖ.¨êfó`´­+þ‰,¢æU]ϰó€þfˆàc™ôyð¡±kât¢ n:Úå+LKM)B/Tr%E{­ß ÷˯Wßæ_ÕOþ“ÈÖ!bqØ„yñ7¦ïL{ö(U¾]Âìø¹BòyÆõ)øÏfÚÀõÝív jÏ7+ZȽYËö-áÿh„¡±È÷µ/Œ¹÷}éÞC"³Ûø@m<>¦ÙœŸë<C5B8>Ýl<C39D>äÓ¿”CMôùœ„³3x4ÈÇYDäóÂÜŸÞªþá˜`•+-&ŸRgÌu—”R;à(æ6š7lغȯãÔ1ü¸¿´ýüᇟzk—Å–<£‰Ëo<C38B>©M0² ?÷ ötÒJ0pÝÖreOˆÈý1Ñh Ó3Æ>i(-9%ä5S4Æ(>`z 6‰&®q×ùöþ—Ã<E28094>±fA¥ò%è>Ly€·wª<>Àý>r?Jÿø×æGGÊwlß'ìm!wmÈØ¥ãW&nJMWªóæÏVfÏžÓ⢙b¤±<C2A4>÷}è·šp¤m“ü¤uÛ÷M8i¢.]æ¡<1A>&#åóÑàñèjUÍ1ÑG!&ò+¿è„òŠT!g™yþîÆ|cKÉå+â•‹[€PB%Ͷݲž·ž&¢S\žiÃŽ<!vÝRmœÜ §¯E¶\o?xv÷RR|©P¼Ù²)OÉÊï3¥UÞ¼µŒÝD«¢j¨2˾<C38B>{…ÚÒš 7øŽ‘¡":Õ-Ÿ@øbä…¹)ºü¼L!#/'g£ÞÍ×(ý(SÖå¾Üóàc»Ù—¤<>Ö8ÖÑì»ËýÁ\jvníÁ¬Sg>iO§LÐÀ0Ë™åNÊßAà§¥]ÿc²lcÚªÂ8Rï½cÃfá®zͽALfC ™°•14Ã<> d@€R Û
åµP åEhâ:ni<6E>e€"ã½ÂË✀£Œ·d)<29>B•„ÌSröÁsQ?<3F>OçÿüŸÎó;ÆG'€bã—ý Äbn8|ŠŠ
r•®To¹%÷ †³Ìù=ˆA@7-£PW¬ Í
R­äó•׬¨ƒÖP§§GG¾¥æ{"ü)ÂXc¬ei³a oZê‰ðd`‡ôÀ×cøj\Š2GJçÊs 3Žiðïr£¯P¢xq\£ÆÉñÊu̯IªDåÇ•åâ#׸üF¸šµõô¸atè1Ê/å×møè>ˆ<C5A0>Ë¢589Zñ »t¤ó…Êb?nAÃÆ~á<>¯íe(tó€ïÃs{gÁiàN®ƒ@ðÖ¹=È0š+‚ý!÷ Ð!Ä×ûüµg/¶GßG<€å‚Ð;oQu„ÝF-Ûõ(ý ðVð!8ãõ'tô ¿vƒA6žWn`¾¸6Ný±p+NÀÖèkêir×ÒøÈ<MíLú¼ y—=C¢†gŒ¦^Ãê…|(G]¿»¡Êëä*3+¨õ¨é-K[رYŠÕUit ©ß ÈmYyu % Îa*q²Ký_|uL8Rò*™ãú~ø3Úy=ãÅ)@X¦7—ÅÃÞÝLˆIÚ4(ìíújjô<6A>BÙL·>ÁŒâ†Ê=äê¥O†b·R™¹¬öìDaRZÊÕ„¸¦FÚ,²K˜wرòvì»xÌ?èGØH„ëÄí2:«å›â!ª§£îËF¦Ò©Uêl*¦  Ày:†àWªV$Üót^´<>B9jÏD#ê'p…ZQQL¦<7F>HÂ(Qúì6Z¼`/ý~M\µNN´×ùb븺¿jdBÈçð<C3A7>;ܱ‡òŒHøÀèoc»ø"phêj¼oìrÕâ<C395>RcFsútpù Gû_ ¸Š1<ðM…L©<E28098>ºªqEGa{~GÀ¾ ßÓÓÙcy:N/ðe8V«ÒW+Ôå•¥t^|Ú­,¹,GZ”SÞú<C39E>Kk­Ù`2oþ.ð‡‹'~ö)o$—JÑ0•u)ûUÝn`À…?’æ[,ÎãßÛONŸFG²`ZÛÚÞKõöåf<C3A5>1d_ÊB¯r<C2AF>š}<^©`BñO«
¤7¨ää&Óu†ÜëJÑ'R×ÏÔ2| ÿ“ï-„.¥Þsþi ˆm ÒF>=ˆ<<10>«M²h}_¿ìO12(n&Èíá;#¦û´Ñpïn'ÕÖVZf`ȧ¦9ŒÜÖåßb?§"ó¥éL¢DvM˜Ó-Ä^ñËó6tDr‡>0äêZçÜÎ`¯²¨•æ§üÖ êˆ×QÜU9ì1ks;æþâº}kÊŒjˆGžü=ý‡k%k—³À“eYÃdv<64>I“ãm§óÇm'lµN¯ÚïžBÛø? ¥{D endstream endobj 15 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 7 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 20 0 obj <</CreationDate(D:20140924184219+02'00')/Creator(Adobe Illustrator CC 2014 \(Macintosh\))/ModDate(D:20140924184219+02'00')/Producer(Adobe PDF library 11.00)/Title(Deelnemers icon)>> endobj xref 0 21 0000000000 65535 f
0000000016 00000 n
0000000076 00000 n
0000037845 00000 n
0000000000 00000 f
0000037896 00000 n
0000038160 00000 n
0000045026 00000 n
0000039596 00000 n
0000039721 00000 n
0000039859 00000 n
0000038877 00000 n
0000039035 00000 n
0000039083 00000 n
0000039994 00000 n
0000044913 00000 n
0000040697 00000 n
0000041118 00000 n
0000041208 00000 n
0000041611 00000 n
0000045138 00000 n
trailer <</Size 21/Root 1 0 R/Info 20 0 R/ID[<89C9740A517742869FF9D8513D45F8AA><5F6C7E3885ED4FC6805EBDB0C5BA9BBB>]>> startxref 45336 %%EOF

View File

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "user_icon_selected.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,666 +0,0 @@
%PDF-1.4 %âãÏÓ
1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 37701/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c011 79.156289, 2014/03/31-23:39:12 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/"
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/"
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Deelnemers icon selected</rdf:li>
</rdf:Alt>
</dc:title>
<xmp:CreatorTool>Adobe Illustrator CC 2014 (Macintosh)</xmp:CreatorTool>
<xmp:CreateDate>2014-09-24T18:42:19+02:00</xmp:CreateDate>
<xmp:ModifyDate>2014-09-24T18:42:19+02:00</xmp:ModifyDate>
<xmp:MetadataDate>2014-09-24T18:42:19+02:00</xmp:MetadataDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>40</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAKAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A6J5d8ueefLXnm0Edin1G&#xA;ZIIr65gieeCcNFBDM5n9RZI2DRNJR4ePLf8A3a7Iqi/zv8r+dbu3fWfK+nQatfQLbRwWzuwmQA3K&#xA;TsiExoRwuEI+KvNQ1KqMVT31POmr/lPay6rpxHmSWGB9U0m3IjaT05lM8Kmc8avGpqrEq32d1NcV&#xA;QH5S6VqFrdXUo0+bTbEQqkyyJcQxzXDJD9iO7jhnJidJqyMtCJFVWZUARV5r+a35T+fde88eatRg&#xA;g+s39yNNfyTqXqXamz9Ap9YSJ4FMEBJBqZiP5h1JxV6j+cNj52b8vof0DbjWNXspIpb2zCrS6RYX&#xA;R6RsGVqSssgWn7O29MVS/wD5x403zvZ+U5X80WDaSHMUdjp0tBKFhQo08gABDy/Dy5fEzAsdzUqs&#xA;Mk/JjX387XHmUahfJ5wOtfWraX0XNuLL6zQN9d+wIhas1beu9OHHvir2zzxp/mfUfKmo2Xle/TTN&#xA;fmjC2F9KKpG/NSSfgk6qCPsnFUT5Zs9es9BsrbX9QTVdZijpe6hFCLdJXqTURKSFoKDbr1oOmKpn&#xA;irEvzQ0nzZqnlZrTyvcSW2pmZG9SGY27+mA1aSBk/aKmnIVxVNvKNrq1p5Z0y21d2k1OG3RLt3kM&#xA;zGQDflISS5964qhdP07znH501S+vdUgm8rTwRR6XpaRcZoZkoZJHkp8XIlu/SmKpJ530DUr/AM16&#xA;ZdL5ct/M2lrY3UE1vqEsCW1tO0kTRSIkqyktKodXPpmiqKEbhlU60Ly/qGmeR10V5yt5HbTRxNaM&#xA;x9D1C7RQ2zzmpW3VljiZ6bKCadMVeOf846fkT+YPkXzRf6/5k1CBYb21ML2EE0k7yzSOsnqTEqqV&#xA;TidwWNSe3VV6r5x8rJqGopftotvrpeJLdLe4ZYvRkjaRlkZm+1A/rMs6AMSAPgfcYqpea/y6Osfl&#xA;Pc+RLa9Nu7afFY295RgOduE4FlBYhGaMBlBPwmmKsQ/5xu/KXzT5D0vWLzzTderrGsywq1sJfXWK&#xA;GzDpExkqQzOH+hQveoCqfxeSNVuPNT6rJaLbyxXjumpSTKZHhF4s6usaCQ8/RX6unJl/dkhtqJir&#xA;0XFWJLqOs+apWGiXR0zy4jFTrMao9zeFSQwsxIGSOEEU9dlYv+wAKSFVExflz5JHx3WkQalcHZrv&#xA;UwdQuD41mujNJT2rTFXS/lz5L+3Z6VDpVwN1u9Lrp84Pb95amJmH+S1R4jFVD9K6z5ZuoodeuP0h&#xA;oNw4ig1wosc1tI5CpHfLGFjKOxos6KoBorqPtFVleKsX/MX8xfLnkHy3NruuS0jX4LW1SnrXExFV&#xA;iiU9+5PQDc4q+I/zF/5yK/MnzpdSqdQk0fR2JEWlWEjRJwrsJZV4ySnx5Hj4KMVeYs7s5kZizseT&#xA;MTUknepOKvQPIP57/mV5JuYzp+rS3mnKR6mlXzNcWzKOyhjyi+cZXFX23+U35s+XfzJ8u/pPTP8A&#xA;R7634pqemOwaS3kYGm9BzR6Hg9N/YggKs3xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxVjXnZpbuGw8uwu0ba9cG2upEJV0soo2muiCNx6kaegGG6mQEdMVRGo+ZNN0e9tNFtrG&#xA;5urp4DLDZWEAZYreIiMMxJjijWpCqOVT2GxxVAG480a5dySCS68q6LZggyulo15cyEVJpMt1DFAg&#xA;PWnN2/lVfjVbFz5p0K9USm680aNeCsVzGlqt5bSBa0dYhawyQSAfCyjkrbHkGBVVG2GvaV5gl1HQ&#xA;rqxuIJo4F+u6ffw8BJbXQdAykF45Ebg6tRjToaYqp+SZ7iOyvNEunaW40C5NgJnYs8lv6aTWsjM2&#xA;7N9XmRXY9XVsVfF3/OUnn268z/mhfacspOleXGbT7SEH4RMlBdPT+Yyrx+SjFUg0D8gPzd12ysr/&#xA;AE/y7MbDUAj211K8MSmNz8MhDurhab149Nxir6FsP+cMvIa6BHZX+sXjeZmtyZLqF4xAJj+0luyc&#xA;2jVtt2BPtXZV4Prv/ONn5x6TNej9ASXtrZFz9ctZIpEljSp5xpy9VuQ3C8OXalcVQX5D+frnyV+Z&#xA;ek6gJOOn3kq2GqITRWtrhgpZv+MTUkH+rir9EsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVY3qPIfmHoLNT0jpeqoKjf1TPp7LQ9AeCyYqtubOK8863ltM0ixy6TAGaCWSCQf6&#xA;TKfhlhZJF/2LDFUg/MPVNIsfN3l+PzPaNdeW5kkWAOjTWyXvVZJoQr+q6qqiIUPHk7/sllVb/LTU&#xA;9NvvMfmYeXbQ2nlaFoEgCK0Vu95RjcSQwlUMLNUCRKUNFk6uaqp/p9pDZ+dGtYOXowaPbRx+o7yt&#xA;xW4lA5PIWdjTuxJxVfo1D508yFacBHYI9BT94I5Wap7ngyYq/Oz8wUnTz75lS4/3oXVb0TbEfGLh&#xA;+Wx3G+Kv0O/LuzhHk3y5eBpfWfRrCIqZZTFxWBGqIS3pBt/tBeXauKvK7TzN5DHkm4PmHSn/AMcp&#xA;MI9Sf0pDqH6SLACaK9WNjG8fKqKrfBT00qOPJV7No1peXGl6Nd6yGXWbe2ja6VJGWMXEkIWfkiN6&#xA;b/FWnIGnbFX5hRiRpFEYJkJAQLXkWrtSnfFX6pYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYqx3zpa3gtLPWrCFri+0K4F6ltGCXmgMbw3UKAfadoJXaNe8gX54qoz6ff6rqNl5&#xA;o8s61bRW91ZCFlntTeW88LN6sMqGOa1dGXk37RBB6VGKr7nR/Ot3A0F1qejTwP8Abil0id0PfdW1&#xA;Ag4q3b6T52toEgttU0eCCMUSKPSZ0RR1oFXUABiqnBZ3mh3Wq+afM+sQTxJaRxAW9q1rDBBAXkY8&#xA;WmupJJHaT+bsAFr1VRHkuxvYtOudS1CJrfUtbuX1G7t3+1CHVYoIWptyitookem3IE4q+Ov+csPy&#xA;6uvLn5iTeYIIj+h/MhNzHIoPFLoAC4jY+LN+8Hjy9jiqJ8t/85g+f9E0DT9HGl6bdpp1vHax3Eqz&#xA;K7pEoROQSRVrxAGwxVEv/wA5jebHvVvn8r6G16gol0YpjKB4B/U5d/HFVS6/5zV/MWW2lih0jS7e&#xA;Z0ZY7hVnYxsRQOFaUqSvXcUxVhX/ADjr+XV150/MnTw0RbR9Hkjv9VlIPDhE3KKInxlkULT+Xke2&#xA;Kv0ExV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KsWm0PWdCu577yyI7ix&#xA;uHaa88vzP6aGV2LyTWcp5CGRyxLxsPTdt6oSzMqqDz9pESsNTtNR0qaMEyR3VlcFFA60uIFmtn/2&#xA;EpxVzefdLlCrpdlqOrTvT047aynRDXxuLlYLZf8AZSjFVtroWsavfw6l5m9KOC1YS6foMDGSGOVT&#xA;VJ7mUhfXlTqgChEO45MFcKsnxVJPOXk3y/5x8v3Oga/bC50+5AJAPF43XdJI3G6up6H6DUEjFXxr&#xA;+Yv/ADif+Ynly6ln8vwnzJo9S0clsALpFrssluTyY+8fKvt0xV5e/wCX3n1J/q7+WtVW43/cmyuA&#xA;+xofh4V2OKvQvIP/ADi3+aHme5ifUbJvLmlkj1bvUFKTBe/C1JEpb/W4j3xV9mfl3+XXlryD5di0&#xA;TQYSsYPO6upKGa4lpQySsAKnwA2A2GKv/9k=</xmpGImg:image>
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:OriginalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</xmpMM:OriginalDocumentID>
<xmpMM:DocumentID>xmp.did:0384652a-a743-48fb-95be-e83b3a760bd7</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:530ae1f5-93a0-f44a-8295-78f0e7976ee3</xmpMM:InstanceID>
<xmpMM:DerivedFrom rdf:parseType="Resource">
<stRef:instanceID>uuid:f9f8ddc6-5d6d-944b-a129-52a52fb086b9</stRef:instanceID>
<stRef:documentID>xmp.did:cfe4c0cb-aa94-4b90-b875-386c79ddd292</stRef:documentID>
<stRef:originalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</stRef:originalDocumentID>
<stRef:renditionClass>proof:pdf</stRef:renditionClass>
</xmpMM:DerivedFrom>
<xmpMM:History>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:a14d73b1-4718-4821-9702-88ea339373cf</stEvt:instanceID>
<stEvt:when>2014-09-24T13:45:07+02:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CC 2014 (Macintosh)</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:0384652a-a743-48fb-95be-e83b3a760bd7</stEvt:instanceID>
<stEvt:when>2014-09-24T18:42:19+02:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CC 2014 (Macintosh)</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
</rdf:Seq>
</xmpMM:History>
<illustrator:StartupProfile>Web</illustrator:StartupProfile>
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>25.000000</stDim:w>
<stDim:h>25.000000</stDim:h>
<stDim:unit>Pixels</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>Wit</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>Zwart</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-rood</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-geel</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-groen</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-cyaan</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>255</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-blauw</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>RGB-magenta</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>255</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>193</xmpG:red>
<xmpG:green>39</xmpG:green>
<xmpG:blue>45</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>237</xmpG:red>
<xmpG:green>28</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>241</xmpG:red>
<xmpG:green>90</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>247</xmpG:red>
<xmpG:green>147</xmpG:green>
<xmpG:blue>30</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>251</xmpG:red>
<xmpG:green>176</xmpG:green>
<xmpG:blue>59</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>252</xmpG:red>
<xmpG:green>238</xmpG:green>
<xmpG:blue>33</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>217</xmpG:red>
<xmpG:green>224</xmpG:green>
<xmpG:blue>33</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>140</xmpG:red>
<xmpG:green>198</xmpG:green>
<xmpG:blue>63</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>57</xmpG:red>
<xmpG:green>181</xmpG:green>
<xmpG:blue>74</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>146</xmpG:green>
<xmpG:blue>69</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>104</xmpG:green>
<xmpG:blue>55</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>34</xmpG:red>
<xmpG:green>181</xmpG:green>
<xmpG:blue>115</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>169</xmpG:green>
<xmpG:blue>157</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>41</xmpG:red>
<xmpG:green>171</xmpG:green>
<xmpG:blue>226</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>113</xmpG:green>
<xmpG:blue>188</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>46</xmpG:red>
<xmpG:green>49</xmpG:green>
<xmpG:blue>146</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>27</xmpG:red>
<xmpG:green>20</xmpG:green>
<xmpG:blue>100</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>102</xmpG:red>
<xmpG:green>45</xmpG:green>
<xmpG:blue>145</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>147</xmpG:red>
<xmpG:green>39</xmpG:green>
<xmpG:blue>143</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>158</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>93</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>212</xmpG:red>
<xmpG:green>20</xmpG:green>
<xmpG:blue>90</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>237</xmpG:red>
<xmpG:green>30</xmpG:green>
<xmpG:blue>121</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>199</xmpG:red>
<xmpG:green>178</xmpG:green>
<xmpG:blue>153</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>153</xmpG:red>
<xmpG:green>134</xmpG:green>
<xmpG:blue>117</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>115</xmpG:red>
<xmpG:green>99</xmpG:green>
<xmpG:blue>87</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>83</xmpG:red>
<xmpG:green>71</xmpG:green>
<xmpG:blue>65</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>198</xmpG:red>
<xmpG:green>156</xmpG:green>
<xmpG:blue>109</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>166</xmpG:red>
<xmpG:green>124</xmpG:green>
<xmpG:blue>82</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>140</xmpG:red>
<xmpG:green>98</xmpG:green>
<xmpG:blue>57</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>117</xmpG:red>
<xmpG:green>76</xmpG:green>
<xmpG:blue>36</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>96</xmpG:red>
<xmpG:green>56</xmpG:green>
<xmpG:blue>19</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>66</xmpG:red>
<xmpG:green>33</xmpG:green>
<xmpG:blue>11</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Grijswaarden</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>0</xmpG:red>
<xmpG:green>0</xmpG:green>
<xmpG:blue>0</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>26</xmpG:red>
<xmpG:green>26</xmpG:green>
<xmpG:blue>26</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>51</xmpG:red>
<xmpG:green>51</xmpG:green>
<xmpG:blue>51</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>77</xmpG:red>
<xmpG:green>77</xmpG:green>
<xmpG:blue>77</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>102</xmpG:red>
<xmpG:green>102</xmpG:green>
<xmpG:blue>102</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>128</xmpG:red>
<xmpG:green>128</xmpG:green>
<xmpG:blue>128</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>153</xmpG:red>
<xmpG:green>153</xmpG:green>
<xmpG:blue>153</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>179</xmpG:red>
<xmpG:green>179</xmpG:green>
<xmpG:blue>179</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>204</xmpG:red>
<xmpG:green>204</xmpG:green>
<xmpG:blue>204</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>230</xmpG:red>
<xmpG:green>230</xmpG:green>
<xmpG:blue>230</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>242</xmpG:red>
<xmpG:green>242</xmpG:green>
<xmpG:blue>242</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Kleurgroep voor web</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=63 G=169 B=245</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>63</xmpG:red>
<xmpG:green>169</xmpG:green>
<xmpG:blue>245</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=122 G=201 B=67</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>122</xmpG:red>
<xmpG:green>201</xmpG:green>
<xmpG:blue>67</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=147 B=30</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>147</xmpG:green>
<xmpG:blue>30</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=29 B=37</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>29</xmpG:green>
<xmpG:blue>37</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=255 G=123 B=172</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>255</xmpG:red>
<xmpG:green>123</xmpG:green>
<xmpG:blue>172</xmpG:blue>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>R=189 G=204 B=212</xmpG:swatchName>
<xmpG:mode>RGB</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:red>189</xmpG:red>
<xmpG:green>204</xmpG:green>
<xmpG:blue>212</xmpG:blue>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
<pdf:Producer>Adobe PDF library 11.00</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[0.0 0.0 25.0 25.0]/BleedBox[0.0 0.0 25.0 25.0]/Contents 6 0 R/MediaBox[0.0 0.0 25.0 25.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0 8 0 R/MC1 9 0 R/MC2 10 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 25.0 25.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 389>>stream
H‰\R9NA ÌûþÀxÚí>C.!$1Á&  ¿§ìYÍÕå)_eÏ·O_Ïšï."<22>_^PxR±{Âsx<0E>ô“]‡]˜¯"í>Â;‰›„$qÁgyuÒk˜”%§Ê±à§”iêœZ!å•–E)sŒ<73>¦ÆE@ŽÍ¼F1PÆ0bâ$B•¥ÑÞPŒ()Ü„{­Yu fwì…<C3AC>4‰ùl€Yœ:»s<C2BB> ¥)@­î§<$ÑàÜQsa<73>hPUN(³¢P<>¸qŠbqzª$ƒ­uÿ,acûCþé7MjPh@С¶ºÖACÙÞCé ¢öfíåXýœ­UQgýèPѸ¡æIW<49>ÒmD] ^<5E>ïf³ÏÂbFˆ<46>!‰ÇGŸù€UaZ1nÅ€× Yly²mAå>ÔÎÓº <20>—gp_ÇÞý¿-ŽxUG¼!m<>·QO¹<ù^Â}¸ºÃ.ϧåu¹ç³ýçÙM7KZ-Îó×}ø`V&q endstream endobj 11 0 obj <</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 3/Length 20/Width 3>>stream
8;Ue`J-(6$!rr<-!!*~> endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 8 0 obj <</Color[20224 32768 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Laag 1)/Visible true>> endobj 9 0 obj <</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed false/Title(nyt_exporter_info)/Visible false>> endobj 10 0 obj <</AIType/HiddenLayer/Contents 14 0 R/Resources<</ExtGState<</GS0 15 0 R>>/Font<</T1_0 16 0 R>>/ProcSet[/PDF/Text]>>>> endobj 14 0 obj <</Length 654>>stream
q
0 25 25 -25 re
W n
BT
0 0 0 rg
/GS0 gs
/T1_0 1 Tf
12 0 0 12 -129 25 Tm
[(<n)13(yt_pr)10(ef)9.1(s>)]TJ
0 -1.2 TD
[( <n)13(yt_pr)10(e\037x/>)]TJ
0 -1.2 TD
[( <n)13(yt_su\036x/>)]TJ
0 -1.2 TD
[( <n)13(yt_base_pa)4(th>~/D)-4(eskt)6(op</n)13(yt_base_pa)4(th>)]TJ
0 -1.2 TD
[( <n)13(yt_scaling>100%</n)12.9(yt_scaling>)]TJ
0 -1.2 TD
[( <n)13(yt_tr)5.1(anspar)9.9(enc)-18(y>true</n)13(yt_tr)5(anspar)10(enc)-18(y>)]TJ
T*
[( <n)13(yt_f)12.9(or)-3.9(ma)3.9(t>PNG 24</n)13(yt_f)13(or)-3.9(ma)4.1(t>)]TJ
0 -1.2 TD
[( <n)13(yt_e)2.9(xpor)-24(t_c)6(ode>ar)-24(tboar)10(ds</n)13(yt_e)3(xpor)-24(t_c)5.9(ode>)]TJ
0 -1.2 TD
[(</n)13(yt_pr)10(ef)8.9(s>)]TJ
ET
Q
endstream endobj 16 0 obj <</BaseFont/GSWOXJ+MyriadPro-Regular/Encoding 17 0 R/FirstChar 30/FontDescriptor 18 0 R/LastChar 126/Subtype/Type1/Type/Font/Widths[815 523 212 0 0 0 0 792 0 0 0 0 0 0 0 0 0 343 513 513 513 0 513 0 0 0 0 0 0 0 596 0 596 0 0 0 0 0 666 0 0 646 0 0 0 0 0 0 658 0 532 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 0 482 569 448 564 501 292 559 555 234 0 469 236 834 555 549 569 0 327 396 331 551 0 0 463 471 0 0 0 0 596]>> endobj 17 0 obj <</BaseEncoding/WinAnsiEncoding/Differences[30/f_f_i/f_i]/Type/Encoding>> endobj 18 0 obj <</Ascent 952/CapHeight 674/CharSet(/f_f_i/f_i/space/percent/slash/zero/one/two/four/less/greater/D/G/N/P/underscore/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/r/s/t/u/x/y/asciitilde)/Descent -250/Flags 32/FontBBox[-157 -250 1126 952]/FontFamily(Myriad Pro)/FontFile3 19 0 R/FontName/GSWOXJ+MyriadPro-Regular/FontStretch/Normal/FontWeight 400/ItalicAngle 0/StemV 88/Type/FontDescriptor/XHeight 484>> endobj 19 0 obj <</Filter/FlateDecode/Length 3217/Subtype/Type1C>>stream
H‰|”iTÔXÇBP&£ä¤ÔÊ<C394>ÔàNÛ*ˆ-Š8¨(
Š´à´"R¥”,nMUà±m<15>Á}GFEeQ¤Jiul@d\èVgæxƒ¯<3)úKš“œûÞÿ޼߽¹//8æêá8>bvìèø¹ŸÍ_¯×&©côéŸ/Ò¬ÎÑ%é<>AQòÂ¥á®àÁ!?TôñãÇ(l¿—\‡^üÃï´ž˜+ŽSî]oW%®JÔÊ÷Ìô ™²zM¶Ê/$ÄœÓØàq*ÿ‰'Ø@Õ uúJ<C3BA>*v}V¶fm*2-9]Ÿ®OÊ֨ǫfètªDJ¯ÉÒè N篵©´Y*<2A>6{<7B>F¯Jƒ«µòz½F­ÊÖ'©5k“ô©ªtgä7rÕÿI¥Ò¦©d*.MëT±Ù²3K•”¦ž SÒ²$§ç¤e뵚¬ñfÅ.^Ÿ¡QMV©5«0 —/ŒÂ°!Æa˜†‰6Ã|1l†ùaX†…»aQ$K` 8ˆáßà˜<C3A0>Ünl>ƒ¸¾7ã-.¬KˆKK ¡$tÄ÷Dk¸ë×ÿ<C397>ÉäeR¢
¨fÚ…¥cèF·!nÜêÝi÷eîî¯M´{PÇ`Íà㋠륾z\¶£ê‰BW© ?ÆQ@AºÉ¡ið- /)¤B 8…cí –Ìa5%]åœ3äT zÃ@þ¶†Õ8Úp¸t ž'í0Õn6µ±FˆîËý9)Döª ³Øç¶ñ϶€—茉¶O
¾äENu>”9áb]S‡U<E280A1>£í'î]ØDc­ã¿œäÙHÆRÏO<C38F>¤4[ò`s2<73>b€Ùñ+3QfÆüY1ÀŒKmê°8Yí'e&ƒÖôÏÈÅÍðhNæàL¿œM¡ÓŸ´$clδàUÝPÞMÀ~¹v4üsä<73>ÒD”j}ŽËèv` C<E28099>A^âŽÙ\oµ7
DSVxû}±ä „BÄõWODæ€Aº×^˜ë ÆNöo`Ttö akCÞÓËæÙHZ)¦°UÚÛŠƒÔMH+­¨ÆJ_­ †wõ<77>‡òe̤
—®Y.ŸO9YwòßwzA¤hŒ¦ ÿYs†ÇÑrˆ°ÁÃN|h;i”"zm%ßq4ºä Â5A#-˜9+ <01>Y~²ôxŹE”IkÖj•h-ÍT0àÍ­D3lå$5ÚJÚhñ¤•œƒ¬œÎ<C593>§¤vB:W8‡<>³hI@ñ¤‰v8Y9<59> ÛíÒ%þ¸KÜK<¶r;._-¸ÃðW65‰Mw*_€ð5ÿˆ¾&\‹ñ?<3F>†ò³¢¶oýRìšÇí<TY\ÃCÔ1(À,¢¹cF¢ÚTKqŽÀôn{évØÕªËõ¬ú§äÑÉöIÏá‡ôà…Qù¹ê­xä7êL‡ÐïarKͦ¯«D¶íÀ’í+I[PÊ#<12>Zf½«ünÆ
QÍÏ2ßó½O•œ™5Þ Ýý oÛãvxÝÎ~þ
¨¦Y¸šÚvt
EÊðšiWÂF@
zMv÷O
Ag)¶ÌÛò­Ÿ`2§ÚÔžŽ@:xEŽû4‰b²åÝ)³Ã g3`{ñXч¨‡ÍGùÎGGêþ.Vž-¯mTÞΩ[uZ¨JŽªâ#$vEqÅûO<14>ãß4­ð?/Þ;-˺s<C2BA>È,FCå£+a® RA=̈́怒°˜{žg»!©“Í“BÛϘª/*!’î[ýù.X¸!3Y¨XH¬¼RRÃÿ²gf²˜O£hËÈyÈ]ÉÖEÔÏúÙvµòÜ1¡ˆbóv- 7A0ÇÖm1ålVnLNŽâ—kŽÝx“È”íƒj‡Ô\ÏÖ.¨êfó`´­+þ‰,¢æU]ϰó€þfˆàc™ôyð¡±kât¢ n:Úå+LKM)B/Tr%E{­ß ÷˯Wßæ_ÕOþ“ÈÖ!bqØ„yñ7¦ïL{ö(U¾]Âìø¹BòyÆõ)øÏfÚÀõÝív jÏ7+ZȽYËö-áÿh„¡±È÷µ/Œ¹÷}éÞC"³Ûø@m<>¦ÙœŸë<C5B8>Ýl<C39D>äÓ¿”CMôùœ„³3x4ÈÇYDäóÂÜŸÞªþá˜`•+-&ŸRgÌu—”R;à(æ6š7lغȯãÔ1ü¸¿´ýüᇟzk—Å–<£‰Ëo<C38B>©M0² ?÷ ötÒJ0pÝÖreOˆÈý1Ñh Ó3Æ>i(-9%ä5S4Æ(>`z 6‰&®q×ùöþ—Ã<E28094>±fA¥ò%è>Ly€·wª<>Àý>r?Jÿø×æGGÊwlß'ìm!wmÈØ¥ãW&nJMWªóæÏVfÏžÓ⢙b¤±<C2A4>÷}è·šp¤m“ü¤uÛ÷M8i¢.]æ¡<1A>&#åóÑàñèjUÍ1ÑG!&ò+¿è„òŠT!g™yþîÆ|cKÉå+â•‹[€PB%Ͷݲž·ž&¢S\žiÃŽ<!vÝRmœÜ §¯E¶\o?xv÷RR|©P¼Ù²)OÉÊï3¥UÞ¼µŒÝD«¢j¨2˾<C38B>{…ÚÒš 7øŽ‘¡":Õ-Ÿ@øbä…¹)ºü¼L!#/'g£ÞÍ×(ý(SÖå¾Üóàc»Ù—¤<>Ö8ÖÑì»ËýÁ\jvníÁ¬Sg>iO§LÐÀ0Ë™åNÊßAà§¥]ÿc²lcÚªÂ8Rï½cÃfá®zͽALfC ™°•14Ã<> d@€R Û
åµP åEhâ:ni<6E>e€"ã½ÂË✀£Œ·d)<29>B•„ÌSröÁsQ?<3F>OçÿüŸÎó;ÆG'€bã—ý Äbn8|ŠŠ
r•®To¹%÷ †³Ìù=ˆA@7-£PW¬ Í
R­äó•׬¨ƒÖP§§GG¾¥æ{"ü)ÂXc¬ei³a oZê‰ðd`‡ôÀ×cøj\Š2GJçÊs 3Žiðïr£¯P¢xq\£ÆÉñÊu̯IªDåÇ•åâ#׸üF¸šµõô¸atè1Ê/å×møè>ˆ<C5A0>Ë¢589Zñ »t¤ó…Êb?nAÃÆ~á<>¯íe(tó€ïÃs{gÁiàN®ƒ@ðÖ¹=È0š+‚ý!÷ Ð!Ä×ûüµg/¶GßG<€å‚Ð;oQu„ÝF-Ûõ(ý ðVð!8ãõ'tô ¿vƒA6žWn`¾¸6Ný±p+NÀÖèkêir×ÒøÈ<MíLú¼ y—=C¢†gŒ¦^Ãê…|(G]¿»¡Êëä*3+¨õ¨é-K[رYŠÕUit ©ß ÈmYyu % Îa*q²Ký_|uL8Rò*™ãú~ø3Úy=ãÅ)@X¦7—ÅÃÞÝLˆIÚ4(ìíújjô<6A>BÙL·>ÁŒâ†Ê=äê¥O†b·R™¹¬öìDaRZÊÕ„¸¦FÚ,²K˜wرòvì»xÌ?èGØH„ëÄí2:«å›â!ª§£îËF¦Ò©Uêl*¦  Ày:†àWªV$Üót^´<>B9jÏD#ê'p…ZQQL¦<7F>HÂ(Qúì6Z¼`/ý~M\µNN´×ùb븺¿jdBÈçð<C3A7>;ܱ‡òŒHøÀèoc»ø"phêj¼oìrÕâ<C395>RcFsútpù Gû_ ¸Š1<ðM…L©<E28098>ºªqEGa{~GÀ¾ ßÓÓÙcy:N/ðe8V«ÒW+Ôå•¥t^|Ú­,¹,GZ”SÞú<C39E>Kk­Ù`2oþ.ð‡‹'~ö)o$—JÑ0•u)ûUÝn`À…?’æ[,ÎãßÛONŸFG²`ZÛÚÞKõöåf<C3A5>1d_ÊB¯r<C2AF>š}<^©`BñO«
¤7¨ää&Óu†ÜëJÑ'R×ÏÔ2| ÿ“ï-„.¥Þsþi ˆm ÒF>=ˆ<<10>«M²h}_¿ìO12(n&Èíá;#¦û´Ñpïn'ÕÖVZf`ȧ¦9ŒÜÖåßb?§"ó¥éL¢DvM˜Ó-Ä^ñËó6tDr‡>0äêZçÜÎ`¯²¨•æ§üÖ êˆ×QÜU9ì1ks;æþâº}kÊŒjˆGžü=ý‡k%k—³À“eYÃdv<64>I“ãm§óÇm'lµN¯ÚïžBÛø? ¥{D endstream endobj 15 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 7 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 20 0 obj <</CreationDate(D:20140924184219+02'00')/Creator(Adobe Illustrator CC 2014 \(Macintosh\))/ModDate(D:20140924184219+02'00')/Producer(Adobe PDF library 11.00)/Title(Deelnemers icon selected)>> endobj xref 0 21 0000000000 65535 f
0000000016 00000 n
0000000076 00000 n
0000037854 00000 n
0000000000 00000 f
0000037905 00000 n
0000038169 00000 n
0000044776 00000 n
0000039345 00000 n
0000039470 00000 n
0000039608 00000 n
0000038626 00000 n
0000038784 00000 n
0000038832 00000 n
0000039743 00000 n
0000044663 00000 n
0000040447 00000 n
0000040868 00000 n
0000040958 00000 n
0000041361 00000 n
0000044888 00000 n
trailer <</Size 21/Root 1 0 R/Info 20 0 R/ID[<01477929FFB54C388EE03727881FDBFF><27E29341D0F7473583847C9068E927A9>]>> startxref 45095 %%EOF

View File

@ -1,8 +0,0 @@
platform :ios, '9.0'
use_frameworks!
target 'SwiftTodos' do
pod 'SwiftDDP', '~> 0.2.2'
pod 'XCGLogger'
end

View File

@ -1,20 +0,0 @@
PODS:
- CryptoSwift (0.3)
- SwiftDDP (0.2.2):
- CryptoSwift (~> 0.3)
- SwiftWebSocket (~> 2.6.0)
- XCGLogger
- SwiftWebSocket (2.6.0)
- XCGLogger (3.2)
DEPENDENCIES:
- SwiftDDP (~> 0.2.2)
- XCGLogger
SPEC CHECKSUMS:
CryptoSwift: 19d29910d88440fcb132761d9ab57e175f1b0d0e
SwiftDDP: 100a5ab2c7b5263009c65683ae6e6e426df72492
SwiftWebSocket: c24c0dde0b33852f478ffb54226408bfe703b26b
XCGLogger: da1f341f4bb8979db6e1df64232f04d9698402d4
COCOAPODS: 0.39.0

View File

@ -1,10 +0,0 @@
Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
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:
- 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.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.

View File

@ -1,309 +0,0 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Hash](#hash)
- [Cyclic Redundancy Check (CRC)](#cyclic-redundancy-check-crc)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
#CryptoSwift
Crypto related functions and helpers for [Swift](https://developer.apple.com/swift/) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift))
-------
<p align="center">
<a href="#features">Features</a> &bull;
<a href="#contribution">Contribution</a> &bull;
<a href="#installation">Installation</a> &bull;
<a href="#usage">Usage</a> &bull;
<a href="#author">Author</a> &bull;
<a href="#changelog">Changelog</a>
</p>
-------
##Requirements
Good mood
##Features
- Easy to use
- Convenient extensions for String and NSData
- iOS, OSX, AppleTV, watchOS, Linux support
##What implemented?
#### Hash
- [MD5](http://tools.ietf.org/html/rfc1321)
- [SHA1](http://tools.ietf.org/html/rfc3174)
- [SHA224](http://tools.ietf.org/html/rfc6234)
- [SHA256](http://tools.ietf.org/html/rfc6234)
- [SHA384](http://tools.ietf.org/html/rfc6234)
- [SHA512](http://tools.ietf.org/html/rfc6234)
#### Cyclic Redundancy Check (CRC)
- [CRC32](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
- [CRC16](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
#####Cipher
- [AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf)
- [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf)
- [Rabbit](https://tools.ietf.org/html/rfc4503)
#####Message authenticators
- [Poly1305](http://cr.yp.to/mac/poly1305-20050329.pdf)
- [HMAC](https://www.ietf.org/rfc/rfc2104.txt) MD5, SHA1, SHA256
#####Cipher block mode
- Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))
- Cipher-block chaining ([CBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29))
- Propagating Cipher Block Chaining ([PCBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29))
- Cipher feedback ([CFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29))
- Output Feedback ([OFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29))
- Counter ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29))
#####Data padding
- [PKCS#7](http://tools.ietf.org/html/rfc5652#section-6.3)
##Why
[Why?](https://github.com/krzyzanowskim/CryptoSwift/issues/5) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/issues/5#issuecomment-53379391).
##Contribution
For latest version, please check **develop** branch. This is latest development version that will be merged into **master** branch at some point.
- If you want to contribute, submit a [pull request](https://github.com/krzyzanowskim/CryptoSwift/pulls).
- If you found a bug, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
- If you have a feature request, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
##Installation
To install CryptoSwift, add it as a submodule to your project (on the top level project directory):
git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
####Embedded Framework
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)
![](https://cloud.githubusercontent.com/assets/758033/10834511/25a26852-7e9a-11e5-8c01-6cc8f1838459.png)
#####iOS, OSX, watchOS, tvOS
In the project, you'll find three targets, configured for each supported SDK:
- CryptoSwift iOS
- CryptoSwift OSX
- CryptoSwift watchOS
- CryptoSwift tvOS
You may need to choose the one you need to build `CryptoSwift.framework` for your application.
####CryptoSwift.framework
Alternatively, you can build the Universal Framework and link it in your Xcode project. To do that please run `build.sh` script and find resulting frameworks in `Framework` directory.
Looking for version for Swift 1.2? check branch **swift12**, it's there.
####CocoaPods
You can use [CocoaPods](http://cocoapods.org/?q=cryptoSwift).
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'CryptoSwift'
```
or for newest version from specified branch of code:
```ruby
pod 'CryptoSwift', :git => "https://github.com/krzyzanowskim/CryptoSwift", :branch => "master"
```
####Carthage
You can use [Carthage](https://github.com/Carthage/Carthage).
Specify in Cartfile:
```ruby
github "krzyzanowskim/CryptoSwift"
```
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)
####Swift Package Manager
You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
```
.Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0)
```
##Usage
```swift
import CryptoSwift
```
For your convenience you should use extensions methods like encrypt(), decrypt(), md5(), sha1() and so on.
Hashing a data or array of bytes (aka `Array<UInt8>`)
```swift
/* Hash enum usage */
let input:[UInt8] = [49, 50, 51]
let output = input.md5()
// alternatively: let output = CryptoSwift.Hash.md5(input).calculate()
print(output.toHexString())
```
```swift
let data = NSData()
let hash = data.md5()
let hash = data.sha1()
let hash = data.sha224()
let hash = data.sha256()
let hash = data.sha384()
let hash = data.sha512()
let crc32 = data.crc32()
let crc16 = data.crc16()
print(hash.toHexString())
```
Hashing a String and printing result
```swift
let hash = "123".md5()
```
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.
```swift
let paddedData = PKCS7().add(arr, blockSize: AES.blockSize)
```
Working with Ciphers
ChaCha20
```swift
let encrypted: [UInt8] = ChaCha20(key: key, iv: iv).encrypt(message)
let decrypted: [UInt8] = ChaCha20(key: key, iv: iv).decrypt(encrypted)
```
Rabbit
```swift
let encrypted = Rabbit(key: key, iv: iv)?.encrypt(plaintext)
let decrypted = Rabbit(key: key, iv: iv)?.decrypt(encrypted!)
```
AES
Notice regarding padding: *Manual padding of data is optional and CryptoSwift by default always will add PKCS7 padding before encryption, and remove after decryption when __Cipher__ enum is used. If you need manually disable/enable padding, you can do this by setting parameter for encrypt()/decrypt() on class __AES__.*
Basic:
```swift
let input = NSData()
let encrypted = try! input.encrypt(AES(key: "secret0key000000", iv:"0123456789012345"))
let input: [UInt8] = [0,1,2,3,4,5,6,7,8,9]
input.encrypt(AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC))
```
Encrypt/Decrypt String to Base64 encoded string:
```swift
// Encrypt string and get Base64 representation of result
let base64String = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345")).toBase64()
// Decrypt Base64 encrypted message with helper function:
let decrypted = try! encryptedBase64.decryptBase64ToString(AES(key: "secret0key000000", iv: "0123456789012345"))
```
...under the hood, this is [UInt8] converted to NSData converted to Base64 string representation:
```swift
let encryptedBytes: [UInt8] = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345"))
let base64 = NSData(bytes: encryptedBytes).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
```
Advanced:
```swift
let input: [UInt8] = [0,1,2,3,4,5,6,7,8,9]
let key: [UInt8] = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: [UInt8] = AES.randomIV(AES.blockSize)
do {
let encrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).encrypt(input, padding: PKCS7())
let decrypted: [UInt8] = try AES(key: key, iv: iv, blockMode: .CBC).decrypt(encrypted, padding: PKCS7())
} catch AES.Error.BlockSizeExceeded {
// block size exceeded
} catch {
// some error
}
```
AES without data padding
```swift
let input: [UInt8] = [0,1,2,3,4,5,6,7,8,9]
let encrypted: [UInt8] = try! AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC).encrypt(input, padding: nil)
```
Using extensions
```swift
let plain = NSData()
let encrypted: NSData = try! plain.encrypt(ChaCha20(key: key, iv: iv))
let decrypted: NSData = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
// plain == decrypted
```
Message authenticators
```swift
// Calculate Message Authentication Code (MAC) for message
let mac: [UInt8] = try! Authenticator.Poly1305(key: key).authenticate(input)
```
#####Conversion between NSData and [UInt8]
For you convenience CryptoSwift provide two function to easily convert array of bytes to NSData and other way around:
```swift
let data: NSData = NSData(bytes: [0x01, 0x02, 0x03])
let bytes:[UInt8] = data.arrayOfBytes()
```
##Author
CryptoSwift is owned and maintained by Marcin Krzyżanowski. You can follow me on Twitter at [@krzyzanowskim](http://twitter.com/krzyzanowskim) for project updates and releases.
[Marcin Krzyżanowski](http://www.krzyzanowskim.com)
##License
Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
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:
- 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.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.
##Changelog
See [CHANGELOG](./CHANGELOG) file.

View File

@ -1,458 +0,0 @@
//
// AES.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 21/11/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
// Implementation of Gladman algorithm http://www.gladman.me.uk/AES
//
final public class AES {
public enum Error: ErrorType {
case BlockSizeExceeded
case InvalidKeyOrInitializationVector
case InvalidInitializationVector
}
public enum AESVariant:Int {
case aes128 = 1, aes192, aes256
var Nk:Int { // Nk words
return [4,6,8][self.rawValue - 1]
}
var Nb:Int { // Nb words
return 4
}
var Nr:Int { // Nr
return Nk + 6
}
}
public let blockMode:CipherBlockMode
public static let blockSize:Int = 16 // 128 /8
public var variant:AESVariant {
switch (self.key.count * 8) {
case 128:
return .aes128
case 192:
return .aes192
case 256:
return .aes256
default:
preconditionFailure("Unknown AES variant for given key.")
}
}
private let key:[UInt8]
private let iv:[UInt8]?
private lazy var expandedKey:[[UInt32]] = self.expandKey(self.key, variant: self.variant)
private lazy var expandedKeyInv:[[UInt32]] = self.expandKeyInv(self.key, variant: self.variant)
private lazy var sBoxes:(sBox:[UInt32], invSBox:[UInt32]) = self.calculateSBox()
private lazy var sBox:[UInt32] = self.sBoxes.sBox
private lazy var sBoxInv:[UInt32] = self.sBoxes.invSBox
// Parameters for Linear Congruence Generators
private let Rcon:[UInt8] = [
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]
private let T0:[UInt32] = [0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f, 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c]
private let T0_INV:[UInt32] = [0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0]
private let T1:[UInt32] = [0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x1010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x5050a0f, 0x9a9a2fb5, 0x7070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x0, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x2020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0xc0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0xb0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0xa0a141e, 0x494992db, 0x6060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x8081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x3030605, 0xf6f6f701, 0xe0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0xd0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0xf0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a]
private let T1_INV:[UInt32] = [0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x3e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0xeea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x24b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x6dd963d, 0x53eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, 0xa7ca147, 0xf427ce9, 0x1e84f8c9, 0x0, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0xd090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0xbd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x99fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 0xca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x1a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042]
private let T2:[UInt32] = [0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x1020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x4080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x50a0f05, 0x9a2fb59a, 0x70e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x9121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x0, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x2040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0xc18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0xb161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0xa141e0a, 0x4992db49, 0x60c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x8101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x3060503, 0xf6f701f6, 0xe1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0xd1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0xf1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16]
private let T2_INV:[UInt32] = [0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x2f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x8f9942b, 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x7f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x6046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x0, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0xefdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0xf0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0xa0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x90e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x1f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x4f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0xbfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0xdff4195, 0xa8397101, 0xc08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257]
private let T3:[UInt32] = [0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x2030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x80c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0xa0f0505, 0x2fb59a9a, 0xe090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x0, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x4060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x58a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0xb838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0xc0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x18c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0xd868b8b, 0xf858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x6050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x7898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x38f8c8c, 0x59f8a1a1, 0x9808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616]
private let T3_INV:[UInt32] = [0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x3e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x2ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x6d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x532e18a, 0xa475ebf6, 0xb39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x46fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x7888b89, 0xe7385b19, 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x0, 0x9838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0xf563885, 0x3d1ed5ae, 0x3627392d, 0xa64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0xcb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0xe0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0xdec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x15d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x8deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8]
private var U1:[UInt32] = [0x0, 0xb0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, 0xfe75793, 0x4ea5e9d, 0x19fd458f, 0x12f04c81, 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733, 0x8cfbc21, 0x3c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x728ebb2, 0xc25e2bc, 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x97826cd, 0x2752fc3, 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, 0x10856342, 0x1b886a4c, 0x69f715e, 0xd927850, 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, 0x1b79aec, 0xaba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, 0xe50cd7f, 0x55dc471, 0x184adf63, 0x1347d66d, 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d]
private var U2:[UInt32] = [0x0, 0xd090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245, 0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81, 0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966, 0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112, 0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa, 0x3e34b93, 0xeea4598, 0x19f15785, 0x14f8598e, 0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7, 0x53eddae, 0x837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b, 0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f, 0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8, 0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x6dd963d, 0xbd49836, 0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c, 0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea, 0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e, 0xa7ca147, 0x775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302, 0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd, 0x99fead4, 0x496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821, 0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055, 0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44, 0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680, 0xf427ce9, 0x24b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8, 0xca1377a, 0x1a83971, 0x16b32b6c, 0x1bba2567, 0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13, 0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f, 0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3]
private var U3:[UInt32] = [0x0, 0x90e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f, 0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3, 0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac, 0x1fe3578f, 0x16ed5c82, 0xdff4195, 0x4f14a98, 0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0, 0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14, 0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e, 0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c, 0x8f9942b, 0x1f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa, 0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6, 0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5, 0x506d5be, 0xc08deb3, 0x171ac3a4, 0x1e14c8a9, 0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25, 0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd, 0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91, 0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275, 0x10e93356, 0x19e7385b, 0x2f5254c, 0xbfb2e41, 0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42, 0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6, 0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0xf0a64d9, 0x6046fd4, 0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa, 0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8, 0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0xa0cb167, 0x302ba6a, 0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044, 0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b, 0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347, 0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5, 0x7f3f0f2, 0xefdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3, 0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397]
private var U4:[UInt32] = [0x0, 0xe0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53, 0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af, 0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20, 0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c, 0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x3e75f8f, 0xdec5286, 0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8, 0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49, 0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd, 0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5, 0x532e18a, 0xb39ec83, 0x1924fb98, 0x172ff691, 0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572, 0x6d5be05, 0x8deb30c, 0x1ac3a417, 0x14c8a91e, 0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2, 0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7, 0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf, 0x9838680, 0x7888b89, 0x15959c92, 0x1b9e919b, 0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f, 0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8, 0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c, 0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0xa64d90f, 0x46fd406, 0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30, 0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9, 0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0xcb1670a, 0x2ba6a03, 0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435, 0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba, 0xf563885, 0x15d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6, 0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362, 0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746]
public init(key:[UInt8], iv:[UInt8], blockMode:CipherBlockMode = .CBC) throws {
self.key = key
self.iv = iv
self.blockMode = blockMode
if (blockMode.options.contains(.InitializationVectorRequired) && iv.count != AES.blockSize) {
assert(false, "Block size and Initialization Vector must be the same length!")
throw Error.InvalidInitializationVector
}
}
convenience public init(key:[UInt8], blockMode:CipherBlockMode = .CBC) throws {
// default IV is all 0x00...
let defaultIV = [UInt8](count: AES.blockSize, repeatedValue: 0)
try self.init(key: key, iv: defaultIV, blockMode: blockMode)
}
/**
Encrypt message. If padding is necessary, then PKCS7 padding is added and needs to be removed after decryption.
- parameter message: Plaintext data
- parameter padding: Optional padding
- returns: Encrypted data
*/
public func encrypt(bytes:[UInt8], padding:Padding? = PKCS7()) throws -> [UInt8] {
var finalBytes = bytes;
if let padding = padding {
finalBytes = padding.add(bytes, blockSize: AES.blockSize)
} else if blockMode.options.contains(.PaddingRequired) && (bytes.count % AES.blockSize != 0) {
throw Error.BlockSizeExceeded
}
let blocks = finalBytes.chunks(AES.blockSize)
let encryptGenerator = blockMode.encryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
var out = [UInt8]()
out.reserveCapacity(bytes.count)
for processedBlock in AnySequence<Array<UInt8>>({ encryptGenerator }) {
out.appendContentsOf(processedBlock)
}
return out
}
private func encryptBlock(block:[UInt8]) -> [UInt8]? {
let rounds = self.variant.Nr
let rk = self.expandedKey
var b = toUInt32Array(block[block.startIndex..<block.endIndex])
var t = [UInt32](count: 4, repeatedValue: 0)
for r in 0..<rounds - 1 {
t[0] = b[0] ^ rk[r][0]
t[1] = b[1] ^ rk[r][1]
t[2] = b[2] ^ rk[r][2]
t[3] = b[3] ^ rk[r][3]
let lb00 = T0[Int(t[0] & 0xFF)]
let lb01 = T1[Int((t[1] >> 8) & 0xFF)]
let lb02 = T2[Int((t[2] >> 16) & 0xFF)]
let lb03 = T3[Int(t[3] >> 24)]
b[0] = lb00 ^ lb01 ^ lb02 ^ lb03
let lb10 = T0[Int(t[1] & 0xFF)]
let lb11 = T1[Int((t[2] >> 8) & 0xFF)]
let lb12 = T2[Int((t[3] >> 16) & 0xFF)]
let lb13 = T3[Int(t[0] >> 24)]
b[1] = lb10 ^ lb11 ^ lb12 ^ lb13
let lb20 = T0[Int(t[2] & 0xFF)]
let lb21 = T1[Int((t[3] >> 8) & 0xFF)]
let lb22 = T2[Int((t[0] >> 16) & 0xFF)]
let lb23 = T3[Int(t[1] >> 24)]
b[2] = lb20 ^ lb21 ^ lb22 ^ lb23
let lb30 = T0[Int(t[3] & 0xFF)]
let lb31 = T1[Int((t[0] >> 8) & 0xFF)]
let lb32 = T2[Int((t[1] >> 16) & 0xFF)]
let lb33 = T3[Int(t[2] >> 24)]
b[3] = lb30 ^ lb31 ^ lb32 ^ lb33
}
// last round
let r = rounds - 1
t[0] = b[0] ^ rk[r][0]
t[1] = b[1] ^ rk[r][1]
t[2] = b[2] ^ rk[r][2]
t[3] = b[3] ^ rk[r][3]
// rounds
b[0] = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0]
b[1] = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
b[2] = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
b[3] = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
var out = [UInt8]()
out.reserveCapacity(b.count * 4)
for num in b {
out.append(UInt8(num & 0xFF))
out.append(UInt8((num >> 8) & 0xFF))
out.append(UInt8((num >> 16) & 0xFF))
out.append(UInt8((num >> 24) & 0xFF))
}
return out
}
public func decrypt(bytes:[UInt8], padding:Padding? = PKCS7()) throws -> [UInt8] {
if padding == nil && blockMode.options.contains(.PaddingRequired) && (bytes.count % AES.blockSize != 0) {
throw Error.BlockSizeExceeded
}
let blocks = bytes.chunks(AES.blockSize)
var out = [UInt8]()
out.reserveCapacity(bytes.count)
switch (blockMode) {
case .CFB, .OFB, .CTR:
// CFB, OFB, CTR uses encryptBlock to decrypt
let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
out.appendContentsOf(processedBlock)
}
default:
let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: decryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
out.appendContentsOf(processedBlock)
}
}
if let padding = padding {
return padding.remove(out, blockSize: AES.blockSize)
}
return out
}
private func decryptBlock(block:[UInt8]) -> [UInt8]? {
let rounds = self.variant.Nr
let rk = expandedKeyInv
var b = toUInt32Array(block[block.startIndex..<block.endIndex])
var t = [UInt32](count: 4, repeatedValue: 0)
for r in (2...rounds).reverse() {
t[0] = b[0] ^ rk[r][0]
t[1] = b[1] ^ rk[r][1]
t[2] = b[2] ^ rk[r][2]
t[3] = b[3] ^ rk[r][3]
let b00 = T0_INV[Int(t[0] & 0xFF)]
let b01 = T1_INV[Int((t[3] >> 8) & 0xFF)]
let b02 = T2_INV[Int((t[2] >> 16) & 0xFF)]
let b03 = T3_INV[Int(t[1] >> 24)]
b[0] = b00 ^ b01 ^ b02 ^ b03
let b10 = T0_INV[Int(t[1] & 0xFF)]
let b11 = T1_INV[Int((t[0] >> 8) & 0xFF)]
let b12 = T2_INV[Int((t[3] >> 16) & 0xFF)]
let b13 = T3_INV[Int(t[2] >> 24)]
b[1] = b10 ^ b11 ^ b12 ^ b13
let b20 = T0_INV[Int(t[2] & 0xFF)]
let b21 = T1_INV[Int((t[1] >> 8) & 0xFF)]
let b22 = T2_INV[Int((t[0] >> 16) & 0xFF)]
let b23 = T3_INV[Int(t[3] >> 24)]
b[2] = b20 ^ b21 ^ b22 ^ b23
let b30 = T0_INV[Int(t[3] & 0xFF)]
let b31 = T1_INV[Int((t[2] >> 8) & 0xFF)]
let b32 = T2_INV[Int((t[1] >> 16) & 0xFF)]
let b33 = T3_INV[Int(t[0] >> 24)]
b[3] = b30 ^ b31 ^ b32 ^ b33
}
// last round
t[0] = b[0] ^ rk[1][0]
t[1] = b[1] ^ rk[1][1]
t[2] = b[2] ^ rk[1][2]
t[3] = b[3] ^ rk[1][3]
// rounds
let lb00 = sBoxInv[Int(B0(t[0]))]
let lb01 = (sBoxInv[Int(B1(t[3]))] << 8)
let lb02 = (sBoxInv[Int(B2(t[2]))] << 16)
let lb03 = (sBoxInv[Int(B3(t[1]))] << 24)
b[0] = lb00 | lb01 | lb02 | lb03 ^ rk[0][0]
let lb10 = sBoxInv[Int(B0(t[1]))]
let lb11 = (sBoxInv[Int(B1(t[0]))] << 8)
let lb12 = (sBoxInv[Int(B2(t[3]))] << 16)
let lb13 = (sBoxInv[Int(B3(t[2]))] << 24)
b[1] = lb10 | lb11 | lb12 | lb13 ^ rk[0][1]
let lb20 = sBoxInv[Int(B0(t[2]))]
let lb21 = (sBoxInv[Int(B1(t[1]))] << 8)
let lb22 = (sBoxInv[Int(B2(t[0]))] << 16)
let lb23 = (sBoxInv[Int(B3(t[3]))] << 24)
b[2] = lb20 | lb21 | lb22 | lb23 ^ rk[0][2]
let lb30 = sBoxInv[Int(B0(t[3]))]
let lb31 = (sBoxInv[Int(B1(t[2]))] << 8)
let lb32 = (sBoxInv[Int(B2(t[1]))] << 16)
let lb33 = (sBoxInv[Int(B3(t[0]))] << 24)
b[3] = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
var out = [UInt8]()
out.reserveCapacity(b.count * 4)
for num in b {
out.append(UInt8(num & 0xFF))
out.append(UInt8((num >> 8) & 0xFF))
out.append(UInt8((num >> 16) & 0xFF))
out.append(UInt8((num >> 24) & 0xFF))
}
return out
}
private func expandKeyInv(key:[UInt8], variant:AESVariant) -> [[UInt32]] {
let rounds = variant.Nr
var rk2:[[UInt32]] = expandKey(key, variant: variant)
for r in 1..<rounds {
var w:UInt32
w = rk2[r][0];
rk2[r][0] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
w = rk2[r][1];
rk2[r][1] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
w = rk2[r][2];
rk2[r][2] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
w = rk2[r][3];
rk2[r][3] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
}
return rk2
}
private func expandKey(key:[UInt8], variant:AESVariant) -> [[UInt32]] {
func convertExpandedKey(expanded:[UInt8]) -> [[UInt32]] {
var arr = [UInt32]()
for idx in expanded.startIndex.stride(to: expanded.endIndex, by: 4) {
let four = Array(expanded[idx..<idx.advancedBy(4)].reverse())
let num = UInt32.withBytes(four)
arr.append(num)
}
var allarr = [[UInt32]]()
for idx in arr.startIndex.stride(to: arr.endIndex, by: 4) {
allarr.append(Array(arr[idx..<idx.advancedBy(4)]))
}
return allarr
}
/*
* Function used in the Key Expansion routine that takes a four-byte
* input word and applies an S-box to each of the four bytes to
* produce an output word.
*/
func subWord(word:[UInt8]) -> [UInt8] {
var result = word
for i in 0..<4 {
result[i] = UInt8(sBox[Int(word[i])])
}
return result
}
var w = [UInt8](count: variant.Nb * (variant.Nr + 1) * 4, repeatedValue: 0)
for i in 0..<variant.Nk {
for wordIdx in 0..<4 {
w[(4*i)+wordIdx] = key[(4*i)+wordIdx]
}
}
var tmp:[UInt8]
for i in variant.Nk..<variant.Nb * (variant.Nr + 1) {
tmp = [UInt8](count: 4, repeatedValue: 0)
for wordIdx in 0..<4 {
tmp[wordIdx] = w[4*(i-1)+wordIdx]
}
if ((i % variant.Nk) == 0) {
tmp = subWord(rotateLeft(UInt32.withBytes(tmp), 8).bytes(sizeof(UInt32)))
tmp[0] = tmp.first! ^ Rcon[i/variant.Nk]
} else if (variant.Nk > 6 && (i % variant.Nk) == 4) {
tmp = subWord(tmp)
}
// xor array of bytes
for wordIdx in 0..<4 {
w[4*i+wordIdx] = w[4*(i-variant.Nk)+wordIdx]^tmp[wordIdx];
}
}
return convertExpandedKey(w)
}
}
extension AES {
private func B0(x: UInt32) -> UInt32 {
return x & 0xFF
}
private func B1(x: UInt32) -> UInt32 {
return (x >> 8) & 0xFF
}
private func B2(x: UInt32) -> UInt32 {
return (x >> 16) & 0xFF
}
private func B3(x: UInt32) -> UInt32 {
return (x >> 24) & 0xFF
}
private func F1(x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
var result:UInt32 = 0
result |= UInt32(B1(T0[Int(x0 & 255)]))
result |= UInt32(B1(T0[Int((x1 >> 8) & 255)])) << 8
result |= UInt32(B1(T0[Int((x2 >> 16) & 255)])) << 16
result |= UInt32(B1(T0[Int(x3 >> 24)])) << 24
return result
}
private func calculateSBox() -> (sBox:[UInt32], invSBox:[UInt32]) {
var sbox = [UInt32](count: 256, repeatedValue: 0)
var invsbox = sbox
sbox[0] = 0x63
var p:UInt8 = 1, q:UInt8 = 1
repeat {
p = p ^ (UInt8(truncatingBitPattern: Int(p) << 1) ^ ((p & 0x80) == 0x80 ? 0x1B : 0))
q ^= q << 1
q ^= q << 2
q ^= q << 4
q ^= (q & 0x80) == 0x80 ? 0x09 : 0
let s = 0x63 ^ q ^ rotateLeft(q, 1) ^ rotateLeft(q, 2) ^ rotateLeft(q, 3) ^ rotateLeft(q, 4)
sbox[Int(p)] = UInt32(s)
invsbox[Int(s)] = UInt32(p)
} while (p != 1)
return (sBox: sbox, invSBox: invsbox)
}
}
extension AES: Cipher {
// MARK: - Cipher
public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
return try self.encrypt(bytes)
}
public func cipherDecrypt(bytes: [UInt8]) throws -> [UInt8] {
return try self.decrypt(bytes)
}
}

View File

@ -1,39 +0,0 @@
//
// ArrayExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 10/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
extension Array {
/** split in chunks with given chunk size */
func chunks(chunksize:Int) -> [Array<Element>] {
var words = [[Element]]()
words.reserveCapacity(self.count / chunksize)
for idx in chunksize.stride(through: self.count, by: chunksize) {
let word = Array(self[idx - chunksize..<idx]) // this is slow for large table
words.append(word)
}
let reminder = Array(self.suffix(self.count % chunksize))
if (reminder.count > 0) {
words.append(reminder)
}
return words
}
/*
This helper call is slow, therefore don't use it. It is due to extension, or due to optimization that can be done
subscript(index: UInt32) -> Element {
get {
return self[Int(index)]
}
set {
self[Int(index)] = newValue
}
}
*/
}

View File

@ -1,42 +0,0 @@
//
// ArraySlice.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
// Disabled because performance is bad. The cost of generic approach is to big.
/*
extension ArraySlice where Element: _UInt8Type {
func toUInt32Array() -> Array<UInt32> {
var result = Array<UInt32>()
result.reserveCapacity(16)
for idx in self.startIndex.stride(to: self.endIndex, by: sizeof(UInt32)) {
let val:UInt32 = (UInt32(self[idx.advancedBy(3)] as! UInt8) << 24) | (UInt32(self[idx.advancedBy(2)] as! UInt8) << 16) | (UInt32(self[idx.advancedBy(1)] as! UInt8) << 8) | UInt32(self[idx] as! UInt8)
result.append(val)
}
return result
}
func toUInt64Array() -> Array<UInt64> {
var result = Array<UInt64>()
result.reserveCapacity(32)
for idx in self.startIndex.stride(to: self.endIndex, by: sizeof(UInt64)) {
var val:UInt64 = 0
val |= UInt64(self[idx.advancedBy(7)] as! UInt8) << 56
val |= UInt64(self[idx.advancedBy(6)] as! UInt8) << 48
val |= UInt64(self[idx.advancedBy(5)] as! UInt8) << 40
val |= UInt64(self[idx.advancedBy(4)] as! UInt8) << 32
val |= UInt64(self[idx.advancedBy(3)] as! UInt8) << 24
val |= UInt64(self[idx.advancedBy(2)] as! UInt8) << 16
val |= UInt64(self[idx.advancedBy(1)] as! UInt8) << 8
val |= UInt64(self[idx.advancedBy(0)] as! UInt8) << 0
result.append(val)
}
return result
}
}
*/

View File

@ -1,45 +0,0 @@
//
// MAC.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 03/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
/**
* Message Authentication
*/
public enum Authenticator {
public enum Error: ErrorType {
case AuthenticateError
}
/**
Poly1305
- parameter key: 256-bit key
*/
case Poly1305(key: [UInt8])
case HMAC(key: [UInt8], variant:CryptoSwift.HMAC.Variant)
/**
Generates an authenticator for message using a one-time key and returns the 16-byte result
- returns: 16-byte message authentication code
*/
public func authenticate(message: [UInt8]) throws -> [UInt8] {
switch (self) {
case .Poly1305(let key):
guard let auth = CryptoSwift.Poly1305.authenticate(key: key, message: message) else {
throw Error.AuthenticateError
}
return auth
case .HMAC(let key, let variant):
guard let auth = CryptoSwift.HMAC.authenticate(key: key, message: message, variant: variant) else {
throw Error.AuthenticateError
}
return auth
}
}
}

View File

@ -1,17 +0,0 @@
//
// BitExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 01/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
extension Bit {
func inverted() -> Bit {
if (self == Bit.Zero) {
return Bit.One
}
return Bit.Zero
}
}

View File

@ -1,20 +0,0 @@
//
// BlockModeGenerator.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// I have no better name for that
enum BlockError: ErrorType {
case MissingInitializationVector
}
typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
protocol BlockModeGenerator: GeneratorType {
var options: BlockModeOptions { get }
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>)
}

View File

@ -1,15 +0,0 @@
//
// BlockModeOptions.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
struct BlockModeOptions: OptionSetType {
let rawValue: Int
static let None = BlockModeOptions(rawValue: 0)
static let InitializationVectorRequired = BlockModeOptions(rawValue: 1)
static let PaddingRequired = BlockModeOptions(rawValue: 2)
}

View File

@ -1,66 +0,0 @@
//
// CBC.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// Cipher-block chaining (CBC)
//
struct CBCModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next(),
let encrypted = cipherOperation(block: xor(prevCiphertext ?? iv, plaintext))
else {
return nil
}
self.prevCiphertext = encrypted
return encrypted
}
}
struct CBCModeDecryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let ciphertext = inputGenerator.next(),
let decrypted = cipherOperation(block: ciphertext)
else {
return nil
}
let result = xor(prevCiphertext ?? iv, decrypted)
self.prevCiphertext = ciphertext
return result
}
}

View File

@ -1,66 +0,0 @@
//
// CFB.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// Cipher feedback (CFB)
//
struct CFBModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next(),
let ciphertext = cipherOperation(block: prevCiphertext ?? iv)
else {
return nil
}
self.prevCiphertext = xor(plaintext, ciphertext)
return self.prevCiphertext
}
}
struct CFBModeDecryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let ciphertext = inputGenerator.next(),
let decrypted = cipherOperation(block: self.prevCiphertext ?? iv)
else {
return nil
}
let result = xor(decrypted, ciphertext)
self.prevCiphertext = ciphertext
return result
}
}

View File

@ -1,80 +0,0 @@
//
// CTR.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// Counter (CTR)
//
struct CTRModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var counter: UInt = 0
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next() else {
return nil
}
let nonce = buildNonce(iv, counter: UInt64(counter))
counter = counter + 1
if let encrypted = cipherOperation(block: nonce) {
return xor(plaintext, encrypted)
}
return nil
}
}
struct CTRModeDecryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var counter: UInt = 0
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let ciphertext = inputGenerator.next() else {
return nil
}
let nonce = buildNonce(iv, counter: UInt64(counter))
counter = counter + 1
if let decrypted = cipherOperation(block: nonce) {
return xor(decrypted, ciphertext)
}
return nil
}
}
private func buildNonce(iv: [UInt8], counter: UInt64) -> [UInt8] {
let noncePartLen = AES.blockSize / 2
let noncePrefix = Array(iv[0..<noncePartLen])
let nonceSuffix = Array(iv[noncePartLen..<iv.count])
let c = UInt64.withBytes(nonceSuffix) + counter
return noncePrefix + arrayOfBytes(c)
}

View File

@ -1,92 +0,0 @@
//
// CipherBlockMode.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
public enum CipherBlockMode {
case ECB, CBC, PCBC, CFB, OFB, CTR
func encryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
switch (self) {
case CBC:
return AnyGenerator<Array<UInt8>>(CBCModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case CFB:
return AnyGenerator<Array<UInt8>>(CFBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case OFB:
return AnyGenerator<Array<UInt8>>(OFBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case CTR:
return AnyGenerator<Array<UInt8>>(CTRModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case PCBC:
return AnyGenerator<Array<UInt8>>(PCBCModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case ECB:
return AnyGenerator<Array<UInt8>>(ECBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
}
}
func decryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
switch (self) {
case CBC:
return AnyGenerator<Array<UInt8>>(CBCModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case CFB:
return AnyGenerator<Array<UInt8>>(CFBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case OFB:
return AnyGenerator<Array<UInt8>>(OFBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case CTR:
return AnyGenerator<Array<UInt8>>(CTRModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case PCBC:
return AnyGenerator<Array<UInt8>>(PCBCModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
case ECB:
return AnyGenerator<Array<UInt8>>(ECBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
}
}
var options: BlockModeOptions {
switch (self) {
case .CBC:
return [.InitializationVectorRequired, .PaddingRequired]
case .CFB:
return .InitializationVectorRequired
case .CTR:
return .InitializationVectorRequired
case .ECB:
return .PaddingRequired
case .OFB:
return .InitializationVectorRequired
case .PCBC:
return [.InitializationVectorRequired, .PaddingRequired]
}
}
/**
Process input blocks with given block cipher mode. With fallback to plain mode.
- parameter blocks: cipher block size blocks
- parameter iv: IV
- parameter cipher: single block encryption closure
- returns: encrypted bytes
*/
// func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
//
// // if IV is not available, fallback to plain
// var finalBlockMode:CipherBlockMode = self
// if (iv == nil) {
// finalBlockMode = .ECB
// }
//
// return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
// }
//
// func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
// // if IV is not available, fallback to plain
// var finalBlockMode:CipherBlockMode = self
// if (iv == nil) {
// finalBlockMode = .ECB
// }
//
// return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
// }
}

View File

@ -1,37 +0,0 @@
//
// CipherBlockMode.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/12/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
// Electronic codebook (ECB)
//
struct ECBModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next(),
let encrypted = cipherOperation(block: plaintext)
else {
return nil
}
return encrypted
}
}
typealias ECBModeDecryptGenerator = ECBModeEncryptGenerator

View File

@ -1,66 +0,0 @@
//
// OFB.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// Output Feedback (OFB)
//
struct OFBModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next(),
let ciphertext = cipherOperation(block: prevCiphertext ?? iv)
else {
return nil
}
self.prevCiphertext = ciphertext
return xor(plaintext, ciphertext)
}
}
struct OFBModeDecryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let ciphertext = inputGenerator.next(),
let decrypted = cipherOperation(block: self.prevCiphertext ?? iv)
else {
return nil
}
let plaintext = xor(decrypted, ciphertext)
self.prevCiphertext = decrypted
return plaintext
}
}

View File

@ -1,66 +0,0 @@
//
// PCBM.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/03/16.
// Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
//
// Propagating Cipher Block Chaining (PCBC)
//
struct PCBCModeEncryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let plaintext = inputGenerator.next(),
let encrypted = cipherOperation(block: xor(prevCiphertext ?? iv, plaintext))
else {
return nil
}
self.prevCiphertext = xor(plaintext, encrypted)
return encrypted
}
}
struct PCBCModeDecryptGenerator: BlockModeGenerator {
typealias Element = Array<UInt8>
let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
private let iv: Element
private let inputGenerator: AnyGenerator<Element>
private let cipherOperation: CipherOperationOnBlock
private var prevCiphertext: Element?
init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
self.iv = iv
self.cipherOperation = cipherOperation
self.inputGenerator = inputGenerator
}
mutating func next() -> Element? {
guard let ciphertext = inputGenerator.next(),
let decrypted = cipherOperation(block: ciphertext)
else {
return nil
}
let plaintext = xor(prevCiphertext ?? iv, decrypted)
self.prevCiphertext = xor(plaintext, ciphertext)
return plaintext
}
}

View File

@ -1,24 +0,0 @@
//
// BytesSequence.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 26/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
struct BytesSequence: SequenceType {
let chunkSize: Int
let data: [UInt8]
func generate() -> AnyGenerator<ArraySlice<UInt8>> {
var offset:Int = 0
return AnyGenerator {
let end = min(self.chunkSize, self.data.count - offset)
let result = self.data[offset..<offset + end]
offset += result.count
return result.count > 0 ? result : nil
}
}
}

View File

@ -1,98 +0,0 @@
//
// CRC.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 25/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
final class CRC {
private static let table32:[UInt32] = [0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d]
private static let table16:[UInt16] = [0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040]
func crc32(message:[UInt8], seed: UInt32? = nil) -> UInt32 {
var crc:UInt32 = seed != nil ? seed! : 0xffffffff
for chunk in BytesSequence(chunkSize: 256, data: message) {
for b in chunk {
let idx = Int((crc ^ UInt32(b)) & 0xff)
crc = (crc >> 8) ^ CRC.table32[idx]
}
}
return crc ^ 0xffffffff
}
func crc16(message:[UInt8], seed: UInt16? = nil) -> UInt16 {
var crc:UInt16 = seed != nil ? seed! : 0x0000
for chunk in BytesSequence(chunkSize: 256, data: message) {
for b in chunk {
crc = (crc >> 8) ^ CRC.table16[Int((crc ^ UInt16(b)) & 0xFF)]
}
}
return crc
}
}

View File

@ -1,87 +0,0 @@
//
// _ArrayType+Extensions.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 08/10/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
public protocol CSArrayType: _ArrayType {
func cs_arrayValue() -> [Generator.Element]
}
extension Array: CSArrayType {
public func cs_arrayValue() -> [Generator.Element] {
return self
}
}
public extension CSArrayType where Generator.Element == UInt8 {
public func toHexString() -> String {
return self.lazy.reduce("") { $0 + String(format:"%02x", $1) }
}
public func toBase64() -> String? {
guard let bytesArray = self as? [UInt8] else {
return nil
}
return NSData(bytes: bytesArray).base64EncodedStringWithOptions([])
}
public init(base64: String) {
self.init()
guard let decodedData = NSData(base64EncodedString: base64, options: []) else {
return
}
self.appendContentsOf(decodedData.arrayOfBytes())
}
}
public extension CSArrayType where Generator.Element == UInt8 {
public func md5() -> [Generator.Element] {
return Hash.md5(cs_arrayValue()).calculate()
}
public func sha1() -> [Generator.Element] {
return Hash.sha1(cs_arrayValue()).calculate()
}
public func sha224() -> [Generator.Element] {
return Hash.sha224(cs_arrayValue()).calculate()
}
public func sha256() -> [Generator.Element] {
return Hash.sha256(cs_arrayValue()).calculate()
}
public func sha384() -> [Generator.Element] {
return Hash.sha384(cs_arrayValue()).calculate()
}
public func sha512() -> [Generator.Element] {
return Hash.sha512(cs_arrayValue()).calculate()
}
public func crc32(seed: UInt32? = nil) -> [Generator.Element] {
return Hash.crc32(cs_arrayValue(), seed: seed).calculate()
}
public func crc16(seed: UInt16? = nil) -> [Generator.Element] {
return Hash.crc16(cs_arrayValue(), seed: seed).calculate()
}
public func encrypt(cipher: Cipher) throws -> [Generator.Element] {
return try cipher.cipherEncrypt(cs_arrayValue())
}
public func decrypt(cipher: Cipher) throws -> [Generator.Element] {
return try cipher.cipherDecrypt(cs_arrayValue())
}
public func authenticate(authenticator: Authenticator) throws -> [Generator.Element] {
return try authenticator.authenticate(cs_arrayValue())
}
}

View File

@ -1,200 +0,0 @@
//
// ChaCha20.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 25/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
final public class ChaCha20 {
public enum Error: ErrorType {
case MissingContext
}
static let blockSize = 64 // 512 / 8
private let stateSize = 16
private var context:Context?
final private class Context {
var input:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
deinit {
for i in 0..<input.count {
input[i] = 0x00;
}
}
}
public init?(key:[UInt8], iv:[UInt8]) {
if let c = contextSetup(iv: iv, key: key) {
context = c
} else {
return nil
}
}
public func encrypt(bytes:[UInt8]) throws -> [UInt8] {
guard context != nil else {
throw Error.MissingContext
}
return try encryptBytes(bytes)
}
public func decrypt(bytes:[UInt8]) throws -> [UInt8] {
return try encrypt(bytes)
}
private final func wordToByte(input:[UInt32] /* 64 */) -> [UInt8]? /* 16 */ {
if (input.count != stateSize) {
return nil;
}
var x = input
for _ in 0..<10 {
quarterround(&x[0], &x[4], &x[8], &x[12])
quarterround(&x[1], &x[5], &x[9], &x[13])
quarterround(&x[2], &x[6], &x[10], &x[14])
quarterround(&x[3], &x[7], &x[11], &x[15])
quarterround(&x[0], &x[5], &x[10], &x[15])
quarterround(&x[1], &x[6], &x[11], &x[12])
quarterround(&x[2], &x[7], &x[8], &x[13])
quarterround(&x[3], &x[4], &x[9], &x[14])
}
var output = [UInt8]()
output.reserveCapacity(16)
for i in 0..<16 {
x[i] = x[i] &+ input[i]
output.appendContentsOf(x[i].bytes().reverse())
}
return output;
}
private func contextSetup(iv iv:[UInt8], key:[UInt8]) -> Context? {
let ctx = Context()
let kbits = key.count * 8
if (kbits != 128 && kbits != 256) {
return nil
}
// 4 - 8
for i in 0..<4 {
let start = i * 4
ctx.input[i + 4] = wordNumber(key[start..<(start + 4)])
}
var addPos = 0;
switch (kbits) {
case 256:
addPos += 16
// sigma
ctx.input[0] = 0x61707865 //apxe
ctx.input[1] = 0x3320646e //3 dn
ctx.input[2] = 0x79622d32 //yb-2
ctx.input[3] = 0x6b206574 //k et
default:
// tau
ctx.input[0] = 0x61707865 //apxe
ctx.input[1] = 0x3620646e //6 dn
ctx.input[2] = 0x79622d31 //yb-1
ctx.input[3] = 0x6b206574 //k et
break;
}
// 8 - 11
for i in 0..<4 {
let start = addPos + (i*4)
let bytes = key[start..<(start + 4)]
ctx.input[i + 8] = wordNumber(bytes)
}
// iv
ctx.input[12] = 0
ctx.input[13] = 0
ctx.input[14] = wordNumber(iv[0..<4])
ctx.input[15] = wordNumber(iv[4..<8])
return ctx
}
private final func encryptBytes(message:[UInt8]) throws -> [UInt8] {
guard let ctx = context else {
throw Error.MissingContext
}
var c:[UInt8] = [UInt8](count: message.count, repeatedValue: 0)
var cPos:Int = 0
var mPos:Int = 0
var bytes = message.count
while (true) {
if let output = wordToByte(ctx.input) {
ctx.input[12] = ctx.input[12] &+ 1
if (ctx.input[12] == 0) {
ctx.input[13] = ctx.input[13] &+ 1
/* stopping at 2^70 bytes per nonce is user's responsibility */
}
if (bytes <= ChaCha20.blockSize) {
for i in 0..<bytes {
c[i + cPos] = message[i + mPos] ^ output[i]
}
return c
}
for i in 0..<ChaCha20.blockSize {
c[i + cPos] = message[i + mPos] ^ output[i]
}
bytes -= ChaCha20.blockSize
cPos += ChaCha20.blockSize
mPos += ChaCha20.blockSize
}
}
}
private final func quarterround(inout a:UInt32, inout _ b:UInt32, inout _ c:UInt32, inout _ d:UInt32) {
a = a &+ b
d = rotateLeft((d ^ a), 16) //FIXME: WAT? n:
c = c &+ d
b = rotateLeft((b ^ c), 12);
a = a &+ b
d = rotateLeft((d ^ a), 8);
c = c &+ d
b = rotateLeft((b ^ c), 7);
}
}
// MARK: - Cipher
extension ChaCha20: Cipher {
public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
return try self.encrypt(bytes)
}
public func cipherDecrypt(bytes: [UInt8]) throws -> [UInt8] {
return try self.decrypt(bytes)
}
}
// MARK: Helpers
/// Change array to number. It's here because arrayOfBytes is too slow
private func wordNumber(bytes:ArraySlice<UInt8>) -> UInt32 {
var value:UInt32 = 0
for i:UInt32 in 0..<4 {
let j = bytes.startIndex + Int(i)
value = value | UInt32(bytes[j]) << (8 * i)
}
return value}

View File

@ -1,35 +0,0 @@
//
// Cipher.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 30/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
#if os(Linux)
import Glibc
#else
import Darwin
#endif
public enum CipherError: ErrorType {
case Encrypt
case Decrypt
}
public protocol Cipher {
func cipherEncrypt(bytes: [UInt8]) throws -> [UInt8]
func cipherDecrypt(bytes: [UInt8]) throws -> [UInt8]
static func randomIV(blockSize:Int) -> [UInt8]
}
extension Cipher {
static public func randomIV(blockSize:Int) -> [UInt8] {
var randomIV:[UInt8] = [UInt8]();
for _ in 0..<blockSize {
randomIV.append(UInt8(truncatingBitPattern: cs_arc4random_uniform(256)));
}
return randomIV
}
}

View File

@ -1,19 +0,0 @@
//
// AES+Foundation.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension AES {
convenience public init(key:String, iv:String, blockMode:CipherBlockMode = .CBC) throws {
guard let kkey = key.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes(), let iiv = iv.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes() else {
throw Error.InvalidKeyOrInitializationVector
}
try self.init(key: kkey, iv: iiv, blockMode: blockMode)
}
}

View File

@ -1,16 +0,0 @@
//
// Array+Foundation.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension Array where Element: _UInt8Type {
public init(_ data: NSData) {
self = Array<Element>(count: data.length, repeatedValue: Element.Zero())
data.getBytes(&self, length: self.count)
}
}

View File

@ -1,18 +0,0 @@
//
// ChaCha20+Foundation.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension ChaCha20 {
convenience public init?(key:String, iv:String) {
guard let kkey = key.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes(), let iiv = iv.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes() else {
return nil
}
self.init(key: kkey, iv: iiv)
}
}

View File

@ -1,110 +0,0 @@
//
// PGPDataExtension.swift
// SwiftPGP
//
// Created by Marcin Krzyzanowski on 05/07/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension NSMutableData {
/** Convenient way to append bytes */
internal func appendBytes(arrayOfBytes: [UInt8]) {
self.appendBytes(arrayOfBytes, length: arrayOfBytes.count)
}
}
extension NSData {
/// Two octet checksum as defined in RFC-4880. Sum of all octets, mod 65536
public func checksum() -> UInt16 {
var s:UInt32 = 0
var bytesArray = self.arrayOfBytes()
for i in 0..<bytesArray.count {
s = s + UInt32(bytesArray[i])
}
s = s % 65536
return UInt16(s)
}
@nonobjc public func md5() -> NSData {
let result = Hash.md5(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func sha1() -> NSData? {
let result = Hash.sha1(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func sha224() -> NSData? {
let result = Hash.sha224(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func sha256() -> NSData? {
let result = Hash.sha256(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func sha384() -> NSData? {
let result = Hash.sha384(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func sha512() -> NSData? {
let result = Hash.sha512(self.arrayOfBytes()).calculate()
return NSData.withBytes(result)
}
public func crc32(seed: UInt32? = nil) -> NSData? {
let result = Hash.crc32(self.arrayOfBytes(), seed: seed).calculate()
return NSData.withBytes(result)
}
public func crc16(seed: UInt16? = nil) -> NSData? {
let result = Hash.crc16(self.arrayOfBytes(), seed: seed).calculate()
return NSData.withBytes(result)
}
public func encrypt(cipher: Cipher) throws -> NSData {
let encrypted = try cipher.cipherEncrypt(self.arrayOfBytes())
return NSData.withBytes(encrypted)
}
public func decrypt(cipher: Cipher) throws -> NSData {
let decrypted = try cipher.cipherDecrypt(self.arrayOfBytes())
return NSData.withBytes(decrypted)
}
public func authenticate(authenticator: Authenticator) throws -> NSData {
let result = try authenticator.authenticate(self.arrayOfBytes())
return NSData.withBytes(result)
}
}
extension NSData {
public func toHexString() -> String {
return self.arrayOfBytes().toHexString()
}
public func arrayOfBytes() -> [UInt8] {
let count = self.length / sizeof(UInt8)
var bytesArray = [UInt8](count: count, repeatedValue: 0)
self.getBytes(&bytesArray, length:count * sizeof(UInt8))
return bytesArray
}
public convenience init(bytes: [UInt8]) {
self.init(data: NSData.withBytes(bytes))
}
class public func withBytes(bytes: [UInt8]) -> NSData {
return NSData(bytes: bytes, length: bytes.count)
}
}

View File

@ -1,28 +0,0 @@
//
// Rabbit+Foundation.swift
// CryptoSwift
//
// Created by Dima Kalachov on 13/11/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension Rabbit {
convenience public init?(key: String) {
guard let kkey = key.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes() else {
return nil
}
self.init(key: kkey)
}
convenience public init?(key: String, iv: String) {
guard let kkey = key.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes(),
let iiv = iv.bridge().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)?.arrayOfBytes()
else {
return nil
}
self.init(key: kkey, iv: iiv)
}
}

View File

@ -1,36 +0,0 @@
//
// String+Extension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 13/10/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
extension String {
/// Return Base64 back to String
public func decryptBase64ToString(cipher: Cipher) throws -> String {
guard let decodedData = NSData(base64EncodedString: self, options: []) else {
throw CipherError.Decrypt
}
let decrypted = try decodedData.decrypt(cipher)
if let decryptedString = String(data: decrypted, encoding: NSUTF8StringEncoding) {
return decryptedString
}
throw CipherError.Decrypt
}
public func decryptBase64(cipher: Cipher) throws -> [UInt8] {
guard let decodedData = NSData(base64EncodedString: self, options: []) else {
throw CipherError.Decrypt
}
return try decodedData.decrypt(cipher).arrayOfBytes()
}
}

View File

@ -1,19 +0,0 @@
//
// String+LinuxFoundation.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/12/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
// Workaround:
// https://github.com/krzyzanowskim/CryptoSwift/issues/177
extension String {
#if !os(Linux)
func bridge() -> NSString {
return self as NSString
}
#endif
}

View File

@ -1,20 +0,0 @@
//
// Utils+Foundation.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/09/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
import Foundation
func perf(text: String, closure: () -> ()) {
let measurementStart = NSDate();
closure()
let measurementStop = NSDate();
let executionTime = measurementStop.timeIntervalSinceDate(measurementStart)
print("\(text) \(executionTime)");
}

View File

@ -1,153 +0,0 @@
//
// Generics.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 02/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
/** Protocol and extensions for integerFromBitsArray. Bit hakish for me, but I can't do it in any other way */
protocol Initiable {
init(_ v: Int)
init(_ v: UInt)
}
extension Int:Initiable {}
extension UInt:Initiable {}
extension UInt8:Initiable {}
extension UInt16:Initiable {}
extension UInt32:Initiable {}
extension UInt64:Initiable {}
/** build bit pattern from array of bits */
func integerFromBitsArray<T: UnsignedIntegerType>(bits: [Bit]) -> T
{
var bitPattern:T = 0
for (idx,b) in bits.enumerate() {
if (b == Bit.One) {
let bit = T(UIntMax(1) << UIntMax(idx))
bitPattern = bitPattern | bit
}
}
return bitPattern
}
/// Initialize integer from array of bytes.
/// This method may be slow
func integerWithBytes<T: IntegerType where T:ByteConvertible, T: BitshiftOperationsType>(bytes: [UInt8]) -> T {
var bytes = bytes.reverse() as Array<UInt8> //FIXME: check it this is equivalent of Array(...)
if bytes.count < sizeof(T) {
let paddingCount = sizeof(T) - bytes.count
if (paddingCount > 0) {
bytes += [UInt8](count: paddingCount, repeatedValue: 0)
}
}
if sizeof(T) == 1 {
return T(truncatingBitPattern: UInt64(bytes.first!))
}
var result: T = 0
for byte in bytes.reverse() {
result = result << 8 | T(byte)
}
return result
}
/// Array of bytes, little-endian representation. Don't use if not necessary.
/// I found this method slow
func arrayOfBytes<T>(value:T, length:Int? = nil) -> [UInt8] {
let totalBytes = length ?? sizeof(T)
let valuePointer = UnsafeMutablePointer<T>.alloc(1)
valuePointer.memory = value
let bytesPointer = UnsafeMutablePointer<UInt8>(valuePointer)
var bytes = [UInt8](count: totalBytes, repeatedValue: 0)
for j in 0..<min(sizeof(T),totalBytes) {
bytes[totalBytes - 1 - j] = (bytesPointer + j).memory
}
valuePointer.destroy()
valuePointer.dealloc(1)
return bytes
}
// MARK: - shiftLeft
// helper to be able tomake shift operation on T
func << <T:SignedIntegerType>(lhs: T, rhs: Int) -> Int {
let a = lhs as! Int
let b = rhs
return a << b
}
func << <T:UnsignedIntegerType>(lhs: T, rhs: Int) -> UInt {
let a = lhs as! UInt
let b = rhs
return a << b
}
// Generic function itself
// FIXME: this generic function is not as generic as I would. It crashes for smaller types
func shiftLeft<T: SignedIntegerType where T: Initiable>(value: T, count: Int) -> T {
if (value == 0) {
return 0;
}
let bitsCount = (sizeofValue(value) * 8)
let shiftCount = Int(Swift.min(count, bitsCount - 1))
var shiftedValue:T = 0;
for bitIdx in 0..<bitsCount {
let bit = T(IntMax(1 << bitIdx))
if ((value & bit) == bit) {
shiftedValue = shiftedValue | T(bit << shiftCount)
}
}
if (shiftedValue != 0 && count >= bitsCount) {
// clear last bit that couldn't be shifted out of range
shiftedValue = shiftedValue & T(~(1 << (bitsCount - 1)))
}
return shiftedValue
}
// for any f*** other Integer type - this part is so non-Generic
func shiftLeft(value: UInt, count: Int) -> UInt {
return UInt(shiftLeft(Int(value), count: count)) //FIXME: count:
}
func shiftLeft(value: UInt8, count: Int) -> UInt8 {
return UInt8(shiftLeft(UInt(value), count: count))
}
func shiftLeft(value: UInt16, count: Int) -> UInt16 {
return UInt16(shiftLeft(UInt(value), count: count))
}
func shiftLeft(value: UInt32, count: Int) -> UInt32 {
return UInt32(shiftLeft(UInt(value), count: count))
}
func shiftLeft(value: UInt64, count: Int) -> UInt64 {
return UInt64(shiftLeft(UInt(value), count: count))
}
func shiftLeft(value: Int8, count: Int) -> Int8 {
return Int8(shiftLeft(Int(value), count: count))
}
func shiftLeft(value: Int16, count: Int) -> Int16 {
return Int16(shiftLeft(Int(value), count: count))
}
func shiftLeft(value: Int32, count: Int) -> Int32 {
return Int32(shiftLeft(Int(value), count: count))
}
func shiftLeft(value: Int64, count: Int) -> Int64 {
return Int64(shiftLeft(Int(value), count: count))
}

View File

@ -1,94 +0,0 @@
//
// HMAC.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 13/01/15.
// Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
//
final public class HMAC {
public enum Variant {
case sha1, sha256, sha384, sha512, md5
var size:Int {
switch (self) {
case .sha1:
return SHA1.size
case .sha256:
return SHA2.Variant.sha256.size
case .sha384:
return SHA2.Variant.sha384.size
case .sha512:
return SHA2.Variant.sha512.size
case .md5:
return MD5.size
}
}
func calculateHash(bytes bytes:[UInt8]) -> [UInt8]? {
switch (self) {
case .sha1:
return Hash.sha1(bytes).calculate()
case .sha256:
return Hash.sha256(bytes).calculate()
case .sha384:
return Hash.sha384(bytes).calculate()
case .sha512:
return Hash.sha512(bytes).calculate()
case .md5:
return Hash.md5(bytes).calculate()
}
}
func blockSize() -> Int {
switch self {
case .md5, .sha1, .sha256:
return 64
case .sha384, .sha512:
return 128
}
}
}
var key:[UInt8]
let variant:Variant
class internal func authenticate(key key: [UInt8], message: [UInt8], variant:HMAC.Variant = .md5) -> [UInt8]? {
return HMAC(key, variant: variant)?.authenticate(message: message)
}
// MARK: - Private
internal init? (_ key: [UInt8], variant:HMAC.Variant = .md5) {
self.variant = variant
self.key = key
if (key.count > variant.blockSize()) {
if let hash = variant.calculateHash(bytes: key) {
self.key = hash
}
}
if (key.count < variant.blockSize()) { // keys shorter than blocksize are zero-padded
self.key = key + [UInt8](count: variant.blockSize() - key.count, repeatedValue: 0)
}
}
internal func authenticate(message message:[UInt8]) -> [UInt8]? {
var opad = [UInt8](count: variant.blockSize(), repeatedValue: 0x5c)
for (idx, _) in key.enumerate() {
opad[idx] = key[idx] ^ opad[idx]
}
var ipad = [UInt8](count: variant.blockSize(), repeatedValue: 0x36)
for (idx, _) in key.enumerate() {
ipad[idx] = key[idx] ^ ipad[idx]
}
var finalHash:[UInt8]? = nil;
if let ipadAndMessageHash = variant.calculateHash(bytes: ipad + message) {
finalHash = variant.calculateHash(bytes: opad + ipadAndMessageHash);
}
return finalHash
}
}

View File

@ -1,36 +0,0 @@
//
// CryptoHash.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 07/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
public enum Hash {
case md5(Array<UInt8>)
case sha1(Array<UInt8>)
case sha224(Array<UInt8>), sha256(Array<UInt8>), sha384(Array<UInt8>), sha512(Array<UInt8>)
case crc32(Array<UInt8>, seed: UInt32?)
case crc16(Array<UInt8>, seed: UInt16?)
public func calculate() -> [UInt8] {
switch self {
case md5(let bytes):
return MD5(bytes).calculate()
case sha1(let bytes):
return SHA1(bytes).calculate()
case sha224(let bytes):
return SHA2(bytes, variant: .sha224).calculate32()
case sha256(let bytes):
return SHA2(bytes, variant: .sha256).calculate32()
case sha384(let bytes):
return SHA2(bytes, variant: .sha384).calculate64()
case sha512(let bytes):
return SHA2(bytes, variant: .sha512).calculate64()
case crc32(let bytes):
return CRC().crc32(bytes.0, seed: bytes.seed).bytes()
case crc16(let bytes):
return UInt32(CRC().crc16(bytes.0, seed: bytes.seed)).bytes(2)
}
}
}

View File

@ -1,36 +0,0 @@
//
// HashProtocol.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 17/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
internal protocol HashProtocol {
var message: Array<UInt8> { get }
/** Common part for hash calculation. Prepare header data. */
func prepare(len:Int) -> Array<UInt8>
}
extension HashProtocol {
func prepare(len:Int) -> Array<UInt8> {
var tmpMessage = message
// Step 1. Append Padding Bits
tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message
// append "0" bit until message length in bits 448 (mod 512)
var msgLength = tmpMessage.count
var counter = 0
while msgLength % len != (len - 8) {
counter += 1
msgLength += 1
}
tmpMessage += Array<UInt8>(count: counter, repeatedValue: 0)
return tmpMessage
}
}

View File

@ -1,113 +0,0 @@
//
// IntExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 12/08/14.
// Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// 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:
//
// - 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.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
#if os(Linux)
import Glibc
#else
import Darwin
#endif
/* array of bits */
extension Int {
init(bits: [Bit]) {
self.init(bitPattern: integerFromBitsArray(bits) as UInt)
}
}
/* array of bytes */
extension Int {
/** Array of bytes with optional padding (little-endian) */
public func bytes(totalBytes: Int = sizeof(Int)) -> [UInt8] {
return arrayOfBytes(self, length: totalBytes)
}
public static func withBytes(bytes: ArraySlice<UInt8>) -> Int {
return Int.withBytes(Array(bytes))
}
/** Int with array bytes (little-endian) */
public static func withBytes(bytes: [UInt8]) -> Int {
return integerWithBytes(bytes)
}
}
/** Shift bits */
extension Int {
/** Shift bits to the left. All bits are shifted (including sign bit) */
private mutating func shiftLeft(count: Int) -> Int {
self = CryptoSwift.shiftLeft(self, count: count) //FIXME: count:
return self
}
/** Shift bits to the right. All bits are shifted (including sign bit) */
private mutating func shiftRight(count: Int) -> Int {
if (self == 0) {
return self;
}
let bitsCount = sizeofValue(self) * 8
if (count >= bitsCount) {
return 0
}
let maxBitsForValue = Int(floor(log2(Double(self)) + 1))
let shiftCount = Swift.min(count, maxBitsForValue - 1)
var shiftedValue:Int = 0;
for bitIdx in 0..<bitsCount {
// if bit is set then copy to result and shift left 1
let bit = 1 << bitIdx
if ((self & bit) == bit) {
shiftedValue = shiftedValue | (bit >> shiftCount)
}
}
self = Int(shiftedValue)
return self
}
}
// Left operator
/** shift left and assign with bits truncation */
public func &<<= (inout lhs: Int, rhs: Int) {
lhs.shiftLeft(rhs)
}
/** shift left with bits truncation */
public func &<< (lhs: Int, rhs: Int) -> Int {
var l = lhs;
l.shiftLeft(rhs)
return l
}
// Right operator
/** shift right and assign with bits truncation */
func &>>= (inout lhs: Int, rhs: Int) {
lhs.shiftRight(rhs)
}
/** shift right and assign with bits truncation */
func &>> (lhs: Int, rhs: Int) -> Int {
var l = lhs;
l.shiftRight(rhs)
return l
}

View File

@ -1,38 +0,0 @@
//
// IntegerConvertible.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 02/06/15.
// Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
//
protocol BitshiftOperationsType {
func <<(lhs: Self, rhs: Self) -> Self
func >>(lhs: Self, rhs: Self) -> Self
func <<=(inout lhs: Self, rhs: Self)
func >>=(inout lhs: Self, rhs: Self)
}
protocol ByteConvertible {
init(_ value: UInt8)
init(truncatingBitPattern: UInt64)
}
extension Int : BitshiftOperationsType, ByteConvertible { }
extension Int8 : BitshiftOperationsType, ByteConvertible { }
extension Int16 : BitshiftOperationsType, ByteConvertible { }
extension Int32 : BitshiftOperationsType, ByteConvertible { }
extension Int64 : BitshiftOperationsType, ByteConvertible {
init(truncatingBitPattern value: UInt64) {
self = Int64(bitPattern: value)
}
}
extension UInt : BitshiftOperationsType, ByteConvertible { }
extension UInt8 : BitshiftOperationsType, ByteConvertible { }
extension UInt16 : BitshiftOperationsType, ByteConvertible { }
extension UInt32 : BitshiftOperationsType, ByteConvertible { }
extension UInt64 : BitshiftOperationsType, ByteConvertible {
init(truncatingBitPattern value: UInt64) {
self = value
}
}

View File

@ -1,118 +0,0 @@
//
// MD5.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 06/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
final class MD5 : HashProtocol {
static let size:Int = 16 // 128 / 8
let message: Array<UInt8>
init (_ message: Array<UInt8>) {
self.message = message
}
/** specifies the per-round shift amounts */
private let s: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
/** binary integer part of the sines of integers (Radians) */
private let k: [UInt32] = [0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
0x6b901122,0xfd987193,0xa679438e,0x49b40821,
0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,
0xd62f105d,0x2441453,0xd8a1e681,0xe7d3fbc8,
0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,
0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,
0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
0x289b7ec6,0xeaa127fa,0xd4ef3085,0x4881d05,
0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,
0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391]
private let h:[UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
func calculate() -> [UInt8] {
var tmpMessage = prepare(64)
tmpMessage.reserveCapacity(tmpMessage.count + 4)
// initialize hh with hash values
var hh = h
// Step 2. Append Length a 64-bit representation of lengthInBits
let lengthInBits = (message.count * 8)
let lengthBytes = lengthInBits.bytes(64 / 8)
tmpMessage += lengthBytes.reverse()
// Process the message in successive 512-bit chunks:
let chunkSizeBytes = 512 / 8 // 64
for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
// break chunk into sixteen 32-bit words M[j], 0 j 15
var M = toUInt32Array(chunk)
assert(M.count == 16, "Invalid array")
// Initialize hash value for this chunk:
var A:UInt32 = hh[0]
var B:UInt32 = hh[1]
var C:UInt32 = hh[2]
var D:UInt32 = hh[3]
var dTemp:UInt32 = 0
// Main loop
for j in 0..<k.count {
var g = 0
var F:UInt32 = 0
switch (j) {
case 0...15:
F = (B & C) | ((~B) & D)
g = j
break
case 16...31:
F = (D & B) | (~D & C)
g = (5 * j + 1) % 16
break
case 32...47:
F = B ^ C ^ D
g = (3 * j + 5) % 16
break
case 48...63:
F = C ^ (B | (~D))
g = (7 * j) % 16
break
default:
break
}
dTemp = D
D = C
C = B
B = B &+ rotateLeft((A &+ F &+ k[j] &+ M[g]), s[j])
A = dTemp
}
hh[0] = hh[0] &+ A
hh[1] = hh[1] &+ B
hh[2] = hh[2] &+ C
hh[3] = hh[3] &+ D
}
var result = [UInt8]()
result.reserveCapacity(hh.count / 4)
hh.forEach {
let itemLE = $0.littleEndian
result += [UInt8(itemLE & 0xff), UInt8((itemLE >> 8) & 0xff), UInt8((itemLE >> 16) & 0xff), UInt8((itemLE >> 24) & 0xff)]
}
return result
}
}

View File

@ -1,22 +0,0 @@
//
// Multiplatform.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 03/12/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
#if os(Linux)
import Glibc
import SwiftShims
#else
import Darwin
#endif
func cs_arc4random_uniform(upperBound: UInt32) -> UInt32 {
#if os(Linux)
return _swift_stdlib_arc4random_uniform(upperBound)
#else
return arc4random_uniform(upperBound)
#endif
}

View File

@ -1,43 +0,0 @@
//
// Operators.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 02/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
/*
Bit shifting with overflow protection using overflow operator "&".
Approach is consistent with standard overflow operators &+, &-, &*, &/
and introduce new overflow operators for shifting: &<<, &>>
Note: Works with unsigned integers values only
Usage
var i = 1 // init
var j = i &<< 2 //shift left
j &<<= 2 //shift left and assign
@see: https://medium.com/@krzyzanowskim/swiftly-shift-bits-and-protect-yourself-be33016ce071
*/
infix operator &<<= {
associativity none
precedence 160
}
infix operator &<< {
associativity none
precedence 160
}
infix operator &>>= {
associativity none
precedence 160
}
infix operator &>> {
associativity none
precedence 160
}

View File

@ -1,50 +0,0 @@
//
// PKCS.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 12/03/15.
// Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
//
// PKCS is a group of public-key cryptography standards devised
// and published by RSA Security Inc, starting in the early 1990s.
//
// PKCS#5 http://tools.ietf.org/html/rfc2898
//public struct PKCS5 {
//}
//
//extension PKCS5 {
// //
// // PBKDF2 - Password-Based Key Derivation Function 2. Key stretching technique.
// // DK = PBKDF2(PRF, Password, Salt, c, dkLen)
// //
// struct PBKDF2 {
// typealias Bytes = [UInt8]
// private func calc(# hash:Hash, password:Bytes, salt:Bytes, c:Int, dkLen:Int) -> [UInt8]? {
// if (dkLen > Int(pow(2,32) as Float - 1)) {
// println("ERROR: derived key too long");
// return nil
// }
//
// if let prf = HMAC(password, variant: .sha256) { //FIXME: hardcoded SHA256
// let hLen = prf.variant.size
// let numBlocks = Int(ceilf(Float(dkLen) / Float(hLen))) // l
// let lastBlockOctets = dkLen - (1 - numBlocks) * hLen // r
// // blocks
// for block in 1...numBlocks {
// // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
// // U_1 = PRF(password, salt || uint(i))
// var uinti = [UInt8](count: 4, repeatedValue: 0)
// uinti[0] = UInt8(block >> 24)
// uinti[1] = UInt8(block >> 16)
// uinti[2] = UInt8(block >> 8)
// uinti[3] = UInt8(block)
// if let dk = prf.authenticate(message: salt + uinti) {
// let T = dk[dk.count - hLen]
// }
// }
// }
// return nil
// }
// }
//}

View File

@ -1,57 +0,0 @@
//
// PKCS7.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 28/02/15.
// Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
//
// PKCS is a group of public-key cryptography standards devised
// and published by RSA Security Inc, starting in the early 1990s.
//
public struct PKCS7: Padding {
public enum Error: ErrorType {
case InvalidPaddingValue
}
public init() {
}
public func add(bytes: [UInt8] , blockSize:Int) -> [UInt8] {
let padding = UInt8(blockSize - (bytes.count % blockSize))
var withPadding = bytes
if (padding == 0) {
// If the original data is a multiple of N bytes, then an extra block of bytes with value N is added.
for _ in 0..<blockSize {
withPadding.appendContentsOf([UInt8(blockSize)])
}
} else {
// The value of each added byte is the number of bytes that are added
for _ in 0..<padding {
withPadding.appendContentsOf([UInt8(padding)])
}
}
return withPadding
}
public func remove(bytes: [UInt8], blockSize:Int?) -> [UInt8] {
assert(bytes.count > 0, "Need bytes to remove padding")
guard bytes.count > 0, let lastByte = bytes.last else {
return bytes
}
let padding = Int(lastByte) // last byte
let finalLength = bytes.count - padding
if finalLength < 0 {
return bytes
}
if padding >= 1 {
return Array(bytes[0..<finalLength])
}
return bytes
}
}

View File

@ -1,12 +0,0 @@
//
// Padding.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 27/02/15.
// Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
//
public protocol Padding {
func add(data: [UInt8], blockSize:Int) -> [UInt8]
func remove(data: [UInt8], blockSize:Int?) -> [UInt8]
}

View File

@ -1,302 +0,0 @@
//
// Poly1305.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 30/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4
//
// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
final public class Poly1305 {
let blockSize = 16
private var ctx:Context?
private class Context {
var r = [UInt8](count: 17, repeatedValue: 0)
var h = [UInt8](count: 17, repeatedValue: 0)
var pad = [UInt8](count: 17, repeatedValue: 0)
var buffer = [UInt8](count: 16, repeatedValue: 0)
var final:UInt8 = 0
var leftover:Int = 0
init?(_ key: [UInt8]) {
assert(key.count == 32,"Invalid key length");
if (key.count != 32) {
return nil;
}
for i in 0..<17 {
h[i] = 0
}
r[0] = key[0] & 0xff;
r[1] = key[1] & 0xff;
r[2] = key[2] & 0xff;
r[3] = key[3] & 0x0f;
r[4] = key[4] & 0xfc;
r[5] = key[5] & 0xff;
r[6] = key[6] & 0xff;
r[7] = key[7] & 0x0f;
r[8] = key[8] & 0xfc;
r[9] = key[9] & 0xff;
r[10] = key[10] & 0xff;
r[11] = key[11] & 0x0f;
r[12] = key[12] & 0xfc;
r[13] = key[13] & 0xff;
r[14] = key[14] & 0xff;
r[15] = key[15] & 0x0f;
r[16] = 0
for i in 0..<16 {
pad[i] = key[i + 16]
}
pad[16] = 0
leftover = 0
final = 0
}
deinit {
for i in 0..<buffer.count {
buffer[i] = 0
}
for i in 0..<r.count {
r[i] = 0
h[i] = 0
pad[i] = 0
final = 0
leftover = 0
}
}
}
// MARK: - Internal
/**
Calculate Message Authentication Code (MAC) for message.
Calculation context is discarder on instance deallocation.
- parameter key: 256-bit key
- parameter message: Message
- returns: Message Authentication Code
*/
class internal func authenticate(key key: [UInt8], message: [UInt8]) -> [UInt8]? {
return Poly1305(key)?.authenticate(message: message)
}
// MARK: - Private
private init? (_ key: [UInt8]) {
ctx = Context(key)
if (ctx == nil) {
return nil
}
}
private func authenticate(message message:[UInt8]) -> [UInt8]? {
if let ctx = self.ctx {
update(ctx, message: message)
return finish(ctx)
}
return nil
}
/**
Add message to be processed
- parameter context: Context
- parameter message: message
- parameter bytes: length of the message fragment to be processed
*/
private func update(context:Context, message:[UInt8], bytes:Int? = nil) {
var bytes = bytes ?? message.count
var mPos = 0
/* handle leftover */
if (context.leftover > 0) {
var want = blockSize - context.leftover
if (want > bytes) {
want = bytes
}
for i in 0..<want {
context.buffer[context.leftover + i] = message[mPos + i]
}
bytes -= want
mPos += want
context.leftover += want
if (context.leftover < blockSize) {
return
}
blocks(context, m: context.buffer)
context.leftover = 0
}
/* process full blocks */
if (bytes >= blockSize) {
let want = bytes & ~(blockSize - 1)
blocks(context, m: message, startPos: mPos)
mPos += want
bytes -= want;
}
/* store leftover */
if (bytes > 0) {
for i in 0..<bytes {
context.buffer[context.leftover + i] = message[mPos + i]
}
context.leftover += bytes
}
}
private func finish(context:Context) -> [UInt8]? {
var mac = [UInt8](count: 16, repeatedValue: 0);
/* process the remaining block */
if (context.leftover > 0) {
context.buffer[context.leftover] = 1
for i in (context.leftover + 1)..<blockSize {
context.buffer[i] = 0
}
context.final = 1
blocks(context, m: context.buffer)
}
/* fully reduce h */
freeze(context)
/* h = (h + pad) % (1 << 128) */
add(context, c: context.pad)
for i in 0..<mac.count {
mac[i] = context.h[i]
}
return mac
}
// MARK: - Utils
private func add(context:Context, c:[UInt8]) -> Bool {
if (context.h.count != 17 && c.count != 17) {
return false
}
var u:UInt16 = 0
for i in 0..<17 {
u += UInt16(context.h[i]) + UInt16(c[i])
context.h[i] = UInt8.withValue(u)
u = u >> 8
}
return true
}
private func squeeze(context:Context, hr:[UInt32]) -> Bool {
if (context.h.count != 17 && hr.count != 17) {
return false
}
var u:UInt32 = 0
for i in 0..<16 {
u += hr[i];
context.h[i] = UInt8.withValue(u) // crash! h[i] = UInt8(u) & 0xff
u >>= 8;
}
u += hr[16]
context.h[16] = UInt8.withValue(u) & 0x03
u >>= 2
u += (u << 2); /* u *= 5; */
for i in 0..<16 {
u += UInt32(context.h[i])
context.h[i] = UInt8.withValue(u) // crash! h[i] = UInt8(u) & 0xff
u >>= 8
}
context.h[16] += UInt8.withValue(u);
return true
}
private func freeze(context:Context) -> Bool {
assert(context.h.count == 17,"Invalid length")
if (context.h.count != 17) {
return false
}
let minusp:[UInt8] = [0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc]
var horig:[UInt8] = [UInt8](count: 17, repeatedValue: 0)
/* compute h + -p */
for i in 0..<17 {
horig[i] = context.h[i]
}
add(context, c: minusp)
/* select h if h < p, or h + -p if h >= p */
let bits:[Bit] = (context.h[16] >> 7).bits()
let invertedBits = bits.map({ (bit) -> Bit in
return bit.inverted()
})
let negative = UInt8(bits: invertedBits)
for i in 0..<17 {
context.h[i] ^= negative & (horig[i] ^ context.h[i]);
}
return true;
}
private func blocks(context:Context, m:[UInt8], startPos:Int = 0) -> Int {
var bytes = m.count
let hibit = context.final ^ 1 // 1 <<128
var mPos = startPos
while (bytes >= Int(blockSize)) {
var hr:[UInt32] = [UInt32](count: 17, repeatedValue: 0)
var u:UInt32 = 0
var c:[UInt8] = [UInt8](count: 17, repeatedValue: 0)
/* h += m */
for i in 0..<16 {
c[i] = m[mPos + i]
}
c[16] = hibit
add(context, c: c)
/* h *= r */
for i in 0..<17 {
u = 0
for j in 0...i {
u = u + UInt32(UInt16(context.h[j])) * UInt32(context.r[i - j]) // u += (unsigned short)st->h[j] * st->r[i - j];
}
for j in (i+1)..<17 {
var v:UInt32 = UInt32(UInt16(context.h[j])) * UInt32(context.r[i + 17 - j]) // unsigned long v = (unsigned short)st->h[j] * st->r[i + 17 - j];
v = ((v << 8) &+ (v << 6))
u = u &+ v
}
hr[i] = u
}
squeeze(context, hr: hr)
mPos += blockSize
bytes -= blockSize
}
return mPos
}
}

View File

@ -1,211 +0,0 @@
//
// Rabbit.swift
// CryptoSwift
//
// Created by Dima Kalachov on 12/11/15.
// Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
//
final public class Rabbit {
/// Size of IV in bytes
public static let ivSize = 64 / 8
/// Size of key in bytes
public static let keySize = 128 / 8
/// Size of block in bytes
public static let blockSize = 128 / 8
/// Key
private let key: [UInt8]
/// IV (optional)
private let iv: [UInt8]?
/// State variables
private var x = [UInt32](count: 8, repeatedValue: 0)
/// Counter variables
private var c = [UInt32](count: 8, repeatedValue: 0)
/// Counter carry
private var p7: UInt32 = 0
/// 'a' constants
private var a: [UInt32] = [
0x4D34D34D,
0xD34D34D3,
0x34D34D34,
0x4D34D34D,
0xD34D34D3,
0x34D34D34,
0x4D34D34D,
0xD34D34D3,
]
// MARK: - Initializers
convenience public init?(key:[UInt8]) {
self.init(key: key, iv: nil)
}
public init?(key:[UInt8], iv:[UInt8]?) {
self.key = key
self.iv = iv
guard key.count == Rabbit.keySize && (iv == nil || iv!.count == Rabbit.ivSize) else {
return nil
}
}
// MARK: -
private func setup() {
p7 = 0
// Key divided into 8 subkeys
var k = [UInt32](count: 8, repeatedValue: 0)
for j in 0..<8 {
k[j] = UInt32(key[Rabbit.blockSize - (2*j + 1)]) | (UInt32(key[Rabbit.blockSize - (2*j + 2)]) << 8)
}
// Initialize state and counter variables from subkeys
for j in 0..<8 {
if j % 2 == 0 {
x[j] = (k[(j+1) % 8] << 16) | k[j]
c[j] = (k[(j+4) % 8] << 16) | k[(j+5) % 8]
} else {
x[j] = (k[(j+5) % 8] << 16) | k[(j+4) % 8]
c[j] = (k[j] << 16) | k[(j+1) % 8]
}
}
// Iterate system four times
nextState()
nextState()
nextState()
nextState()
// Reinitialize counter variables
for j in 0..<8 {
c[j] = c[j] ^ x[(j+4) % 8]
}
if let iv = iv {
setupIV(iv)
}
}
private func setupIV(iv: [UInt8]) {
// 63...56 55...48 47...40 39...32 31...24 23...16 15...8 7...0 IV bits
// 0 1 2 3 4 5 6 7 IV bytes in array
let iv0: UInt32 = integerWithBytes([iv[4], iv[5], iv[6], iv[7]])
let iv1: UInt32 = integerWithBytes([iv[0], iv[1], iv[4], iv[5]])
let iv2: UInt32 = integerWithBytes([iv[0], iv[1], iv[2], iv[3]])
let iv3: UInt32 = integerWithBytes([iv[2], iv[3], iv[6], iv[7]])
// Modify the counter state as function of the IV
c[0] = c[0] ^ iv0
c[1] = c[1] ^ iv1
c[2] = c[2] ^ iv2
c[3] = c[3] ^ iv3
c[4] = c[4] ^ iv0
c[5] = c[5] ^ iv1
c[6] = c[6] ^ iv2
c[7] = c[7] ^ iv3
// Iterate system four times
nextState()
nextState()
nextState()
nextState()
}
private func nextState() {
// Before an iteration the counters are incremented
var carry = p7
for j in 0..<8 {
let prev = c[j]
c[j] = prev &+ a[j] &+ carry
carry = prev > c[j] ? 1 : 0 // detect overflow
}
p7 = carry // save last carry bit
// Iteration of the system
var newX = [UInt32](count: 8, repeatedValue: 0)
newX[0] = g(0) &+ rotateLeft(g(7), 16) &+ rotateLeft(g(6), 16)
newX[1] = g(1) &+ rotateLeft(g(0), 8) &+ g(7)
newX[2] = g(2) &+ rotateLeft(g(1), 16) &+ rotateLeft(g(0), 16)
newX[3] = g(3) &+ rotateLeft(g(2), 8) &+ g(1)
newX[4] = g(4) &+ rotateLeft(g(3), 16) &+ rotateLeft(g(2), 16)
newX[5] = g(5) &+ rotateLeft(g(4), 8) &+ g(3)
newX[6] = g(6) &+ rotateLeft(g(5), 16) &+ rotateLeft(g(4), 16)
newX[7] = g(7) &+ rotateLeft(g(6), 8) &+ g(5)
x = newX
}
private func g(j: Int) -> UInt32 {
let sum = x[j] &+ c[j]
let square = UInt64(sum) * UInt64(sum)
return UInt32(truncatingBitPattern: square ^ (square >> 32))
}
private func nextOutput() -> [UInt8] {
nextState()
var output16 = [UInt16](count: Rabbit.blockSize / 2, repeatedValue: 0)
output16[7] = UInt16(truncatingBitPattern: x[0]) ^ UInt16(truncatingBitPattern: x[5] >> 16)
output16[6] = UInt16(truncatingBitPattern: x[0] >> 16) ^ UInt16(truncatingBitPattern: x[3])
output16[5] = UInt16(truncatingBitPattern: x[2]) ^ UInt16(truncatingBitPattern: x[7] >> 16)
output16[4] = UInt16(truncatingBitPattern: x[2] >> 16) ^ UInt16(truncatingBitPattern: x[5])
output16[3] = UInt16(truncatingBitPattern: x[4]) ^ UInt16(truncatingBitPattern: x[1] >> 16)
output16[2] = UInt16(truncatingBitPattern: x[4] >> 16) ^ UInt16(truncatingBitPattern: x[7])
output16[1] = UInt16(truncatingBitPattern: x[6]) ^ UInt16(truncatingBitPattern: x[3] >> 16)
output16[0] = UInt16(truncatingBitPattern: x[6] >> 16) ^ UInt16(truncatingBitPattern: x[1])
var output8 = [UInt8](count: Rabbit.blockSize, repeatedValue: 0)
for j in 0..<output16.count {
output8[j * 2] = UInt8(truncatingBitPattern: output16[j] >> 8)
output8[j * 2 + 1] = UInt8(truncatingBitPattern: output16[j])
}
return output8
}
// MARK: - Public
public func encrypt(bytes: [UInt8]) -> [UInt8] {
setup()
var result = [UInt8](count: bytes.count, repeatedValue: 0)
var output = nextOutput()
var byteIdx = 0
var outputIdx = 0
while byteIdx < bytes.count {
if (outputIdx == Rabbit.blockSize) {
output = nextOutput()
outputIdx = 0
}
result[byteIdx] = bytes[byteIdx] ^ output[outputIdx]
byteIdx += 1
outputIdx += 1
}
return result
}
public func decrypt(bytes: [UInt8]) -> [UInt8] {
return encrypt(bytes)
}
}
// MARK: - Cipher
extension Rabbit: Cipher {
public func cipherEncrypt(bytes:[UInt8]) -> [UInt8] {
return self.encrypt(bytes)
}
public func cipherDecrypt(bytes: [UInt8]) -> [UInt8] {
return self.decrypt(bytes)
}
}

View File

@ -1,104 +0,0 @@
//
// SHA1.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 16/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
final class SHA1 : HashProtocol {
static let size:Int = 20 // 160 / 8
let message: [UInt8]
init(_ message: [UInt8]) {
self.message = message
}
private let h:[UInt32] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
func calculate() -> [UInt8] {
var tmpMessage = self.prepare(64)
// hash values
var hh = h
// append message length, in a 64-bit big-endian integer. So now the message length is a multiple of 512 bits.
tmpMessage += (self.message.count * 8).bytes(64 / 8)
// Process the message in successive 512-bit chunks:
let chunkSizeBytes = 512 / 8 // 64
for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
// break chunk into sixteen 32-bit words M[j], 0 j 15, big-endian
// Extend the sixteen 32-bit words into eighty 32-bit words:
var M:[UInt32] = [UInt32](count: 80, repeatedValue: 0)
for x in 0..<M.count {
switch (x) {
case 0...15:
let start = chunk.startIndex + (x * sizeofValue(M[x]))
let end = start + sizeofValue(M[x])
let le = toUInt32Array(chunk[start..<end])[0]
M[x] = le.bigEndian
break
default:
M[x] = rotateLeft(M[x-3] ^ M[x-8] ^ M[x-14] ^ M[x-16], 1) //FIXME: n:
break
}
}
var A = hh[0]
var B = hh[1]
var C = hh[2]
var D = hh[3]
var E = hh[4]
// Main loop
for j in 0...79 {
var f: UInt32 = 0;
var k: UInt32 = 0
switch (j) {
case 0...19:
f = (B & C) | ((~B) & D)
k = 0x5A827999
break
case 20...39:
f = B ^ C ^ D
k = 0x6ED9EBA1
break
case 40...59:
f = (B & C) | (B & D) | (C & D)
k = 0x8F1BBCDC
break
case 60...79:
f = B ^ C ^ D
k = 0xCA62C1D6
break
default:
break
}
let temp = (rotateLeft(A,5) &+ f &+ E &+ M[j] &+ k) & 0xffffffff
E = D
D = C
C = rotateLeft(B, 30)
B = A
A = temp
}
hh[0] = (hh[0] &+ A) & 0xffffffff
hh[1] = (hh[1] &+ B) & 0xffffffff
hh[2] = (hh[2] &+ C) & 0xffffffff
hh[3] = (hh[3] &+ D) & 0xffffffff
hh[4] = (hh[4] &+ E) & 0xffffffff
}
// Produce the final hash value (big-endian) as a 160 bit number:
var result = [UInt8]()
result.reserveCapacity(hh.count / 4)
hh.forEach {
let item = $0.bigEndian
result += [UInt8(item & 0xff), UInt8((item >> 8) & 0xff), UInt8((item >> 16) & 0xff), UInt8((item >> 24) & 0xff)]
}
return result
}
}

View File

@ -1,286 +0,0 @@
//
// SHA2.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 24/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
final class SHA2 : HashProtocol {
var size:Int { return variant.rawValue }
let variant:SHA2.Variant
let message: [UInt8]
init(_ message:[UInt8], variant: SHA2.Variant) {
self.variant = variant
self.message = message
}
enum Variant: RawRepresentable {
case sha224, sha256, sha384, sha512
typealias RawValue = Int
var rawValue: RawValue {
switch (self) {
case .sha224:
return 224
case .sha256:
return 256
case .sha384:
return 384
case .sha512:
return 512
}
}
init?(rawValue: RawValue) {
switch (rawValue) {
case 224:
self = .sha224
break;
case 256:
self = .sha256
break;
case 384:
self = .sha384
break;
case 512:
self = .sha512
break;
default:
return nil
}
}
var size:Int { return self.rawValue }
private var h:[UInt64] {
switch (self) {
case .sha224:
return [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4]
case .sha256:
return [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]
case .sha384:
return [0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4]
case .sha512:
return [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179]
}
}
private var k:[UInt64] {
switch (self) {
case .sha224, .sha256:
return [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
case .sha384, .sha512:
return [0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817]
}
}
private func resultingArray<T>(hh:[T]) -> ArraySlice<T> {
switch (self) {
case .sha224:
return hh[0..<7]
case .sha384:
return hh[0..<6]
default:
break;
}
return ArraySlice(hh)
}
}
//FIXME: I can't do Generic func out of calculate32 and calculate64 (UInt32 vs UInt64), but if you can - please do pull request.
func calculate32() -> [UInt8] {
var tmpMessage = self.prepare(64)
// hash values
var hh = [UInt32]()
variant.h.forEach {(h) -> () in
hh.append(UInt32(h))
}
// append message length, in a 64-bit big-endian integer. So now the message length is a multiple of 512 bits.
tmpMessage += (message.count * 8).bytes(64 / 8)
// Process the message in successive 512-bit chunks:
let chunkSizeBytes = 512 / 8 // 64
for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
// break chunk into sixteen 32-bit words M[j], 0 j 15, big-endian
// Extend the sixteen 32-bit words into sixty-four 32-bit words:
var M:[UInt32] = [UInt32](count: variant.k.count, repeatedValue: 0)
for x in 0..<M.count {
switch (x) {
case 0...15:
let start = chunk.startIndex + (x * sizeofValue(M[x]))
let end = start + sizeofValue(M[x])
let le = toUInt32Array(chunk[start..<end])[0]
M[x] = le.bigEndian
break
default:
let s0 = rotateRight(M[x-15], n: 7) ^ rotateRight(M[x-15], n: 18) ^ (M[x-15] >> 3) //FIXME: n
let s1 = rotateRight(M[x-2], n: 17) ^ rotateRight(M[x-2], n: 19) ^ (M[x-2] >> 10)
M[x] = M[x-16] &+ s0 &+ M[x-7] &+ s1
break
}
}
var A = hh[0]
var B = hh[1]
var C = hh[2]
var D = hh[3]
var E = hh[4]
var F = hh[5]
var G = hh[6]
var H = hh[7]
// Main loop
for j in 0..<variant.k.count {
let s0 = rotateRight(A,n: 2) ^ rotateRight(A,n: 13) ^ rotateRight(A,n: 22)
let maj = (A & B) ^ (A & C) ^ (B & C)
let t2 = s0 &+ maj
let s1 = rotateRight(E,n: 6) ^ rotateRight(E,n: 11) ^ rotateRight(E,n: 25)
let ch = (E & F) ^ ((~E) & G)
let t1 = H &+ s1 &+ ch &+ UInt32(variant.k[j]) &+ M[j]
H = G
G = F
F = E
E = D &+ t1
D = C
C = B
B = A
A = t1 &+ t2
}
hh[0] = (hh[0] &+ A)
hh[1] = (hh[1] &+ B)
hh[2] = (hh[2] &+ C)
hh[3] = (hh[3] &+ D)
hh[4] = (hh[4] &+ E)
hh[5] = (hh[5] &+ F)
hh[6] = (hh[6] &+ G)
hh[7] = (hh[7] &+ H)
}
// Produce the final hash value (big-endian) as a 160 bit number:
var result = [UInt8]()
result.reserveCapacity(hh.count / 4)
variant.resultingArray(hh).forEach {
let item = $0.bigEndian
result += [UInt8(item & 0xff), UInt8((item >> 8) & 0xff), UInt8((item >> 16) & 0xff), UInt8((item >> 24) & 0xff)]
}
return result
}
func calculate64() -> [UInt8] {
var tmpMessage = self.prepare(128)
// hash values
var hh = [UInt64]()
variant.h.forEach {(h) -> () in
hh.append(h)
}
// append message length, in a 64-bit big-endian integer. So now the message length is a multiple of 512 bits.
tmpMessage += (message.count * 8).bytes(64 / 8)
// Process the message in successive 1024-bit chunks:
let chunkSizeBytes = 1024 / 8 // 128
for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
// break chunk into sixteen 64-bit words M[j], 0 j 15, big-endian
// Extend the sixteen 64-bit words into eighty 64-bit words:
var M = [UInt64](count: variant.k.count, repeatedValue: 0)
for x in 0..<M.count {
switch (x) {
case 0...15:
let start = chunk.startIndex + (x * sizeofValue(M[x]))
let end = start + sizeofValue(M[x])
let le = toUInt64Array(chunk[start..<end])[0]
M[x] = le.bigEndian
break
default:
let s0 = rotateRight(M[x-15], n: 1) ^ rotateRight(M[x-15], n: 8) ^ (M[x-15] >> 7)
let s1 = rotateRight(M[x-2], n: 19) ^ rotateRight(M[x-2], n: 61) ^ (M[x-2] >> 6)
M[x] = M[x-16] &+ s0 &+ M[x-7] &+ s1
break
}
}
var A = hh[0]
var B = hh[1]
var C = hh[2]
var D = hh[3]
var E = hh[4]
var F = hh[5]
var G = hh[6]
var H = hh[7]
// Main loop
for j in 0..<variant.k.count {
let s0 = rotateRight(A,n: 28) ^ rotateRight(A,n: 34) ^ rotateRight(A,n: 39) //FIXME: n:
let maj = (A & B) ^ (A & C) ^ (B & C)
let t2 = s0 &+ maj
let s1 = rotateRight(E,n: 14) ^ rotateRight(E,n: 18) ^ rotateRight(E,n: 41)
let ch = (E & F) ^ ((~E) & G)
let t1 = H &+ s1 &+ ch &+ variant.k[j] &+ UInt64(M[j])
H = G
G = F
F = E
E = D &+ t1
D = C
C = B
B = A
A = t1 &+ t2
}
hh[0] = (hh[0] &+ A)
hh[1] = (hh[1] &+ B)
hh[2] = (hh[2] &+ C)
hh[3] = (hh[3] &+ D)
hh[4] = (hh[4] &+ E)
hh[5] = (hh[5] &+ F)
hh[6] = (hh[6] &+ G)
hh[7] = (hh[7] &+ H)
}
// Produce the final hash value (big-endian)
var result = [UInt8]()
result.reserveCapacity(hh.count / 4)
variant.resultingArray(hh).forEach {
let item = $0.bigEndian
var partialResult = [UInt8]()
partialResult.reserveCapacity(8)
for i in 0..<8 {
let shift = UInt64(8 * i)
partialResult.append(UInt8((item >> shift) & 0xff))
}
result += partialResult
}
return result
}
}

View File

@ -1,56 +0,0 @@
//
// StringExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 15/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
/** String extension */
extension String {
public func md5() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).md5().toHexString()
}
public func sha1() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).sha1().toHexString()
}
public func sha224() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).sha224().toHexString()
}
public func sha256() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).sha256().toHexString()
}
public func sha384() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).sha384().toHexString()
}
public func sha512() -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).sha512().toHexString()
}
public func crc32(seed: UInt32? = nil) -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).crc32(seed).toHexString()
}
public func crc16(seed: UInt16? = nil) -> String {
return self.utf8.lazy.map({ $0 as UInt8 }).crc16(seed).toHexString()
}
public func encrypt(cipher: Cipher) throws -> [UInt8] {
return try self.utf8.lazy.map({ $0 as UInt8 }).encrypt(cipher)
}
public func decrypt(cipher: Cipher) throws -> [UInt8] {
return try self.utf8.lazy.map({ $0 as UInt8 }).decrypt(cipher)
}
/// Returns hex string of bytes.
public func authenticate(authenticator: Authenticator) throws -> String {
return try self.utf8.lazy.map({ $0 as UInt8 }).authenticate(authenticator).toHexString()
}
}

View File

@ -1,116 +0,0 @@
//
// UInt32Extension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 02/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
#if os(Linux)
import Glibc
#else
import Darwin
#endif
protocol _UInt32Type { }
extension UInt32: _UInt32Type {}
/** array of bytes */
extension UInt32 {
public func bytes(totalBytes: Int = sizeof(UInt32)) -> [UInt8] {
return arrayOfBytes(self, length: totalBytes)
}
public static func withBytes(bytes: ArraySlice<UInt8>) -> UInt32 {
return UInt32.withBytes(Array(bytes))
}
/** Int with array bytes (little-endian) */
public static func withBytes(bytes: [UInt8]) -> UInt32 {
return integerWithBytes(bytes)
}
}
/** Shift bits */
extension UInt32 {
/** Shift bits to the left. All bits are shifted (including sign bit) */
private mutating func shiftLeft(count: UInt32) -> UInt32 {
if (self == 0) {
return self;
}
let bitsCount = UInt32(sizeof(UInt32) * 8)
let shiftCount = Swift.min(count, bitsCount - 1)
var shiftedValue:UInt32 = 0;
for bitIdx in 0..<bitsCount {
// if bit is set then copy to result and shift left 1
let bit = 1 << bitIdx
if ((self & bit) == bit) {
shiftedValue = shiftedValue | (bit << shiftCount)
}
}
if (shiftedValue != 0 && count >= bitsCount) {
// clear last bit that couldn't be shifted out of range
shiftedValue = shiftedValue & (~(1 << (bitsCount - 1)))
}
self = shiftedValue
return self
}
/** Shift bits to the right. All bits are shifted (including sign bit) */
private mutating func shiftRight(count: UInt32) -> UInt32 {
if (self == 0) {
return self;
}
let bitsCount = UInt32(sizeofValue(self) * 8)
if (count >= bitsCount) {
return 0
}
let maxBitsForValue = UInt32(floor(log2(Double(self)) + 1))
let shiftCount = Swift.min(count, maxBitsForValue - 1)
var shiftedValue:UInt32 = 0;
for bitIdx in 0..<bitsCount {
// if bit is set then copy to result and shift left 1
let bit = 1 << bitIdx
if ((self & bit) == bit) {
shiftedValue = shiftedValue | (bit >> shiftCount)
}
}
self = shiftedValue
return self
}
}
/** shift left and assign with bits truncation */
public func &<<= (inout lhs: UInt32, rhs: UInt32) {
lhs.shiftLeft(rhs)
}
/** shift left with bits truncation */
public func &<< (lhs: UInt32, rhs: UInt32) -> UInt32 {
var l = lhs;
l.shiftLeft(rhs)
return l
}
/** shift right and assign with bits truncation */
func &>>= (inout lhs: UInt32, rhs: UInt32) {
lhs.shiftRight(rhs)
}
/** shift right and assign with bits truncation */
func &>> (lhs: UInt32, rhs: UInt32) -> UInt32 {
var l = lhs;
l.shiftRight(rhs)
return l
}

View File

@ -1,23 +0,0 @@
//
// UInt64Extension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 02/09/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
/** array of bytes */
extension UInt64 {
public func bytes(totalBytes: Int = sizeof(UInt64)) -> [UInt8] {
return arrayOfBytes(self, length: totalBytes)
}
public static func withBytes(bytes: ArraySlice<UInt8>) -> UInt64 {
return UInt64.withBytes(Array(bytes))
}
/** Int with array bytes (little-endian) */
public static func withBytes(bytes: [UInt8]) -> UInt64 {
return integerWithBytes(bytes)
}
}

View File

@ -1,116 +0,0 @@
//
// ByteExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 07/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
#if os(Linux)
import Glibc
#else
import Darwin
#endif
public protocol _UInt8Type { }
extension UInt8: _UInt8Type {}
extension _UInt8Type {
static func Zero() -> Self {
return 0 as! Self
}
}
/** casting */
extension UInt8 {
/** cast because UInt8(<UInt32>) because std initializer crash if value is > byte */
static func withValue(v:UInt64) -> UInt8 {
let tmp = v & 0xFF
return UInt8(tmp)
}
static func withValue(v:UInt32) -> UInt8 {
let tmp = v & 0xFF
return UInt8(tmp)
}
static func withValue(v:UInt16) -> UInt8 {
let tmp = v & 0xFF
return UInt8(tmp)
}
}
/** Bits */
extension UInt8 {
init(bits: [Bit]) {
self.init(integerFromBitsArray(bits) as UInt8)
}
/** array of bits */
func bits() -> [Bit] {
let totalBitsCount = sizeofValue(self) * 8
var bitsArray = [Bit](count: totalBitsCount, repeatedValue: Bit.Zero)
for j in 0..<totalBitsCount {
let bitVal:UInt8 = 1 << UInt8(totalBitsCount - 1 - j)
let check = self & bitVal
if (check != 0) {
bitsArray[j] = Bit.One;
}
}
return bitsArray
}
func bits() -> String {
var s = String()
let arr:[Bit] = self.bits()
for (idx,b) in arr.enumerate() {
s += (b == Bit.One ? "1" : "0")
if ((idx + 1) % 8 == 0) { s += " " }
}
return s
}
}
/** Shift bits */
extension UInt8 {
/** Shift bits to the right. All bits are shifted (including sign bit) */
mutating func shiftRight(count: UInt8) -> UInt8 {
if (self == 0) {
return self;
}
let bitsCount = UInt8(sizeof(UInt8) * 8)
if (count >= bitsCount) {
return 0
}
let maxBitsForValue = UInt8(floor(log2(Double(self) + 1)))
let shiftCount = Swift.min(count, maxBitsForValue - 1)
var shiftedValue:UInt8 = 0;
for bitIdx in 0..<bitsCount {
let byte = 1 << bitIdx
if ((self & byte) == byte) {
shiftedValue = shiftedValue | (byte >> shiftCount)
}
}
self = shiftedValue
return self
}
}
/** shift right and assign with bits truncation */
func &>> (lhs: UInt8, rhs: UInt8) -> UInt8 {
var l = lhs;
l.shiftRight(rhs)
return l
}

View File

@ -1,80 +0,0 @@
//
// Utils.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 26/08/14.
// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//
func rotateLeft(v:UInt8, _ n:UInt8) -> UInt8 {
return ((v << n) & 0xFF) | (v >> (8 - n))
}
func rotateLeft(v:UInt16, _ n:UInt16) -> UInt16 {
return ((v << n) & 0xFFFF) | (v >> (16 - n))
}
func rotateLeft(v:UInt32, _ n:UInt32) -> UInt32 {
return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n))
}
func rotateLeft(x:UInt64, _ n:UInt64) -> UInt64 {
return (x << n) | (x >> (64 - n))
}
func rotateRight(x:UInt16, n:UInt16) -> UInt16 {
return (x >> n) | (x << (16 - n))
}
func rotateRight(x:UInt32, n:UInt32) -> UInt32 {
return (x >> n) | (x << (32 - n))
}
func rotateRight(x:UInt64, n:UInt64) -> UInt64 {
return ((x >> n) | (x << (64 - n)))
}
func reverseBytes(value: UInt32) -> UInt32 {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);
}
func toUInt32Array(slice: ArraySlice<UInt8>) -> Array<UInt32> {
var result = Array<UInt32>()
result.reserveCapacity(16)
for idx in slice.startIndex.stride(to: slice.endIndex, by: sizeof(UInt32)) {
let val1:UInt32 = (UInt32(slice[idx.advancedBy(3)]) << 24)
let val2:UInt32 = (UInt32(slice[idx.advancedBy(2)]) << 16)
let val3:UInt32 = (UInt32(slice[idx.advancedBy(1)]) << 8)
let val4:UInt32 = UInt32(slice[idx])
let val:UInt32 = val1 | val2 | val3 | val4
result.append(val)
}
return result
}
func toUInt64Array(slice: ArraySlice<UInt8>) -> Array<UInt64> {
var result = Array<UInt64>()
result.reserveCapacity(32)
for idx in slice.startIndex.stride(to: slice.endIndex, by: sizeof(UInt64)) {
var val:UInt64 = 0
val |= UInt64(slice[idx.advancedBy(7)]) << 56
val |= UInt64(slice[idx.advancedBy(6)]) << 48
val |= UInt64(slice[idx.advancedBy(5)]) << 40
val |= UInt64(slice[idx.advancedBy(4)]) << 32
val |= UInt64(slice[idx.advancedBy(3)]) << 24
val |= UInt64(slice[idx.advancedBy(2)]) << 16
val |= UInt64(slice[idx.advancedBy(1)]) << 8
val |= UInt64(slice[idx.advancedBy(0)]) << 0
result.append(val)
}
return result
}
func xor(a: [UInt8], _ b:[UInt8]) -> [UInt8] {
var xored = [UInt8](count: min(a.count, b.count), repeatedValue: 0)
for i in 0..<xored.count {
xored[i] = a[i] ^ b[i]
}
return xored
}

View File

@ -1,20 +0,0 @@
PODS:
- CryptoSwift (0.3)
- SwiftDDP (0.2.2):
- CryptoSwift (~> 0.3)
- SwiftWebSocket (~> 2.6.0)
- XCGLogger
- SwiftWebSocket (2.6.0)
- XCGLogger (3.2)
DEPENDENCIES:
- SwiftDDP (~> 0.2.2)
- XCGLogger
SPEC CHECKSUMS:
CryptoSwift: 19d29910d88440fcb132761d9ab57e175f1b0d0e
SwiftDDP: 100a5ab2c7b5263009c65683ae6e6e426df72492
SwiftWebSocket: c24c0dde0b33852f478ffb54226408bfe703b26b
XCGLogger: da1f341f4bb8979db6e1df64232f04d9698402d4
COCOAPODS: 0.39.0

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,326 +0,0 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [SwiftDDP](#swiftddp)
- [A client for Meteor servers, written in Swift](#a-client-for-meteor-servers-written-in-swift)
- [License](#license)
- [Changelog](#changelog)
- [0.2.1:](#021)
- [0.2.0:](#020)
- [Installation](#installation)
- [Documentation](#documentation)
- [Quick Start](#quick-start)
- [Setting basic configuration options](#setting-basic-configuration-options)
- [Connecting to a Meteor server](#connecting-to-a-meteor-server)
- [Login & Logout with Facebook, Twitter, etc. (beta)](#login-&-logout-with-facebook-twitter-etc-beta)
- [Gotchas and implementation notes for OAuth login flows](#gotchas-and-implementation-notes-for-oauth-login-flows)
- [Login & Logout with password](#login-&-logout-with-password)
- [Subscribe to a subset of a collection on the server](#subscribe-to-a-subset-of-a-collection-on-the-server)
- [Call a method on the server](#call-a-method-on-the-server)
- [Simple in-memory persistence](#simple-in-memory-persistence)
- [Example Projects](#example-projects)
- [Todos](#todos)
- [Example: Creating an array based custom collection](#example-creating-an-array-based-custom-collection)
- [The following pattern can be used to create custom collections backed by any datastore](#the-following-pattern-can-be-used-to-create-custom-collections-backed-by-any-datastore)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# SwiftDDP
## A client for Meteor servers, written in Swift
#### License
MIT
[![Version](https://img.shields.io/cocoapods/v/SwiftDDP.svg?style=flat)](http://cocoapods.org/pods/SwiftDDP)
[![License](https://img.shields.io/cocoapods/l/SwiftDDP.svg?style=flat)](http://cocoapods.org/pods/SwiftDDP)
[![Platform](https://img.shields.io/cocoapods/p/SwiftDDP.svg?style=flat)](http://cocoapods.org/pods/SwiftDDP)
## Changelog
### 0.2.1:
- Reconnection behavior improvements: reconnect attempts now follow an exponential backoff pattern
- Client now connects to servers using self signed SSL certificates when allowSelfSignedSSL is set to true
- The loglevel can now be set directly using the logLevel property on the client. The default setting is .None
### 0.2.0:
- Integration with Meteor's Facebook, Twitter & other login services.
## Installation
Install using [Carthage](https://github.com/Carthage/Carthage) by adding the following line to your Cartfile:
```ruby
github "siegesmund/SwiftDDP" ~> 0.2.1
```
Or, use [CocoaPods](http://cocoapods.org). Add the following line to your Podfile:
```ruby
pod "SwiftDDP", "~> 0.2.1"
```
## Documentation
###[API Reference](https://siegesmund.github.io/SwiftDDP)
### Quick Start
#### Setting basic configuration options
```swift
import SwiftDDP
Meteor.client.allowSelfSignedSSL = true // Connect to a server that uses a self signed ssl certificate
Meteor.client.logLevel = .Info // Options are: .Verbose, .Debug, .Info, .Warning, .Error, .Severe, .None
```
#### Connecting to a Meteor server
```swift
// Meteor.connect will automatically connect and will sign in using
// a stored login token if the client was previously signed in.
Meteor.connect("wss://todos.meteor.com/websocket") {
// do something after the client connects
}
```
#### Login & Logout with Facebook, Twitter, etc. (beta)
These services use the standard Meteor accounts packages. Just add the appropriate package on the server (e.g. ```meteor add accounts-facebook```) and follow the web-based provider setup. Choose redirect, rather than popup and save your appId/clientId as you'll need it again in your iOS application.
In your iOS app, create a UIButton and associate its' action with the appropriate Meteor login method. That's it!
```swift
class ViewController: UIViewController {
// client id is the id that Facebook, Google etc. assigns your app.
let GITHUB_CLIENT_ID = "1234567890"
let FACEBOOK_CLIENT_ID = "qwertyuiop"
let GOOGLE_CLIENT_ID = "asdfghjkl"
// Note that Twitter does not require a client id
@IBAction func loginWithTwitterWasClicked(sender: UIButton) {
Meteor.loginWithTwitter(self)
}
@IBAction func loginWithFacebookWasClicked(sender: UIButton) {
Meteor.loginWithFacebook(FACEBOOK_CLIENT_ID, viewController: self)
}
@IBAction func loginWithGoogleWasClicked(sender: UIButton) {
Meteor.loginWithGoogle(GOOGLE_CLIENT_ID, viewController: self)
}
@IBAction func loginWithGithubWasClicked(sender: UIButton) {
Meteor.loginWithGithub(GITHUB_CLIENT_ID, viewController: self)
}
}
```
#### Gotchas and implementation notes for OAuth login flows
When configuring OAuth services
* If you connect over wss (as you should), then you must provide a https:// app url and redirect url to the service provider. If you connect over ws, you must use http:// for your app url and redirect url. In other words, you can't mix the two.
* You'll need to choose redirect rather than popup in the Meteor OAuth configuration dialog
* Once configured, Meteor provides the appId/clientId via the "meteor.loginServiceConfiguration" publication, which SwiftDDP automatically subscribes to. However, SwiftDDP currently requires that you explicitly provide the appId as this allows the user to begin logging in immediately, rather than waiting for the initial batch of subscriptions to finish.
#### Login & Logout with password
```swift
Meteor.loginWithPassword("user@swiftddp.com", password: "********") { result, error in
// do something after login
}
Meteor.logout() { result, error in
// do something after logout
}
```
The client also posts a notification when the user signs in and signs out.
```swift
// Notification name (a string global variable)
DDP_USER_DID_LOGIN
DDP_USER_DID_LOGOUT
// Example
NSNotificationCenter.defaultCenter().addObserver(self, selector: "userDidLogin", name: DDP_USER_DID_LOGIN, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "userDidLogout", name: DDP_USER_DID_LOGOUT, object: nil)
func userDidLogin() {
print("The user just signed in!")
}
func userDidLogout() {
print("The user just signed out!")
}
```
#### Subscribe to a subset of a collection on the server
```swift
Meteor.subscribe("todos")
Meteor.subscribe("todos") {
// Do something when the todos subscription is ready
}
Meteor.subscribe("todos", [1,2,3,4]) {
// Do something when the todos subscription is ready
}
```
#### Call a method on the server
```swift
Meteor.call("foo", [1, 2, 3, 4]) { result, error in
// Do something with the method result
}
```
When passing parameters to a server method, the parameters object must be serializable with NSJSONSerialization
#### Simple in-memory persistence
SwiftDDP includes a class called MeteorCollection that provides simple, ephemeral dictionary backed persistence. MeteorCollection stores objects subclassed from MeteorDocument. Creating a collection is as simple as:
```swift
class List: MeteorDocument {
var collection:String = "lists"
var name:String?
var userId:String?
}
let lists = MeteorCollection<List>(name: "lists") // As with Meteorjs, the name is the name of the server-side collection
Meteor.subscribe("lists")
```
For client side insertions, updates and removals:
```swift
let list = List(id: Meteor.client.getId(), fields: ["name": "foo"])
// Insert the object on both the client and server.
lists.insert(list)
// Update the object on both the client and server
list.name = "bar"
lists.update(list)
// Remove the object on both the client and server
lists.remove(list)
```
For each operation the action is executed on the client, and rolled back if the server returns an error.
## Example Projects
#### Todos
These are iOS implementations of [Meteor's Todos example](https://www.meteor.com/todos). The best way to run the examples is to connect to a local instance of Meteor's Todos app: ``` meteor create --example todos && cd todos && meteor ```. You can specify the server that the Todos app connects to by changing the url variable in AppDelegate.swift. There are currently two flavors: a simple example with dictionary based persistence and an example showing how to use SwiftDDP with Core Data and NSFetchedResultsController.
- [Meteor Todos with dictionary based in-memory storage](https://github.com/siegesmund/SwiftDDP/tree/master/Examples/Dictionary)
- [Meteor Todos Core Data integration](https://github.com/siegesmund/SwiftDDP/tree/master/Examples/CoreData)
When running the examples with preexisting instances of the todos app hosted at *.meteor.com, note that connectivity to apps hosted on Meteor's free hosting (not to be confused with Galaxy) can be erratic as the server periodically idles. If SwiftTodos does not connect or you cannot add or remove items or login, try connecting to a different instance. The surest way to do this is to run an instance of the todos app locally.
```bash meteor create --example todos```
Once you've created and started the Meteor todos server, set the url variable in AppDelegate.swift to ws://localhost:3000/websocket, then run the iOS app.
## Example: Creating an array based custom collection
#### The following pattern can be used to create custom collections backed by any datastore
In this example, we'll create a simple collection to hold a list of contacts. The first thing we'll do is create an object to represent a contact. This object has four properties and a method named *update* that maps the *fields* NSDictionary to the struct's properties. *Update* is called when an object is created and when an update is performed. Meteor will always transmit an **id** to identify the object that should be added, updated or removed, so objects that represent Meteor documents must **always** have an id field. Here we're sticking to the MongoDB convention of naming our id *_id*.
```swift
struct Contact {
var _id:String?
var name:String?
var phone:String?
var email:String?
init(id:String, fields:NSDictionary?) {
self._id = id
update(fields)
}
mutating func update(fields:NSDictionary?) {
if let name = fields?.valueForKey("name") as? String {
self.name = name
}
if let phone = fields?.valueForKey("phone") as? String {
self.phone = phone
}
if let email = fields?.valueForKey("email") as? String {
self.email = email
}
}
}
```
Next, we'll create the collection class that will hold our contacts and provide the logic to respond to server-side changes to the documents and the subscription set. SwiftDDP contains an abstract class called AbstractCollection that can be used to build custom collections. Subclassing AbstractCollection allows you to override three methods that are called in response to events on the server: *documentWasAdded*, *documentWasChanged* and *documentWasRemoved*.
```swift
class UserCollection: AbstractCollection {
var contacts = [Contact]()
// Include any logic that needs to occur when a document is added to the collection on the server
override public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
let user = User(id, fields)
users.append(user)
}
// Include any logic that needs to occur when a document is changed on the server
override public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
if let index = contacts.indexOf({ contact in return contact._id == id }) {
contact = contacts[index]
contact.update(fields)
contacts[index] = contact
}
}
// Include any logic that needs to occur when a document is removed on the server
override public func documentWasRemoved(collection:String, id:String) {
if let index = contacts.indexOf({ contact in return contact._id == id }) {
contacts[index] = nil
}
}
}
```
So far, we're able to process documents that have been added, changed or removed on the server. But the UserCollection class still lacks the ability to make changes to both the local datastore and on the server. We'll change that. In the UserCollection class, create a method called insert.
```swift
class UserCollection: AbstractCollection {
/*
override public func documentWasAdded ...
override public func documentWasChanged ...
override public func documentWasRemoved ...
*/
public func insert(contact: Contact) {
// (1) save the document to the contacts array
contacts[contacts._id] = contact
// (2) now try to insert the document on the server
client.insert(self.name, document: [contacts.fields()]) { result, error in
// (3) However, if the server returns an error, reverse the action on the client by
// removing the document from the contacts collection
if error != nil {
self.contacts[contact._id] = nil
log.error("\(error!)")
}
}
}
}
```
The key parts of this method are:
- (1) save the new contact to the array we created in UserCollection
- (2) invoke client.insert to initiate an insert on the server
- (3) remove the contact from the local store if the server rejects the insert
Creating update and remove methods are also easy to create, and follow the same patern as insert. For a more extensive example of the patterns shown here, have a look at [MeteorCollection.swift](https://github.com/siegesmund/SwiftDDP/blob/master/SwiftDDP/MeteorCollection.swift). MeteorCollection is an in-memory collection implementation suitable for simple applications.

View File

@ -1,590 +0,0 @@
//
//
// A DDP Client written in Swift
//
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software uses CryptoSwift: https://github.com/krzyzanowskim/CryptoSwift/
//
import Foundation
import SwiftWebSocket
import XCGLogger
let log = XCGLogger(identifier: "DDP")
public typealias DDPMethodCallback = (result:AnyObject?, error:DDPError?) -> ()
public typealias DDPConnectedCallback = (session:String) -> ()
public typealias DDPCallback = () -> ()
/**
DDPDelegate provides an interface to react to user events
*/
public protocol SwiftDDPDelegate {
func ddpUserDidLogin(user:String)
func ddpUserDidLogout(user:String)
}
/**
DDPClient is the base class for communicating with a server using the DDP protocol
*/
public class DDPClient: NSObject {
// included for storing login id and token
internal let userData = NSUserDefaults.standardUserDefaults()
let background: NSOperationQueue = {
let queue = NSOperationQueue()
queue.name = "DDP Background Data Queue"
queue.qualityOfService = .Background
return queue
}()
// Callbacks execute in the order they're received
internal let callbackQueue: NSOperationQueue = {
let queue = NSOperationQueue()
queue.name = "DDP Callback Queue"
queue.maxConcurrentOperationCount = 1
queue.qualityOfService = .UserInitiated
return queue
}()
// Document messages are processed in the order that they are received,
// separately from callbacks
internal let documentQueue: NSOperationQueue = {
let queue = NSOperationQueue()
queue.name = "DDP Background Queue"
queue.maxConcurrentOperationCount = 1
queue.qualityOfService = .Background
return queue
}()
// Hearbeats get a special queue so that they're not blocked by
// other operations, causing the connection to close
internal let heartbeat: NSOperationQueue = {
let queue = NSOperationQueue()
queue.name = "DDP Heartbeat Queue"
queue.qualityOfService = .Utility
return queue
}()
let userBackground: NSOperationQueue = {
let queue = NSOperationQueue()
queue.name = "DDP High Priority Background Queue"
queue.qualityOfService = .UserInitiated
return queue
}()
let userMainQueue: NSOperationQueue = {
let queue = NSOperationQueue.mainQueue()
queue.name = "DDP High Priorty Main Queue"
queue.qualityOfService = .UserInitiated
return queue
}()
private var socket:WebSocket!{
didSet{ socket.allowSelfSignedSSL = self.allowSelfSignedSSL }
}
private var server:(ping:NSDate?, pong:NSDate?) = (nil, nil)
internal var resultCallbacks:[String:Completion] = [:]
internal var subCallbacks:[String:Completion] = [:]
internal var unsubCallbacks:[String:Completion] = [:]
public var url:String!
private var subscriptions = [String:(id:String, name:String, ready:Bool)]()
internal var events = DDPEvents()
internal var connection:(ddp:Bool, session:String?) = (false, nil)
public var delegate:SwiftDDPDelegate?
// MARK: Settings
/**
Boolean value that determines whether the
*/
public var allowSelfSignedSSL:Bool = false {
didSet{
guard let currentSocket = socket else { return }
currentSocket.allowSelfSignedSSL = allowSelfSignedSSL
}
}
/**
Sets the log level. The default value is .None.
Possible values: .Verbose, .Debug, .Info, .Warning, .Error, .Severe, .None
*/
public var logLevel = XCGLogger.LogLevel.None {
didSet {
log.setup(logLevel, showLogIdentifier: true, showFunctionName: true, showThreadName: true, showLogLevel: true, showFileNames: false, showLineNumbers: true, showDate: false, writeToFile: nil, fileLogLevel: .None)
}
}
internal override init() {
super.init()
}
/**
Creates a random String id
*/
public func getId() -> String {
let numbers = Set<Character>(["0","1","2","3","4","5","6","7","8","9"])
let uuid = NSUUID().UUIDString.stringByReplacingOccurrencesOfString("-", withString: "")
var id = ""
for character in uuid.characters {
if (!numbers.contains(character) && (round(Float(arc4random()) / Float(UINT32_MAX)) == 1)) {
id += String(character).lowercaseString
} else {
id += String(character)
}
}
return id
}
/**
Makes a DDP connection to the server
- parameter url: The String url to connect to, ex. "wss://todos.meteor.com/websocket"
- parameter callback: A closure that takes a String argument with the value of the websocket session token
*/
public func connect(url:String, callback:DDPConnectedCallback?) {
self.url = url
// capture the thread context in which the function is called
let executionQueue = NSOperationQueue.currentQueue()
socket = WebSocket(url)
//Create backoff
let backOff:DDPExponentialBackoff = DDPExponentialBackoff()
socket.event.close = {code, reason, clean in
//Use backoff to slow reconnection retries
backOff.createBackoff({
log.info("Web socket connection closed with code \(code). Clean: \(clean). \(reason)")
let event = self.socket.event
self.socket = WebSocket(url)
self.socket.event = event
self.ping()
})
}
socket.event.error = events.onWebsocketError
socket.event.open = {
self.heartbeat.addOperationWithBlock() {
// Add a subscription to loginServices to each connection event
let callbackWithServiceConfiguration = { (session:String) in
// let loginServicesSubscriptionCollection = "meteor_accounts_loginServiceConfiguration"
let loginServiceConfiguration = "meteor.loginServiceConfiguration"
self.sub(loginServiceConfiguration, params: nil) // /tools/meteor-services/auth.js line 922
// Resubscribe to existing subs on connection to ensure continuity
self.subscriptions.forEach({ (subscription: (String, (id: String, name: String, ready: Bool))) -> () in
if subscription.1.name != loginServiceConfiguration {
self.sub(subscription.1.id, name: subscription.1.name, params: nil, callback: nil)
}
})
callback?(session: session)
}
var completion = Completion(callback: callbackWithServiceConfiguration)
//Reset the backoff to original values
backOff.reset()
completion.executionQueue = executionQueue
self.events.onConnected = completion
self.sendMessage(["msg":"connect", "version":"1", "support":["1"]])
}
}
socket.event.message = { message in
self.background.addOperationWithBlock() {
if let text = message as? String {
do { try self.ddpMessageHandler(DDPMessage(message: text)) }
catch { log.debug("Message handling error. Raw message: \(text)")}
}
}
}
}
private func ping() {
heartbeat.addOperationWithBlock() {
self.sendMessage(["msg":"ping", "id":self.getId()])
}
}
// Respond to a server ping
private func pong(ping: DDPMessage) {
heartbeat.addOperationWithBlock() {
self.server.ping = NSDate()
var response = ["msg":"pong"]
if let id = ping.id { response["id"] = id }
self.sendMessage(response)
}
}
// Parse DDP messages and dispatch to the appropriate function
internal func ddpMessageHandler(message: DDPMessage) throws {
log.debug("Received message: \(message.json)")
switch message.type {
case .Connected:
self.connection = (true, message.session!)
self.events.onConnected.execute(message.session!)
case .Result: callbackQueue.addOperationWithBlock() {
if let id = message.id, // Message has id
let completion = self.resultCallbacks[id], // There is a callback registered for the message
let result = message.result {
completion.execute(result, error: message.error)
self.resultCallbacks[id] = nil
} else if let id = message.id,
let completion = self.resultCallbacks[id] {
completion.execute(nil, error:message.error)
self.resultCallbacks[id] = nil
}
}
// Principal callbacks for managing data
// Document was added
case .Added: documentQueue.addOperationWithBlock() {
if let collection = message.collection,
let id = message.id {
self.documentWasAdded(collection, id: id, fields: message.fields)
}
}
// Document was changed
case .Changed: documentQueue.addOperationWithBlock() {
if let collection = message.collection,
let id = message.id {
self.documentWasChanged(collection, id: id, fields: message.fields, cleared: message.cleared)
}
}
// Document was removed
case .Removed: documentQueue.addOperationWithBlock() {
if let collection = message.collection,
let id = message.id {
self.documentWasRemoved(collection, id: id)
}
}
// Notifies you when the result of a method changes
case .Updated: documentQueue.addOperationWithBlock() {
if let methods = message.methods {
self.methodWasUpdated(methods)
}
}
// Callbacks for managing subscriptions
case .Ready: documentQueue.addOperationWithBlock() {
if let subs = message.subs {
self.ready(subs)
}
}
// Callback that fires when subscription has been completely removed
//
case .Nosub: documentQueue.addOperationWithBlock() {
if let id = message.id {
self.nosub(id, error: message.error)
}
}
case .Ping: heartbeat.addOperationWithBlock() { self.pong(message) }
case .Pong: heartbeat.addOperationWithBlock() { self.server.pong = NSDate() }
case .Error: background.addOperationWithBlock() {
self.didReceiveErrorMessage(DDPError(json: message.json))
}
default: log.error("Unhandled message: \(message.json)")
}
}
private func sendMessage(message:NSDictionary) {
if let m = message.stringValue() {
self.socket.send(m)
}
}
/**
Executes a method on the server. If a callback is passed, the callback is asynchronously
executed when the method has completed. The callback takes two arguments: result and error. It
the method call is successful, result contains the return value of the method, if any. If the method fails,
error contains information about the error.
- parameter name: The name of the method
- parameter params: An object containing method arguments, if any
- parameter callback: The closure to be executed when the method has been executed
*/
public func method(name: String, params: AnyObject?, callback: DDPMethodCallback?) -> String {
let id = getId()
let message = ["msg":"method", "method":name, "id":id] as NSMutableDictionary
if let p = params { message["params"] = p }
if let completionCallback = callback {
let completion = Completion(callback: completionCallback)
self.resultCallbacks[id] = completion
}
userBackground.addOperationWithBlock() {
self.sendMessage(message)
}
return id
}
//
// Subscribe
//
internal func sub(id: String, name: String, params: [AnyObject]?, callback: DDPCallback?) -> String {
if let completionCallback = callback {
let completion = Completion(callback: completionCallback)
self.subCallbacks[id] = completion
}
self.subscriptions[id] = (id, name, false)
let message = ["msg":"sub", "name":name, "id":id] as NSMutableDictionary
if let p = params { message["params"] = p }
userBackground.addOperationWithBlock() {
self.sendMessage(message)
}
return id
}
/**
Sends a subscription request to the server.
- parameter name: The name of the subscription
- parameter params: An object containing method arguments, if any
*/
public func sub(name: String, params: [AnyObject]?) -> String {
let id = String(name.hashValue)
return sub(id, name: name, params: params, callback:nil)
}
/**
Sends a subscription request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the initial subset of documents contained
in the subscription has been sent by the server.
- parameter name: The name of the subscription
- parameter params: An object containing method arguments, if any
- parameter callback: The closure to be executed when the server sends a 'ready' message
*/
public func sub(name:String, params: [AnyObject]?, callback: DDPCallback?) -> String {
let id = String(name.hashValue)
if let subData = findSubscription(name) {
log.info("You are already subscribed to \(name)")
return subData.id
}
return sub(id, name: name, params: params, callback: callback)
}
// Iterates over the Dictionary of subscriptions to find a subscription by name
internal func findSubscription(name:String) -> (id:String, name:String, ready:Bool)? {
for subscription in subscriptions.values {
if (name == subscription.name) {
return subscription
}
}
return nil
}
//
// Unsubscribe
//
/**
Sends an unsubscribe request to the server.
- parameter name: The name of the subscription
*/
public func unsub(name: String) -> String? {
return unsub(name, callback: nil)
}
/**
Sends an unsubscribe request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the subset of documents contained
in the subscription have been removed.
- parameter name: The name of the subscription
- parameter callback: The closure to be executed when the server sends a 'ready' message
*/
public func unsub(name: String, callback: DDPCallback?) -> String? {
if let sub = findSubscription(name) {
unsub(withId: sub.id, callback: callback)
background.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":sub.id]) }
return sub.id
}
return nil
}
internal func unsub(withId id: String, callback: DDPCallback?) {
if let completionCallback = callback {
let completion = Completion(callback: completionCallback)
unsubCallbacks[id] = completion
}
background.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":id]) }
}
//
// Responding to server subscription messages
//
private func ready(subs: [String]) {
for id in subs {
if let completion = subCallbacks[id] {
completion.execute() // Run the callback
subCallbacks[id] = nil // Delete the callback after running
} else { // If there is no callback, execute the method
if var sub = subscriptions[id] {
sub.ready = true
subscriptions[id] = sub
subscriptionIsReady(sub.id, subscriptionName: sub.name)
}
}
}
}
private func nosub(id: String, error: DDPError?) {
if let e = error where (e.isValid == true) {
log.error("\(e)")
} else {
if let completion = unsubCallbacks[id],
let _ = subscriptions[id] {
completion.execute()
unsubCallbacks[id] = nil
subscriptions[id] = nil
} else {
if let subscription = subscriptions[id] {
subscriptions[id] = nil
subscriptionWasRemoved(subscription.id, subscriptionName: subscription.name)
}
}
}
}
//
// public callbacks: should be overridden
//
/**
Executes when a subscription is ready.
- parameter subscriptionId: A String representation of the hash of the subscription name
- parameter subscriptionName: The name of the subscription
*/
public func subscriptionIsReady(subscriptionId: String, subscriptionName:String) {}
/**
Executes when a subscription is removed.
- parameter subscriptionId: A String representation of the hash of the subscription name
- parameter subscriptionName: The name of the subscription
*/
public func subscriptionWasRemoved(subscriptionId:String, subscriptionName:String) {}
/**
Executes when the server has sent a new document.
- parameter collection: The name of the collection that the document belongs to
- parameter id: The document's unique id
- parameter fields: The documents properties
*/
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
if let added = events.onAdded { added(collection: collection, id: id, fields: fields) }
}
/**
Executes when the server sends a message to remove a document.
- parameter collection: The name of the collection that the document belongs to
- parameter id: The document's unique id
*/
public func documentWasRemoved(collection:String, id:String) {
if let removed = events.onRemoved { removed(collection: collection, id: id) }
}
/**
Executes when the server sends a message to update a document.
- parameter collection: The name of the collection that the document belongs to
- parameter id: The document's unique id
- parameter fields: Optional object with EJSON values containing the fields to update
- parameter cleared: Optional array of strings (field names to delete)
*/
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
if let changed = events.onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
}
/**
Executes when the server sends a message indicating that the result of a method has changed.
- parameter methods: An array of strings (ids passed to 'method', all of whose writes have been reflected in data messages)
*/
public func methodWasUpdated(methods:[String]) {
if let updated = events.onUpdated { updated(methods: methods) }
}
/**
Executes when the client receives an error message from the server. Such a message is used to represent errors raised by the method or subscription, as well as an attempt to subscribe to an unknown subscription or call an unknown method.
- parameter message: A DDPError object with information about the error
*/
public func didReceiveErrorMessage(message: DDPError) {
if let error = events.onError { error(message: message) }
}
}

View File

@ -1,123 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
DDPEvents is a struct holder for callback closures that execute in response to
websocket and Meteor lifecyle events. New closures can be assigned to public
closures to modify the clients behavior in response to the trigger event.
*/
public struct DDPEvents {
/**
onWebsocketClose executes when the websocket connection has closed
- parameter code: An integer value that provides the reason code for closing the websocket connection
- parameter reason: A string describing the reason that the websocket was closed
- parameter clean: A boolean value indicating if the websocket connection was closed cleanly
*/
internal var onWebsocketClose: ((code:Int, reason:String, clean:Bool) -> ())?
/**
onWebsocketError executes when the websocket connection returns an error.
- parameter error: An ErrorType object describing the error
*/
internal var onWebsocketError: (error:ErrorType) -> () = {error in log.error("websocket error \(error)")}
/**
onConnected executes when the client makes a DDP connection
- parameter session: A string session id
*/
// public var onConnected: (session:String) -> () = {session in log.info("connected with session: \(session)")}
public var onConnected: Completion = Completion(callback: {session in log.info("connected with session: \(session)")})
/**
onDisconnected executes when the client is disconnected
*/
public var onDisconnected: () -> () = {log.debug("disconnected")}
/**
onFailed executes when an attempt to make a DDP connection fails
*/
public var onFailed: () -> () = {log.error("failed")}
// Data messages
/**
onAdded executes when a document has been added to a local collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
*/
public var onAdded: ((collection:String, id:String, fields:NSDictionary?) -> ())?
/**
onChanged executes when the server sends an instruction to modify a local document
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
- parameter cleared: an optional array of string property names to delete
*/
public var onChanged: ((collection:String, id:String, fields:NSDictionary?, cleared:NSArray?) -> ())?
/**
onRemoved executes when the server sends an instruction to remove a document from the local collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
*/
public var onRemoved: ((collection:String, id:String) -> ())?
// RPC Messages
// public var onResult: (json: NSDictionary?, callback:(result:AnyObject?, error:AnyObject?) -> ()) -> () = {json, callback in callback(result: json, error:nil) }
/**
onUpdated executes when the server sends a notification that all the consequences of a method call have
been communicated to the client
- parameter methods: An array of method id strings
*/
public var onUpdated: ((methods: [String]) -> ())?
/**
onError executes when the client receives a DDP error message
- parameter message: A DDPError message describing the error
*/
public var onError: ((message:DDPError) -> ())?
}

View File

@ -1,84 +0,0 @@
//
// DDPExponentialBackoff.swift
//
//
// Created by Joseph Kitchener on 05/02/2016.
// Copyright © 2016 Joseph Kitchener. All rights reserved.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
///Retry connection requests to the server. The retries exponentially increase the waiting time up to a certain threshold. The idea is that if the server is down temporarily, it is not overwhelmed with requests hitting at the same time when it comes back up.
class DDPExponentialBackoff {
init(retryInterval:Double = 0.01,maxWaitInterval:Double = 5,multiplier:Double = 1.5){
self.reconnectionRetryInterval = retryInterval
self._reconnectionRetryInterval = retryInterval
self.maxWaitInterval = maxWaitInterval
self.multiplier = multiplier
}
//Cached original interval time
private var _reconnectionRetryInterval:Double!
private var reconnectionRetryInterval:Double!
private var maxWaitInterval:Double!
private var multiplier:Double!
///Perform a closure with increasing exponential delay time up to a max wait interval
func createBackoff(closure:()->()) {
let previousRetryInterval = self.reconnectionRetryInterval
let newRetryInterval = min(previousRetryInterval * multiplier,maxWaitInterval)
self.reconnectionRetryInterval = previousRetryInterval < maxWaitInterval ? newRetryInterval: maxWaitInterval
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(self.reconnectionRetryInterval * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
// print(reconnectionRetryInterval)
}
//Reset backoff to orignal time
func reset(){
reconnectionRetryInterval = _reconnectionRetryInterval
}
//Sets the backoff
func setBackoff(retryInterval:Double,maxWaitInterval:Double,multiplier:Double){
self.reconnectionRetryInterval = retryInterval
self._reconnectionRetryInterval = retryInterval
self.maxWaitInterval = maxWaitInterval
self.multiplier = multiplier
}
}

View File

@ -1,499 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import CryptoSwift
private let DDP_ID = "DDP_ID"
private let DDP_EMAIL = "DDP_EMAIL"
private let DDP_USERNAME = "DDP_USERNAME"
private let DDP_TOKEN = "DDP_TOKEN"
private let DDP_TOKEN_EXPIRES = "DDP_TOKEN_EXPIRES"
private let DDP_LOGGED_IN = "DDP_LOGGED_IN"
public let DDP_USER_DID_LOGIN = "DDP_USER_DID_LOGIN"
public let DDP_USER_DID_LOGOUT = "DDP_USER_DID_LOGOUT"
let SWIFT_DDP_CALLBACK_DISPATCH_TIME = DISPATCH_TIME_FOREVER
private let syncWarning = {(name:String) -> Void in
if NSThread.isMainThread() {
print("\(name) is running synchronously on the main thread. This will block the main thread and should be run on a background thread")
}
}
extension String {
func dictionaryValue() -> NSDictionary? {
if let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
let dictionary = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) as! NSDictionary
return dictionary
}
return nil
}
}
extension NSDictionary {
func stringValue() -> String? {
if let data = try? NSJSONSerialization.dataWithJSONObject(self, options: NSJSONWritingOptions(rawValue: 0)) {
return NSString(data: data, encoding: NSASCIIStringEncoding) as? String
}
return nil
}
}
/**
Extensions that provide an api for interacting with basic Meteor server-side services
*/
extension DDPClient {
/**
Sends a subscription request to the server.
- parameter name: The name of the subscription
*/
public func subscribe(name:String) -> String { return sub(name, params:nil) }
/**
Sends a subscription request to the server.
- parameter name: The name of the subscription
- parameter params: An object containing method arguments, if any
*/
public func subscribe(name:String, params:[AnyObject]) -> String { return sub(name, params:params) }
/**
Sends a subscription request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the initial subset of documents contained
in the subscription has been sent by the server.
- parameter name: The name of the subscription
- parameter params: An object containing method arguments, if any
- parameter callback: The closure to be executed when the server sends a 'ready' message
*/
public func subscribe(name:String, params:[AnyObject]?, callback: DDPCallback?) -> String { return sub(name, params:params, callback:callback) }
/**
Sends a subscription request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the initial subset of documents contained
in the subscription has been sent by the server.
- parameter name: The name of the subscription
- parameter callback: The closure to be executed when the server sends a 'ready' message
*/
public func subscribe(name:String, callback: DDPCallback?) -> String { return sub(name, params:nil, callback:callback) }
/**
Asynchronously inserts a document into a collection on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to insert
- parameter callback: A closure with result and error arguments describing the result of the operation
*/
public func insert(collection: String, document: NSArray, callback: DDPMethodCallback?) -> String {
let arg = "/\(collection)/insert"
return self.method(arg, params: document, callback: callback)
}
/**
Asynchronously inserts a document into a collection on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to insert
*/
public func insert(collection: String, document: NSArray) -> String {
return insert(collection, document: document, callback:nil)
}
/**
Synchronously inserts a document into a collection on the server. Cannot be used on the main queue.
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to insert
*/
public func insert(sync collection: String, document: NSArray) -> Result {
syncWarning("Insert")
let semaphore = dispatch_semaphore_create(0)
var serverResponse = Result()
insert(collection, document:document) { result, error in
serverResponse.result = result
serverResponse.error = error
dispatch_semaphore_signal(semaphore)
}
dispatch_semaphore_wait(semaphore, SWIFT_DDP_CALLBACK_DISPATCH_TIME)
return serverResponse
}
/**
Asynchronously updates a document into a collection on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to update
- parameter callback: A closure with result and error arguments describing the result of the operation
*/
public func update(collection: String, document: NSArray, callback: DDPMethodCallback?) -> String {
let arg = "/\(collection)/update"
return method(arg, params: document, callback: callback)
}
/**
Asynchronously updates a document on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to update
*/
public func update(collection: String, document: NSArray) -> String {
return update(collection, document: document, callback:nil)
}
/**
Synchronously updates a document on the server. Cannot be used on the main queue
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to update
*/
public func update(sync collection: String, document: NSArray) -> Result {
syncWarning("Update")
let semaphore = dispatch_semaphore_create(0)
var serverResponse = Result()
update(collection, document:document) { result, error in
serverResponse.result = result
serverResponse.error = error
dispatch_semaphore_signal(semaphore)
}
dispatch_semaphore_wait(semaphore, SWIFT_DDP_CALLBACK_DISPATCH_TIME)
return serverResponse
}
/**
Asynchronously removes a document on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to remove
- parameter callback: A closure with result and error arguments describing the result of the operation
*/
public func remove(collection: String, document: NSArray, callback: DDPMethodCallback?) -> String {
let arg = "/\(collection)/remove"
return method(arg, params: document, callback: callback)
}
/**
Asynchronously removes a document into a collection on the server
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to remove
*/
public func remove(collection: String, document: NSArray) -> String {
return remove(collection, document: document, callback:nil)
}
/**
Synchronously removes a document into a collection on the server. Cannot be used on the main queue.
- parameter collection: The name of the collection
- parameter document: An NSArray of documents to remove
*/
public func remove(sync collection: String, document: NSArray) -> Result {
syncWarning("Remove")
let semaphore = dispatch_semaphore_create(0)
var serverResponse = Result()
remove(collection, document:document) { result, error in
serverResponse.result = result
serverResponse.error = error
dispatch_semaphore_signal(semaphore)
}
dispatch_semaphore_wait(semaphore, SWIFT_DDP_CALLBACK_DISPATCH_TIME)
return serverResponse
}
// Callback runs on main thread
public func login(params: NSDictionary, callback: ((result: AnyObject?, error: DDPError?) -> ())?) {
// method is run on the userBackground queue
method("login", params: NSArray(arrayLiteral: params)) { result, error in
guard let e = error where (e.isValid == true) else {
if let user = params["user"],
let email = user["email"] {
self.userData.setObject(email, forKey: DDP_EMAIL)
}
if let data = result as? NSDictionary,
let id = data["id"] as? String,
let token = data["token"] as? String,
let tokenExpires = data["tokenExpires"] as? NSDictionary,
let date = tokenExpires["$date"] as? Int {
let timestamp = NSTimeInterval(Double(date)) / 1000.0
let expiration = NSDate(timeIntervalSince1970: timestamp)
self.userData.setObject(id, forKey: DDP_ID)
self.userData.setObject(token, forKey: DDP_TOKEN)
self.userData.setObject(expiration, forKey: DDP_TOKEN_EXPIRES)
}
self.userMainQueue.addOperationWithBlock() {
if let c = callback { c(result:result, error:error) }
self.userData.setObject(true, forKey: DDP_LOGGED_IN)
NSNotificationCenter.defaultCenter().postNotificationName(DDP_USER_DID_LOGIN, object: nil)
if let _ = self.delegate {
self.delegate!.ddpUserDidLogin(self.user()!)
}
}
return
}
log.debug("Login error: \(e)")
if let c = callback { c(result: result, error: error) }
}
}
/**
Logs a user into the server using an email and password
- parameter email: An email string
- parameter password: A password string
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public func loginWithPassword(email: String, password: String, callback: DDPMethodCallback?) {
if !(loginWithToken(callback)) {
let params = ["user": ["email": email], "password":["digest": password.sha256(), "algorithm":"sha-256"]] as NSDictionary
login(params, callback: callback)
}
}
/**
Attempts to login a user with a token, if one exists
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public func loginWithToken(callback: DDPMethodCallback?) -> Bool {
if let token = userData.stringForKey(DDP_TOKEN),
let tokenDate = userData.objectForKey(DDP_TOKEN_EXPIRES) {
print("Found token & token expires \(token), \(tokenDate)")
if (tokenDate.compare(NSDate()) == NSComparisonResult.OrderedDescending) {
let params = ["resume":token] as NSDictionary
login(params, callback:callback)
return true
}
}
return false
}
public func signup(params:NSDictionary, callback:((result: AnyObject?, error: DDPError?) -> ())?) {
method("createUser", params: NSArray(arrayLiteral: params)) { result, error in
guard let e = error where (e.isValid == true) else {
if let email = params["email"] {
self.userData.setObject(email, forKey: DDP_EMAIL)
}
if let data = result as? NSDictionary,
let id = data["id"] as? String,
let token = data["token"] as? String,
let tokenExpires = data["tokenExpires"] as? NSDictionary,
let date = tokenExpires["$date"] as? Int {
let timestamp = NSTimeInterval(Double(date)) / 1000.0
let expiration = NSDate(timeIntervalSince1970: timestamp)
self.userData.setObject(id, forKey: DDP_ID)
self.userData.setObject(token, forKey: DDP_TOKEN)
self.userData.setObject(expiration, forKey: DDP_TOKEN_EXPIRES)
self.userData.synchronize()
}
if let c = callback { c(result:result, error:error) }
self.userData.setObject(true, forKey: DDP_LOGGED_IN)
return
}
log.debug("login error: \(e)")
if let c = callback { c(result: result, error: error) }
}
}
/**
Invokes a Meteor method to create a user account with a given email and password on the server
*/
public func signupWithEmail(email: String, password: String, callback: ((result:AnyObject?, error:DDPError?) -> ())?) {
let params = ["email":email, "password":["digest":password.sha256(), "algorithm":"sha-256"]]
signup(params, callback: callback)
}
/**
Invokes a Meteor method to create a user account with a given email and password, and a NSDictionary containing a user profile
*/
public func signupWithEmail(email: String, password: String, profile: NSDictionary, callback: ((result:AnyObject?, error:DDPError?) -> ())?) {
let params = ["email":email, "password":["digest":password.sha256(), "algorithm":"sha-256"], "profile":profile]
signup(params, callback: callback)
}
/**
Returns the client userId, if it exists
*/
public func userId() -> String? {
return self.userData.objectForKey(DDP_ID) as? String
}
/**
Returns the client's username or email, if it exists
*/
public func user() -> String? {
if let username = self.userData.objectForKey(DDP_USERNAME) as? String {
return username
} else if let email = self.userData.objectForKey(DDP_EMAIL) as? String {
return email
}
return nil
}
internal func resetUserData() {
self.userData.setObject(false, forKey: DDP_LOGGED_IN)
self.userData.removeObjectForKey(DDP_ID)
self.userData.removeObjectForKey(DDP_EMAIL)
self.userData.removeObjectForKey(DDP_USERNAME)
self.userData.removeObjectForKey(DDP_TOKEN)
self.userData.removeObjectForKey(DDP_TOKEN_EXPIRES)
self.userData.synchronize()
}
/**
Logs a user out and removes their account data from NSUserDefaults
*/
public func logout() {
logout(nil)
}
/**
Logs a user out and removes their account data from NSUserDefaults.
When it completes, it posts a notification: DDP_USER_DID_LOGOUT on the main queue
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public func logout(callback:DDPMethodCallback?) {
method("logout", params: nil) { result, error in
if (error == nil) {
self.userMainQueue.addOperationWithBlock() {
let user = self.user()!
NSNotificationCenter.defaultCenter().postNotificationName(DDP_USER_DID_LOGOUT, object: nil)
if let _ = self.delegate {
self.delegate!.ddpUserDidLogout(user)
}
self.resetUserData()
}
} else {
log.error("\(error)")
}
if let c = callback { c(result: result, error: error) }
}
}
/**
Automatically attempts to resume a prior session, if one exists
- parameter url: The server url
*/
public func resume(url:String, callback:DDPCallback?) {
connect(url) { session in
if let _ = self.user() {
self.loginWithToken() { result, error in
if error == nil {
log.debug("Resumed previous session at launch")
if let completion = callback { completion() }
} else {
self.logout()
log.error("\(error)")
}
}
} else {
if let completion = callback { completion() }
}
}
}
/**
Connects and logs in with an email address and password in one action
- parameter url: String url, ex. wss://todos.meteor.com/websocket
- parameter email: String email address
- parameter password: String password
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public convenience init(url: String, email: String, password: String, callback: DDPMethodCallback?) {
self.init()
connect(url) { session in
self.loginWithPassword(email, password: password, callback:callback)
}
}
/**
Returns true if the user is logged in, and false otherwise
*/
public func loggedIn() -> Bool {
if let userLoggedIn = self.userData.objectForKey(DDP_LOGGED_IN) as? Bool where (userLoggedIn == true) {
return true
}
return false
}
}

View File

@ -1,341 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
Enum value representing the types of DDP messages that the server can send
*/
// Handled Message Types
public enum DDPMessageType:String {
// case Connect = "connect" // (client -> server)
case Connected = "connected"
case Failed = "failed"
case Ping = "ping"
case Pong = "pong"
// case Sub = "sub" // (client -> server)
// case Unsub = "unsub" // (client -> server)
case Nosub = "nosub"
case Added = "added"
case Changed = "changed"
case Removed = "removed"
case Ready = "ready"
case AddedBefore = "addedBefore"
case MovedBefore = "movedBefore"
// case Method = "method" // (client -> server)
case Result = "result"
case Updated = "updated"
case Error = "error"
case Unhandled = "unhandled"
}
// Method or Nosub error
// Such an Error is used to represent errors raised by the method or subscription,
// as well as an attempt to subscribe to an unknown subscription or call an unknown method.
// Other erroneous messages sent from the client to the server can result in receiving a top-level msg: 'error' message in response. These conditions include:
// - sending messages which are not valid JSON objects
// - unknown msg type
// - other malformed client requests (not including required fields)
// - sending anything other than connect as the first message, or sending connect as a non-initial message
// The error message contains the following fields:
// - reason: string describing the error
// - offendingMessage: if the original message parsed properly, it is included here
/**
A struct to parse, encapsulate and facilitate handling of DDP message strings
*/
public struct DDPMessage {
/**
The message's properties, stored as an NSDictionary
*/
public var json:NSDictionary!
/**
Initialize a message struct, with a Json string
*/
public init(message:String) {
if let JSON = message.dictionaryValue() { json = JSON }
else {
json = ["msg":"error", "reason":"SwiftDDP JSON serialization error.",
"details": "SwiftDDP JSON serialization error. JSON string was: \(message). Message will be handled as a DDP message error."]
}
}
/**
Initialize a message struct, with a dictionary of strings
*/
public init(message:[String:String]) {
json = message as NSDictionary
}
/**
Converts an NSDictionary to a JSON string
*/
public static func toString(json:AnyObject) -> String? {
if let data = try? NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions(rawValue: 0)) {
let message = NSString(data: data, encoding: NSASCIIStringEncoding) as String?
return message
}
return nil
}
//
// Computed variables
//
/**
Returns the DDP message type, of type DDPMessageType enum
*/
public var type:DDPMessageType {
if let msg = message,
let type = DDPMessageType(rawValue: msg) {
return type
}
return DDPMessageType(rawValue: "unhandled")!
}
/**
Returns a boolean value indicating if the message is an error message or not
*/
public var isError:Bool {
if (self.type == .Error) { return true } // if message is a top level error ("msg"="error")
if let _ = self.error { return true } // if message contains an error object, as in method or nosub
return false
}
// Returns the root-level keys of the JSON object
internal var keys:[String] {
return json.allKeys as! [String]
}
public func hasProperty(name:String) -> Bool {
if let property = json[name] where ((property as! NSObject) != NSNull()) {
return true
}
return false
}
/**
The optional DDP message
*/
public var message:String? {
get { return json["msg"] as? String }
}
/**
The optional DDP session string
*/
public var session:String? {
get { return json["session"] as? String }
}
/**
The optional DDP version string
*/
public var version:String? {
get { return json["version"] as? String }
}
/**
The optional DDP support string
*/
public var support:String? {
get { return json["support"] as? String }
}
/**
The optional DDP message id string
*/
public var id:String? {
get { return json["id"] as? String }
}
/**
The optional DDP name string
*/
public var name:String? {
get { return json["name"] as? String }
}
/**
The optional DDP param string
*/
public var params:String? {
get { return json["params"] as? String }
}
/**
The optional DDP error object
*/
public var error:DDPError? {
get { if let e = json["error"] as? NSDictionary { return DDPError(json:e) } else { return nil }}
}
/**
The optional DDP collection name string
*/
public var collection:String? {
get { return json["collection"] as? String }
}
/**
The optional DDP fields dictionary
*/
public var fields:NSDictionary? {
get { return json["fields"] as? NSDictionary }
}
/**
The optional DDP cleared array. Contains an array of fields that should be removed
*/
public var cleared:[String]? {
get { return json["cleared"] as? [String] }
}
/**
The optional method name
*/
public var method:String? {
get { return json["method"] as? String }
}
/**
The optional random seed JSON value (an arbitrary client-determined seed for pseudo-random generators)
*/
public var randomSeed:String? {
get { return json["randomSeed"] as? String }
}
/**
The optional result object, containing the result of a method call
*/
public var result:AnyObject? {
get { return json["result"] }
}
/**
The optional array of ids passed to 'method', all of whose writes have been reflected in data messages)
*/
public var methods:[String]? {
get { return json["methods"] as? [String] }
}
/**
The optional array of id strings passed to 'sub' which have sent their initial batch of data
*/
public var subs:[String]? {
get { return json["subs"] as? [String] }
}
/**
The optional reason given for an error returned from the server
*/
public var reason:String? {
get { return json["reason"] as? String }
}
/**
The optional original error message
*/
public var offendingMessage:String? {
get { return json["offendingMessage"] as? String }
}
}
/**
A struct encapsulating a DDP error message
*/
public struct DDPError: ErrorType {
private var json:NSDictionary?
/**
The string error code
*/
public var error:String? { return json?["error"] as? String } // Error code
/**
The detailed message given for an error returned from the server
*/
public var reason:String? { return json?["reason"] as? String }
/**
The string providing error details
*/
public var details:String? { return json?["details"] as? String }
/**
If the original message parsed properly, it is included here
*/
public var offendingMessage:String? { return json?["offendingMessage"] as? String }
/**
Helper variable that returns true if the struct has both an error code and a reason
*/
var isValid:Bool {
if let _ = error { return true }
if let _ = reason { return true }
return false
}
init(json:AnyObject?) {
self.json = json as? NSDictionary
}
}

View File

@ -1,40 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
/**
Struct to encapsulate the result of a Meteor method call
*/
public struct Result {
/**
The result of the method call
*/
public var result:AnyObject?
/**
An error object describing the server-side error, or nil if the method completed successfully
*/
public var error:DDPError?
}

View File

@ -1,67 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// Base64
func randomBase64String(n: Int = 20) -> String {
var string = ""
let BASE64_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
for _ in 1...n {
let r = arc4random() % UInt32(BASE64_CHARS.characters.count)
let index = BASE64_CHARS.startIndex.advancedBy(Int(r))
let c = BASE64_CHARS[index]
string += String(c)
}
return string
}
func toBase64(string: String) -> String {
let encodedData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let base64String = encodedData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return base64String as String
}
func fromBase64(string: String) -> String {
let decodedData = NSData(base64EncodedString: string, options: NSDataBase64DecodingOptions(rawValue: 0))
let decodedString = NSString(data: decodedData!, encoding: NSUTF8StringEncoding)
return decodedString as! String
}
// URL Parsing
// Returns a dictionary of arguments
func getArguments(fromUrl url: String) -> [String:String] {
var componentsDictionary:[String:String] = [:]
let components = NSURLComponents(string: url)
components?.queryItems?.forEach { item in componentsDictionary[item.name] = item.value }
return componentsDictionary
}
func getValue(fromUrl url: String, forArgument argument:String) -> String? {
let arguments = getArguments(fromUrl: url)
print("Arguments \(arguments) for url: \(url)")
return arguments[argument]
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// {"$date": MILLISECONDS_SINCE_EPOCH} // Dates
// {"$binary": BASE_64_STRING} // Binary data:
// {"$escape": THING} // Escaped things that might otherwise look like EJSON types
// {"$type": TYPENAME, "$value": VALUE} // User specified types
public class EJSON: NSObject {
/**
Determines whether a given key is an eJSON key
*/
public static func isEJSON(key:String) -> Bool {
switch key {
case "$date": return true
case "$binary": return true
case "$type": return true
default: return false
}
}
/**
Converts an eJSON date to NSDate
*/
public static func convertToNSDate(ejson:NSDictionary) -> NSDate {
let timeInterval = NSTimeInterval(ejson.valueForKey("$date") as! Double) / 1000
return NSDate(timeIntervalSince1970: timeInterval)
}
public static func convertToEJSONDate(date:NSDate) -> [String:Double] {
let timeInterval = Double(date.timeIntervalSince1970) * 1000
print("Date -> \(date), \(timeInterval)")
return ["$date": timeInterval]
}
}

View File

@ -1,368 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import UIKit
/*
enum Error: String {
case BadRequest = "400" // The server cannot or will not process the request due to something that is perceived to be a client error
case Unauthorized = "401" // Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided.
case NotFound = "404" // ex. Method not found, Subscription not found
case Forbidden = "403" // Not authorized to access resource, also issued when you've been logged out by the server
case RequestConflict = "409" // ex. MongoError: E11000 duplicate key error
case PayloadTooLarge = "413" // The request is larger than the server is willing or able to process.
case InternalServerError = "500"
}
*/
public protocol MeteorCollectionType {
func documentWasAdded(collection:String, id:String, fields:NSDictionary?)
func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?)
func documentWasRemoved(collection:String, id:String)
}
/**
Meteor is a class to simplify communicating with and consuming MeteorJS server services
*/
public class Meteor {
/**
client is a singleton instance of DDPClient
*/
public static let client = Meteor.Client() // Client is a singleton object
internal static var collections = [String:MeteorCollectionType]()
/**
returns a Meteor collection, if it exists
*/
public static func collection(name:String) -> MeteorCollectionType? {
return collections[name]
}
/**
Sends a subscription request to the server.
- parameter name: The name of the subscription.
*/
public static func subscribe(name:String) -> String { return client.sub(name, params:nil) }
/**
Sends a subscription request to the server.
- parameter name: The name of the subscription.
- parameter params: An object containing method arguments, if any.
*/
public static func subscribe(name:String, params:[AnyObject]) -> String { return client.sub(name, params:params) }
/**
Sends a subscription request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the initial subset of documents contained
in the subscription has been sent by the server.
- parameter name: The name of the subscription.
- parameter params: An object containing method arguments, if any.
- parameter callback: The closure to be executed when the server sends a 'ready' message.
*/
public static func subscribe(name:String, params:[AnyObject]?, callback: DDPCallback?) -> String { return client.sub(name, params:params, callback:callback) }
/**
Sends a subscription request to the server. If a callback is passed, the callback asynchronously
runs when the client receives a 'ready' message indicating that the initial subset of documents contained
in the subscription has been sent by the server.
- parameter name: The name of the subscription.
- parameter callback: The closure to be executed when the server sends a 'ready' message.
*/
public static func subscribe(name:String, callback: DDPCallback?) -> String { return client.sub(name, params: nil, callback: callback) }
/**
Sends an unsubscribe request to the server.
*/
public static func unsubscribe(name:String) -> String? { return client.unsub(name) }
/**
Sends an unsubscribe request to the server. If a callback is passed, the callback asynchronously
runs when the unsubscribe transaction is complete.
*/
public static func unsubscribe(name:String, callback:DDPCallback?) -> String? { return client.unsub(name, callback: callback) }
/**
Calls a method on the server. If a callback is passed, the callback is asynchronously
executed when the method has completed. The callback takes two arguments: result and error. It
the method call is successful, result contains the return value of the method, if any. If the method fails,
error contains information about the error.
- parameter name: The name of the method
- parameter params: An array containing method arguments, if any
- parameter callback: The closure to be executed when the method has been executed
*/
public static func call(name:String, params:[AnyObject]?, callback:DDPMethodCallback?) -> String? {
return client.method(name, params: params, callback: callback)
}
/**
Call a single function to establish a DDP connection, and login with email and password
- parameter url: The url of a Meteor server
- parameter email: A string email address associated with a Meteor account
- parameter password: A string password
*/
public static func connect(url:String, email:String, password:String) {
client.connect(url) { session in
client.loginWithPassword(email, password: password) { result, error in
guard let _ = error else {
if let _ = result as? NSDictionary {
// client.userDidLogin(credentials)
}
return
}
}
}
}
/**
Connect to a Meteor server and resume a prior session, if the user was logged in
- parameter url: The url of a Meteor server
*/
public static func connect(url:String) {
client.resume(url, callback: nil)
}
/**
Connect to a Meteor server and resume a prior session, if the user was logged in
- parameter url: The url of a Meteor server
- parameter callback: An optional closure to be executed after the connection is established
*/
public static func connect(url:String, callback:DDPCallback?) {
client.resume(url, callback: callback)
}
/**
Creates a user account on the server with an email and password
- parameter email: An email string
- parameter password: A password string
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public static func signupWithEmail(email: String, password: String, callback: DDPMethodCallback?) {
client.signupWithEmail(email, password: password, callback: callback)
}
/**
Logs a user into the server using an email and password
- parameter email: An email string
- parameter password: A password string
- parameter callback: A closure with result and error parameters describing the outcome of the operation
*/
public static func loginWithPassword(email:String, password:String, callback:DDPMethodCallback?) {
client.loginWithPassword(email, password: password, callback: callback)
}
/**
Logs a user into the server using an email and password
- parameter email: An email string
- parameter password: A password string
*/
public static func loginWithPassword(email:String, password:String) {
client.loginWithPassword(email, password: password, callback: nil)
}
internal static func loginWithService<T: UIViewController>(service: String, clientId: String, viewController: T) {
// Resume rather than
if Meteor.client.loginWithToken(nil) == false {
var url:String!
switch service {
case "twitter":
url = MeteorOAuthServices.twitter()
case "facebook":
url = MeteorOAuthServices.facebook(clientId)
case "github":
url = MeteorOAuthServices.github(clientId)
case "google":
url = MeteorOAuthServices.google(clientId)
default:
url = nil
}
let oauthDialog = MeteorOAuthDialogViewController()
oauthDialog.serviceName = service.capitalizedString
oauthDialog.url = NSURL(string: url)
viewController.presentViewController(oauthDialog, animated: true, completion: nil)
} else {
log.debug("Already have valid server login credentials. Logging in with preexisting login token")
}
}
/**
Logs a user into the server using Twitter
- parameter viewController: A view controller from which to launch the OAuth modal dialog
*/
public static func loginWithTwitter<T: UIViewController>(viewController: T) {
Meteor.loginWithService("twitter", clientId: "", viewController: viewController)
}
/**
Logs a user into the server using Facebook
- parameter viewController: A view controller from which to launch the OAuth modal dialog
- parameter clientId: The apps client id, provided by the service (Facebook, Google, etc.)
*/
public static func loginWithFacebook<T: UIViewController>(clientId: String, viewController: T) {
Meteor.loginWithService("facebook", clientId: clientId, viewController: viewController)
}
/**
Logs a user into the server using Github
- parameter viewController: A view controller from which to launch the OAuth modal dialog
- parameter clientId: The apps client id, provided by the service (Facebook, Google, etc.)
*/
public static func loginWithGithub<T: UIViewController>(clientId: String, viewController: T) {
Meteor.loginWithService("github", clientId: clientId, viewController: viewController)
}
/**
Logs a user into the server using Google
- parameter viewController: A view controller from which to launch the OAuth modal dialog
- parameter clientId: The apps client id, provided by the service (Facebook, Google, etc.)
*/
public static func loginWithGoogle<T: UIViewController>(clientId: String, viewController: T) {
Meteor.loginWithService("google", clientId: clientId, viewController: viewController)
}
/**
Logs a user out of the server and executes a callback when the logout process has completed
- parameter callback: An optional closure to be executed after the client has logged out
*/
public static func logout(callback:DDPMethodCallback?) {
client.logout(callback)
}
/**
Logs a user out of the server
*/
public static func logout() {
client.logout()
}
/**
Meteor.Client is a subclass of DDPClient that facilitates interaction with the MeteorCollection class
*/
public class Client: DDPClient {
typealias SubscriptionCallback = () -> ()
let notifications = NSNotificationCenter.defaultCenter()
public convenience init(url:String, email:String, password:String) {
self.init()
}
/**
Calls the documentWasAdded method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
*/
public override func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
if let meteorCollection = Meteor.collections[collection] {
meteorCollection.documentWasAdded(collection, id: id, fields: fields)
}
}
/**
Calls the documentWasChanged method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
- parameter cleared: an optional array of string property names to delete
*/
public override func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
if let meteorCollection = Meteor.collections[collection] {
meteorCollection.documentWasChanged(collection, id: id, fields: fields, cleared: cleared)
}
}
/**
Calls the documentWasRemoved method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
*/
public override func documentWasRemoved(collection:String, id:String) {
if let meteorCollection = Meteor.collections[collection] {
meteorCollection.documentWasRemoved(collection, id: id)
}
}
}
}

View File

@ -1,80 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public class MeteorDocument: NSObject {
var _id:String
required public init(id: String, fields: NSDictionary?) {
self._id = id
super.init()
if let properties = fields {
for (key,value) in properties {
self.setValue(value, forKey: key as! String)
}
}
}
public func update(fields: NSDictionary?, cleared: [String]?) {
if let properties = fields {
for (key,value) in properties {
print("Key: \(key), Value: \(value)")
self.setValue(value, forKey: key as! String)
}
}
if let deletions = cleared {
for property in deletions {
self.setNilValueForKey(property)
}
}
}
/*
Limitations to propertyNames:
- Returns an empty array for Objective-C objects
- Will not return computed properties, i.e.:
- If self is an instance of a class (vs., say, a struct), this doesn't report its superclass's properties, i.e.:
see http://stackoverflow.com/questions/24844681/list-of-classs-properties-in-swift
*/
func propertyNames() -> [String] {
return Mirror(reflecting: self).children.filter { $0.label != nil }.map { $0.label! }
}
func fields() -> NSDictionary {
let fieldsDict = NSMutableDictionary()
let properties = propertyNames()
for name in properties {
if let value = self.valueForKey(name) {
fieldsDict.setValue(value, forKey: name)
}
}
fieldsDict.setValue(self._id, forKey: "_id")
print("fields \(fieldsDict)")
return fieldsDict as NSDictionary
}
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public class MeteorOAuth {
static let meteor = Meteor.client
static var httpUrl:String = {
let url = MeteorOAuth.getHTTPUrl(Meteor.client.url)
return url
}()
// Forms a HTTP url from a Meteor websocket url
static func getHTTPUrl(websocketUrl: String) -> String {
// remove websocket; should rewrite this so that it takes only
// websocket from the end of the string
let path = websocketUrl.componentsSeparatedByString("/websocket")[0]
let components = path.componentsSeparatedByString("://")
let applicationLayerProtocol = components[0]
assert(applicationLayerProtocol == "ws" || applicationLayerProtocol == "wss")
let domainName = components[1]
if applicationLayerProtocol == "ws" {
return "http://\(domainName)"
}
return "https://\(domainName)"
}
// Construct the state parameter
static func stateParam(credentialToken: String, redirectUrl: String) -> String {
let objectString = "{\"redirectUrl\":\"\(redirectUrl)\",\"loginStyle\":\"redirect\",\"isCordova\":\"false\",\"credentialToken\":\"\(credentialToken)\"}"
return toBase64(objectString)
}
}

View File

@ -1,91 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public class MeteorOAuthServices {
public static func twitter() -> String {
let httpUrl = MeteorOAuth.httpUrl
let token = randomBase64String()
let redirect = "\(httpUrl)/_oauth/twitter"
let state = MeteorOAuth.stateParam(token, redirectUrl: redirect)
return "\(httpUrl)/_oauth/twitter/?requestTokenAndRedirect=true&state=\(state)"
}
public static func facebook(appId: String) -> String {
let token = randomBase64String()
let httpUrl = MeteorOAuth.httpUrl
let redirect = "\(httpUrl)/_oauth/facebook"
let state = MeteorOAuth.stateParam(token, redirectUrl: redirect)
let scope = "email"
var url = "https://m.facebook.com/v2.2/dialog/oauth?client_id=\(appId)"
url += "&redirect_uri=\(redirect)"
url += "&scope=\(scope)"
url += "&state=\(state)"
return url
}
public static func github(clientId: String) -> String {
let token = randomBase64String()
let httpUrl = MeteorOAuth.httpUrl
let redirect = "\(httpUrl)/_oauth/github"
let state = MeteorOAuth.stateParam(token, redirectUrl: redirect)
let scope = "user:email"
var url = "https://github.com/login/oauth/authorize?client_id=\(clientId)"
url += "&redirect_uri=\(redirect)"
url += "&scope=\(scope)"
url += "&state=\(state)"
return url
}
public static func google(clientId: String) -> String {
let token = randomBase64String()
let httpUrl = MeteorOAuth.httpUrl
let redirect = "\(httpUrl)/_oauth/google"
let state = MeteorOAuth.stateParam(token, redirectUrl: redirect)
let scope = "email"
var url = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=\(clientId)"
url += "&redirect_uri=\(redirect)"
url += "&scope=\(scope)"
url += "&state=\(state)"
return url
}
}

View File

@ -1,122 +0,0 @@
// Copyright (c) 2016 Peter Siegesmund <peter.siegesmund@icloud.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import WebKit
// TODO: Handle login failure > specific actions for cancellation, for example
// TODO: Gotchas: connecting over wss, but registered domain is http...
// TODO: Activity indicator?
// TODO: Add redirect not popup; register as web app when setting up services to instructions
// TODO: Login first with stored token
public class MeteorOAuthDialogViewController: UIViewController, WKNavigationDelegate {
// App must be set to redirect, rather than popup
// https://github.com/meteor/meteor/wiki/OAuth-for-mobile-Meteor-clients#popup-versus-redirect-flow
var meteor = Meteor.client
public var navigationBar:UINavigationBar!
public var cancelButton:UIBarButtonItem!
public var webView:WKWebView!
public var url:NSURL!
public var serviceName: String?
override public func viewDidLoad() {
navigationBar = UINavigationBar() // Offset by 20 pixels vertically to take the status bar into account
let navigationItem = UINavigationItem()
navigationItem.title = "Login"
if let name = serviceName {
navigationItem.title = "Login with \(name)"
}
cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "close")
navigationItem.rightBarButtonItem = cancelButton
navigationBar!.items = [navigationItem]
// Configure WebView
let request = NSURLRequest(URL:url)
webView = WKWebView()
webView.navigationDelegate = self
webView.loadRequest(request)
self.view.addSubview(webView)
self.view.addSubview(navigationBar)
}
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navigationBar.frame = CGRectMake(0, 0, self.view.frame.size.width, 64)
webView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64)
}
func close() {
self.dismissViewControllerAnimated(true, completion: nil)
}
func signIn(token: String, secret: String) {
let params = ["oauth":["credentialToken": token, "credentialSecret": secret]]
Meteor.client.login(params) { result, error in
print("Meteor login attempt \(result), \(error)")
self.close()
}
}
//
//
// WKNavigationDelegate Methods
//
//
/* Start the network activity indicator when the web view is loading */
public func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
/* Stop the network activity indicator when the loading finishes */
public func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation){
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
// This works to get the credentialSecret, credentialToken, redirectUrl etc.
webView.evaluateJavaScript("JSON.parse(document.getElementById('config').innerHTML)",
completionHandler: { (html: AnyObject?, error: NSError?) in
if let json = html {
if let secret = json["credentialSecret"] as? String,
token = json["credentialToken"] as? String {
webView.stopLoading() // Is there a possible race condition here?
self.signIn(token, secret: secret)
}
} else {
print("There was no json here")
}
// TODO: What if there's an error?, if the login fails
})
}
}

View File

@ -1,17 +0,0 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,172 +0,0 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Features](#features)
- [Example](#example)
- [Custom Headers](#custom-headers)
- [Reuse and Delaying WebSocket Connections](#reuse-and-delaying-websocket-connections)
- [Compression](#compression)
- [Self-signed SSL Certificate](#self-signed-ssl-certificate)
- [Network Services (VoIP, Video, Background, Voice)](#network-services-voip-video-background-voice)
- [[Carthage]](#carthage)
- [[CocoaPods]](#cocoapods)
- [Contact](#contact)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
#<img src="https://tidwall.github.com/SwiftWebSocket/logo.png" height="45" width="60">&nbsp;SwiftWebSocket
<a href="https://tidwall.github.io/SwiftWebSocket/results/"><img src="https://tidwall.github.io/SwiftWebSocket/build.png" alt="" width="93" height="20" border="0" /></a>
<a href="https://developer.apple.com/swift/"><img src="https://tidwall.github.io/SwiftWebSocket/swift2.png" alt="" width="65" height="20" border="0" /></a>
<a href="https://tidwall.github.io/SwiftWebSocket/docs/"><img src="https://tidwall.github.io/SwiftWebSocket/docs.png" alt="" width="65" height="20" border="0" /></a>
Conforming WebSocket ([RFC 6455](https://tools.ietf.org/html/rfc6455)) client library for iOS and Mac OSX.
SwiftWebSocket passes all 521 of the Autobahn's fuzzing tests, including strict UTF-8, and message compression.
**Important: Xcode 7.2 and Swift 2.0 Users**
If you are developing in either environment then please use the `swift/2.0` branch.
## Features
- High performance.
- 100% conforms to [Autobahn Tests](http://autobahn.ws/testsuite/#test-suite-coverage). Including base, limits, compression, etc. [Test results](https://tidwall.github.io/SwiftWebSocket/results/).
- TLS / WSS support. Self-signed certificate option.
- The API is modeled after the [Javascript API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).
- Reads compressed messages (`permessage-deflate`). [RFC 7692](https://tools.ietf.org/html/rfc7692)
- Send pings and receive pong events.
- Strict UTF-8 processing.
- `binaryType` property to choose between `[UInt8]` or `NSData` messages.
- Zero asserts. All networking, stream, and protocol errors are routed through the `error` event.
- iOS / Objective-C support.
## Example
```swift
func echoTest(){
var messageNum = 0
let ws = WebSocket("wss://echo.websocket.org")
let send : ()->() = {
let msg = "\(++messageNum): \(NSDate().description)"
print("send: \(msg)")
ws.send(msg)
}
ws.event.open = {
print("opened")
send()
}
ws.event.close = { code, reason, clean in
print("close")
}
ws.event.error = { error in
print("error \(error)")
}
ws.event.message = { message in
if let text = message as? String {
print("recv: \(text)")
if messageNum == 10 {
ws.close()
} else {
send()
}
}
}
}
```
## Custom Headers
```swift
let request = NSMutableURLRequest(URL: NSURL(string:"ws://url")!)
request.addValue("AUTH_TOKEN", forHTTPHeaderField: "Authorization")
request.addValue("Value", forHTTPHeaderField: "X-Another-Header")
let ws = WebSocket(request: request)
```
## Reuse and Delaying WebSocket Connections
v2.3.0+ makes available an optional `open` method. This will allow for a `WebSocket` object to be instantiated without an immediate connection to the server. It can also be used to reconnect to a server following the `close` event.
For example,
```swift
let ws = WebSocket()
ws.event.close = { _ in
ws.open() // reopen the socket to the previous url
ws.open("ws://otherurl") // or, reopen the socket to a new url
}
ws.open("ws://url") // call with url
```
## Compression
The `compression` flag may be used to request compressed messages from the server. If the server does not support or accept the request, then connection will continue as normal, but with uncompressed messages.
```swift
let ws = WebSocket("ws://url")
ws.compression.on = true
```
## Self-signed SSL Certificate
```swift
let ws = WebSocket("ws://url")
ws.allowSelfSignedSSL = true
```
## Network Services (VoIP, Video, Background, Voice)
```swift
// Allow socket to handle VoIP in the background.
ws.services = [.VoIP, .Background]
```
##Installation (iOS and OS X)
### [Carthage]
[Carthage]: https://github.com/Carthage/Carthage
Add the following to your Cartfile:
```
github "tidwall/SwiftWebSocket"
```
Then run `carthage update`.
Follow the current instructions in [Carthage's README][carthage-installation]
for up to date installation instructions.
[carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
The `import SwiftWebSocket` directive is required in order to access SwiftWebSocket features.
### [CocoaPods]
[CocoaPods]: http://cocoapods.org
Add the following to your [Podfile](http://guides.cocoapods.org/using/the-podfile.html):
```ruby
use_frameworks!
pod 'SwiftWebSocket'
```
Then run `pod install` with CocoaPods 0.36 or newer.
The `import SwiftWebSocket` directive is required in order to access SwiftWebSocket features.
###Manually
Copy the `SwiftWebSocket/WebSocket.swift` file into your project.
You must also add the `libz.dylib` library. `Project -> Target -> Build Phases -> Link Binary With Libraries`
There is no need for `import SwiftWebSocket` when manually installing.
## Contact
Josh Baker [@tidwall](http://twitter.com/tidwall)
## License
SwiftWebSocket source code is available under the MIT License.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_CryptoSwift : NSObject
@end
@implementation PodsDummy_CryptoSwift
@end

View File

@ -1,4 +0,0 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif

View File

@ -1,6 +0,0 @@
#import <UIKit/UIKit.h>
FOUNDATION_EXPORT double CryptoSwiftVersionNumber;
FOUNDATION_EXPORT const unsigned char CryptoSwiftVersionString[];

View File

@ -1,6 +0,0 @@
framework module CryptoSwift {
umbrella header "CryptoSwift-umbrella.h"
export *
module * { export * }
}

View File

@ -1,5 +0,0 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/CryptoSwift" "${PODS_ROOT}/Headers/Public"
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
PODS_ROOT = ${SRCROOT}
SKIP_INSTALL = YES

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -1,98 +0,0 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Acknowledgements](#acknowledgements)
- [CryptoSwift](#cryptoswift)
- [SwiftDDP](#swiftddp)
- [SwiftWebSocket](#swiftwebsocket)
- [XCGLogger](#xcglogger)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Acknowledgements
This application makes use of the following third party libraries:
## CryptoSwift
Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
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:
- 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.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.
## SwiftDDP
Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## SwiftWebSocket
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## XCGLogger
The MIT License (MIT)
Copyright (c) 2014 Dave Wood, Cerebral Gardens http://www.cerebralgardens.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Generated by CocoaPods - http://cocoapods.org

View File

@ -1,128 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (C) 2014 Marcin Krzy&#380;anowski &lt;marcin.krzyzanowski@gmail.com&gt;
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
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:
- 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.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.</string>
<key>Title</key>
<string>CryptoSwift</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2015 Peter Siegesmund &lt;peter.siegesmund@icloud.com&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>Title</key>
<string>SwiftDDP</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>Title</key>
<string>SwiftWebSocket</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>The MIT License (MIT)
Copyright (c) 2014 Dave Wood, Cerebral Gardens http://www.cerebralgardens.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>Title</key>
<string>XCGLogger</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - http://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>

View File

@ -1,5 +0,0 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_SwiftTodos : NSObject
@end
@implementation PodsDummy_Pods_SwiftTodos
@end

View File

@ -1,97 +0,0 @@
#!/bin/sh
set -e
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
# use filter instead of exclude so missing patterns dont' throw errors
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Signs a framework with the provided identity
code_sign_if_enabled() {
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identitiy
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\""
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1"
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "Pods-SwiftTodos/CryptoSwift.framework"
install_framework "Pods-SwiftTodos/SwiftDDP.framework"
install_framework "Pods-SwiftTodos/SwiftWebSocket.framework"
install_framework "Pods-SwiftTodos/XCGLogger.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "Pods-SwiftTodos/CryptoSwift.framework"
install_framework "Pods-SwiftTodos/SwiftDDP.framework"
install_framework "Pods-SwiftTodos/SwiftWebSocket.framework"
install_framework "Pods-SwiftTodos/XCGLogger.framework"
fi

View File

@ -1,95 +0,0 @@
#!/bin/sh
set -e
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
XCASSET_FILES=()
realpath() {
DIRECTORY="$(cd "${1%/*}" && pwd)"
FILENAME="${1##*/}"
echo "$DIRECTORY/$FILENAME"
}
install_resource()
{
case $1 in
*.storyboard)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.xib)
echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
;;
*.framework)
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
;;
*.xcdatamodel)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
;;
*.xcdatamodeld)
echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
;;
*.xcmappingmodel)
echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
;;
*.xcassets)
ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1")
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
;;
/*)
echo "$1"
echo "$1" >> "$RESOURCES_TO_COPY"
;;
*)
echo "${PODS_ROOT}/$1"
echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
;;
esac
}
mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
then
case "${TARGETED_DEVICE_FAMILY}" in
1,2)
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
;;
1)
TARGET_DEVICE_ARGS="--target-device iphone"
;;
2)
TARGET_DEVICE_ARGS="--target-device ipad"
;;
*)
TARGET_DEVICE_ARGS="--target-device mac"
;;
esac
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
while read line; do
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
XCASSET_FILES+=("$line")
fi
done <<<"$OTHER_XCASSETS"
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi

Some files were not shown because too many files have changed in this diff Show More