project start

This commit is contained in:
Dawid Kubicki 2018-11-19 14:31:37 +01:00
parent b60784300b
commit 1a500db453
165 changed files with 13800 additions and 0 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
<FileRef
location = "group:/Users/dawidkubicki/Documents/uczelnia/bsm/bsm-project/bsmZadanie.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,46 @@
import UIKit
final class AppController {
static let shared = AppController()
var window: UIWindow!
var rootViewController: UIViewController? {
didSet {
if let vc = rootViewController {
window.rootViewController = vc
}
}
}
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handleAuthState),
name: .loginStatusChanged,
object: nil
)
}
func show(in window: UIWindow?) {
guard let window = window else {
fatalError("Cannot layout app with a nil window.")
}
window.backgroundColor = .black
self.window = window
rootViewController = SplashViewController()
window.makeKeyAndVisible()
}
@objc func handleAuthState() {
if AuthController.isSignedIn {
rootViewController = NavigationController(rootViewController: FriendsViewController())
} else {
rootViewController = AuthViewController()
}
}
}

View File

@ -0,0 +1,14 @@
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
AppController.shared.show(in: UIWindow(frame: UIScreen.main.bounds))
return true
}
}

View File

@ -0,0 +1,182 @@
{
"images":[
{
"idiom":"iphone",
"size":"20x20",
"scale":"2x",
"filename":"Icon-App-20x20@2x.png"
},
{
"idiom":"iphone",
"size":"20x20",
"scale":"3x",
"filename":"Icon-App-20x20@3x.png"
},
{
"idiom":"iphone",
"size":"29x29",
"scale":"1x",
"filename":"Icon-App-29x29@1x.png"
},
{
"idiom":"iphone",
"size":"29x29",
"scale":"2x",
"filename":"Icon-App-29x29@2x.png"
},
{
"idiom":"iphone",
"size":"29x29",
"scale":"3x",
"filename":"Icon-App-29x29@3x.png"
},
{
"idiom":"iphone",
"size":"40x40",
"scale":"1x",
"filename":"Icon-App-40x40@1x.png"
},
{
"idiom":"iphone",
"size":"40x40",
"scale":"2x",
"filename":"Icon-App-40x40@2x.png"
},
{
"idiom":"iphone",
"size":"40x40",
"scale":"3x",
"filename":"Icon-App-40x40@3x.png"
},
{
"idiom":"iphone",
"size":"57x57",
"scale":"1x",
"filename":"Icon-App-57x57@1x.png"
},
{
"idiom":"iphone",
"size":"57x57",
"scale":"2x",
"filename":"Icon-App-57x57@2x.png"
},
{
"idiom":"iphone",
"size":"60x60",
"scale":"1x",
"filename":"Icon-App-60x60@1x.png"
},
{
"idiom":"iphone",
"size":"60x60",
"scale":"2x",
"filename":"Icon-App-60x60@2x.png"
},
{
"idiom":"iphone",
"size":"60x60",
"scale":"3x",
"filename":"Icon-App-60x60@3x.png"
},
{
"idiom":"iphone",
"size":"76x76",
"scale":"1x",
"filename":"Icon-App-76x76@1x.png"
},
{
"idiom":"ipad",
"size":"20x20",
"scale":"1x",
"filename":"Icon-App-20x20@1x.png"
},
{
"idiom":"ipad",
"size":"20x20",
"scale":"2x",
"filename":"Icon-App-20x20@2x.png"
},
{
"idiom":"ipad",
"size":"29x29",
"scale":"1x",
"filename":"Icon-App-29x29@1x.png"
},
{
"idiom":"ipad",
"size":"29x29",
"scale":"2x",
"filename":"Icon-App-29x29@2x.png"
},
{
"idiom":"ipad",
"size":"40x40",
"scale":"1x",
"filename":"Icon-App-40x40@1x.png"
},
{
"idiom":"ipad",
"size":"40x40",
"scale":"2x",
"filename":"Icon-App-40x40@2x.png"
},
{
"size" : "50x50",
"idiom" : "ipad",
"filename" : "Icon-Small-50x50@1x.png",
"scale" : "1x"
},
{
"size" : "50x50",
"idiom" : "ipad",
"filename" : "Icon-Small-50x50@2x.png",
"scale" : "2x"
},
{
"idiom":"ipad",
"size":"72x72",
"scale":"1x",
"filename":"Icon-App-72x72@1x.png"
},
{
"idiom":"ipad",
"size":"72x72",
"scale":"2x",
"filename":"Icon-App-72x72@2x.png"
},
{
"idiom":"ipad",
"size":"76x76",
"scale":"1x",
"filename":"Icon-App-76x76@1x.png"
},
{
"idiom":"ipad",
"size":"76x76",
"scale":"2x",
"filename":"Icon-App-76x76@2x.png"
},
{
"idiom":"ipad",
"size":"76x76",
"scale":"3x",
"filename":"Icon-App-76x76@3x.png"
},
{
"idiom":"ipad",
"size":"83.5x83.5",
"scale":"2x",
"filename":"Icon-App-83.5x83.5@2x.png"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "ItunesArtwork@2x.png",
"scale" : "1x"
}
],
"info":{
"version":1,
"author":"makeappicon"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "FaceID.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "TouchID.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Razewarelogo_1024.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "rwdevcon-bg.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

View File

@ -0,0 +1,52 @@
import Foundation
import CryptoSwift
final class AuthController {
static let serviceName = "FriendvatarsService"
static var isSignedIn: Bool {
guard let currentUser = Settings.currentUser else {
return false
}
do {
let password = try KeychainPasswordItem(service: serviceName, account: currentUser.email).readPassword()
return password.count > 0
} catch {
return false
}
}
class func passwordHash(from email: String, password: String) -> String {
let salt = "x4vV8bGgqqmQwgCoyXFQj+(o.nUNQhVP7ND"
return "\(password).\(email).\(salt)".sha256()
}
class func signIn(_ user: User, password: String) throws {
let finalHash = passwordHash(from: user.email, password: password)
try KeychainPasswordItem(service: serviceName, account: user.email).savePassword(finalHash)
Settings.currentUser = user
NotificationCenter.default.post(name: .loginStatusChanged, object: nil)
}
class func signOut() throws {
guard let currentUser = Settings.currentUser else {
return
}
try KeychainPasswordItem(service: serviceName, account: currentUser.email).deleteItem()
Settings.currentUser = nil
NotificationCenter.default.post(name: .loginStatusChanged, object: nil)
}
}
extension Notification.Name {
static let loginStatusChanged = Notification.Name("com.razeware.auth.changed")
}

View File

@ -0,0 +1,220 @@
import UIKit
import KeychainAccess
final class AuthViewController: UIViewController {
override var prefersStatusBarHidden: Bool {
return true
}
private enum TextFieldTag: Int {
case email
case password
}
@IBOutlet weak var txtSecret: UITextField!
@IBOutlet weak var imgBio: UIImageView!
@IBOutlet weak var lblSecret: UILabel!
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var emailField: UITextField!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var signInButton: UIButton!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
let keychain = Keychain(service: "com.zadanie.bsm")
override func viewDidLoad() {
super.viewDidLoad()
if(biometricType == .touchID) {
imgBio.image = UIImage(named: "TouchID")
} else if(biometricType == .faceID) {
imgBio.image = UIImage(named: "FaceID")
} else if(biometricType == .none) {
print("Nie ma biometrycznego czytnika")
}
containerView.transform = CGAffineTransform(scaleX: 0, y: 0)
containerView.backgroundColor = .rwGreen
containerView.layer.cornerRadius = 7
emailField.delegate = self
emailField.tintColor = .rwGreen
emailField.tag = TextFieldTag.email.rawValue
passwordField.delegate = self
passwordField.tintColor = .rwGreen
passwordField.tag = TextFieldTag.password.rawValue
titleLabel.isHidden = true
view.addGestureRecognizer(
UITapGestureRecognizer(
target: self,
action: #selector(handleTap(_:))
)
)
registerForKeyboardNotifications()
}
@IBAction func storeSecret(_ sender: Any) {
DispatchQueue.global().async {
do {
try self.keychain
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence)
.set(self.txtSecret.text!, key: "secret")
} catch let error {
print(error)
}
}
}
@IBAction func getSecret(_ sender: Any) {
DispatchQueue.global().async {
do {
let secret = try self.keychain
.authenticationPrompt("Użyj czynnika biometrycznego, żeby zobaczyć sekret")
.get("secret")
self.lblSecret.text = "Sekret to \(secret!)"
} catch let error {
print(error)
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 0.3
animation.fromValue = 0
animation.toValue = 1
CATransaction.begin()
CATransaction.setCompletionBlock {
self.emailField.becomeFirstResponder()
self.titleLabel.isHidden = false
}
containerView.layer.add(animation, forKey: "scale")
containerView.transform = CGAffineTransform(scaleX: 1, y: 1)
CATransaction.commit()
}
// MARK: - Actions
@objc private func handleTap(_ gesture: UITapGestureRecognizer) {
view.endEditing(true)
}
@IBAction func signInButtonPressed() {
signIn()
}
// MARK: - Helpers
private func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillHide(_:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil
)
}
private func signIn() {
view.endEditing(true)
guard let email = emailField.text, email.count > 0 else {
return
}
guard let password = passwordField.text, password.count > 0 else {
return
}
let name = UIDevice.current.name
let user = User(name: name, email: email)
do {
try AuthController.signIn(user, password: password)
} catch {
print("Error signing in: \(error.localizedDescription)")
}
}
// MARK: - Notifications
@objc internal func keyboardWillShow(_ notification: Notification) {
guard let userInfo = notification.userInfo else {
return
}
guard let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height else {
return
}
guard let keyboardAnimationDuration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue else {
return
}
guard let keyboardAnimationCurve = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue else {
return
}
let options = UIViewAnimationOptions(rawValue: keyboardAnimationCurve << 16)
bottomConstraint.constant = keyboardHeight + 32
UIView.animate(withDuration: keyboardAnimationDuration, delay: 0, options: options, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
@objc internal func keyboardWillHide(_ notification: Notification) {
guard let userInfo = notification.userInfo else {
return
}
guard let keyboardAnimationDuration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue else {
return
}
guard let keyboardAnimationCurve = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue else {
return
}
let options = UIViewAnimationOptions(rawValue: keyboardAnimationCurve << 16)
bottomConstraint.constant = 0
UIView.animate(withDuration: keyboardAnimationDuration, delay: 0, options: options, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
extension AuthViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard let text = textField.text, text.count > 0 else {
return false
}
switch textField.tag {
case TextFieldTag.email.rawValue:
passwordField.becomeFirstResponder()
case TextFieldTag.password.rawValue:
signIn()
default:
return false
}
return true
}
}

View File

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AuthViewController" customModule="Friendvatars" customModuleProvider="target">
<connections>
<outlet property="bottomConstraint" destination="nvR-sM-xyu" id="sfO-yG-bij"/>
<outlet property="containerView" destination="fIM-wX-ThP" id="MCr-wf-hth"/>
<outlet property="emailField" destination="vrM-BE-Sxz" id="yN0-VF-tnI"/>
<outlet property="imgBio" destination="aiB-UR-Quk" id="Rf6-w3-c9d"/>
<outlet property="lblSecret" destination="SIk-oO-kOD" id="8c0-hE-Wb2"/>
<outlet property="passwordField" destination="XnE-em-cB7" id="I2k-JM-vRu"/>
<outlet property="signInButton" destination="hSR-Ry-zgR" id="67R-L3-h8e"/>
<outlet property="titleLabel" destination="WHD-fd-dhU" id="y4p-7Q-Mwd"/>
<outlet property="txtSecret" destination="NYv-x5-X0G" id="967-mt-IUu"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="rwdevcon-bg" translatesAutoresizingMaskIntoConstraints="NO" id="tFe-fM-7UZ">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UKRYTE WIADOMOŚCI" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHD-fd-dhU">
<rect key="frame" x="32" y="69" width="311" height="31.5"/>
<constraints>
<constraint firstAttribute="height" constant="31.5" id="Hl5-V5-oUY"/>
<constraint firstAttribute="width" constant="311" id="O3M-ll-ype"/>
</constraints>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="NYv-x5-X0G">
<rect key="frame" x="83.5" y="400" width="208" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="Kc5-kK-ceQ"/>
<constraint firstAttribute="width" constant="208" id="Z2q-C8-b0N"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fIM-wX-ThP">
<rect key="frame" x="32" y="112.5" width="311" height="256"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="47J-gQ-72v">
<rect key="frame" x="12" y="12" width="287" height="232"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" text="Login lub mail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jBg-ue-wfi">
<rect key="frame" x="0.0" y="0.0" width="287" height="40"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Podaj swoj login/hasło" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vrM-BE-Sxz">
<rect key="frame" x="0.0" y="48" width="287" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="o9g-dR-A9f"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="emailAddress" keyboardAppearance="alert" enablesReturnKeyAutomatically="YES" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no" textContentType="email"/>
</textField>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hasło" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AMS-r7-phX">
<rect key="frame" x="0.0" y="96" width="287" height="40"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Podaj swoje hasło" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="XnE-em-cB7">
<rect key="frame" x="0.0" y="144" width="287" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="r71-Sl-CjK"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<textInputTraits key="textInputTraits" keyboardAppearance="alert" secureTextEntry="YES"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hSR-Ry-zgR">
<rect key="frame" x="0.0" y="192" width="287" height="40"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<state key="normal" title="Zobacz zaszyfrowaną wiadomość">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="signInButtonPressed" destination="-1" eventType="touchUpInside" id="tdM-du-QeO"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="vrM-BE-Sxz" secondAttribute="trailing" id="1Z2-xc-gAX"/>
<constraint firstItem="XnE-em-cB7" firstAttribute="leading" secondItem="47J-gQ-72v" secondAttribute="leading" id="7b3-lJ-Ouz"/>
<constraint firstItem="vrM-BE-Sxz" firstAttribute="leading" secondItem="47J-gQ-72v" secondAttribute="leading" id="AFS-11-IhR"/>
<constraint firstAttribute="trailing" secondItem="XnE-em-cB7" secondAttribute="trailing" id="sJh-f6-THo"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="scrollViewTexturedBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="256" id="7Lf-Jc-Y1f"/>
<constraint firstAttribute="trailing" secondItem="47J-gQ-72v" secondAttribute="trailing" constant="12" id="WkR-AZ-hfk"/>
<constraint firstItem="47J-gQ-72v" firstAttribute="centerY" secondItem="fIM-wX-ThP" secondAttribute="centerY" id="Yml-f5-C1g"/>
<constraint firstAttribute="width" constant="311" id="eHP-rK-M2p"/>
<constraint firstItem="47J-gQ-72v" firstAttribute="top" secondItem="fIM-wX-ThP" secondAttribute="top" constant="12" id="lYI-As-5gY"/>
<constraint firstAttribute="bottom" secondItem="47J-gQ-72v" secondAttribute="bottom" constant="12" id="pTj-6w-3fL"/>
<constraint firstItem="47J-gQ-72v" firstAttribute="leading" secondItem="fIM-wX-ThP" secondAttribute="leading" constant="12" id="tLY-wi-TIE"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eHu-E9-yMk">
<rect key="frame" x="141" y="438" width="93" height="30"/>
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
<constraints>
<constraint firstAttribute="width" constant="93" id="WtV-69-tY5"/>
<constraint firstAttribute="height" constant="30" id="pYP-ke-zF0"/>
</constraints>
<state key="normal" title="Zapisz sekret">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="storeSecret:" destination="-1" eventType="touchUpInside" id="sVO-a8-q7z"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0xi-uO-9hm">
<rect key="frame" x="143.5" y="476" width="88" height="30"/>
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="sbM-9x-AyV"/>
<constraint firstAttribute="width" constant="88" id="uiH-pa-VyX"/>
</constraints>
<state key="normal" title="Pokaż sekret">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="getSecret:" destination="-1" eventType="touchUpInside" id="cye-aX-2am"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="aiB-UR-Quk">
<rect key="frame" x="152.5" y="514" width="70" height="70"/>
<constraints>
<constraint firstAttribute="height" constant="70" id="B0t-Rd-p9j"/>
<constraint firstAttribute="width" constant="70" id="LJW-QK-sy1"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SIk-oO-kOD">
<rect key="frame" x="32" y="620" width="311" height="0.0"/>
<constraints>
<constraint firstAttribute="width" constant="311" id="KVE-6x-sQC"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="fIM-wX-ThP" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="0Uu-L2-f41"/>
<constraint firstItem="fIM-wX-ThP" firstAttribute="top" secondItem="WHD-fd-dhU" secondAttribute="bottom" constant="7.5" id="0zh-0H-6hl"/>
<constraint firstItem="fIM-wX-ThP" firstAttribute="centerY" relation="lessThanOrEqual" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="6Ln-YA-ghi"/>
<constraint firstItem="NYv-x5-X0G" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="9SD-Fn-k8d"/>
<constraint firstItem="0xi-uO-9hm" firstAttribute="top" secondItem="eHu-E9-yMk" secondAttribute="bottom" constant="8" id="Q8W-5c-khU"/>
<constraint firstItem="SIk-oO-kOD" firstAttribute="top" secondItem="aiB-UR-Quk" secondAttribute="bottom" constant="36" id="QFy-ww-vht"/>
<constraint firstItem="SIk-oO-kOD" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="QgF-DT-GKx"/>
<constraint firstItem="0xi-uO-9hm" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="UeN-Ml-sk1"/>
<constraint firstItem="aiB-UR-Quk" firstAttribute="top" secondItem="0xi-uO-9hm" secondAttribute="bottom" constant="8" id="WKd-0t-34H"/>
<constraint firstItem="fIM-wX-ThP" firstAttribute="top" secondItem="WHD-fd-dhU" secondAttribute="bottom" constant="12" id="aP2-gg-QM4"/>
<constraint firstItem="WHD-fd-dhU" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="49" id="buf-vK-MV1"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="fIM-wX-ThP" secondAttribute="trailing" constant="32" id="eeV-zF-hQt"/>
<constraint firstItem="tFe-fM-7UZ" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="feS-0C-4ss"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="SIk-oO-kOD" secondAttribute="bottom" constant="47" id="gPG-53-d0t"/>
<constraint firstAttribute="bottom" secondItem="tFe-fM-7UZ" secondAttribute="bottom" id="lKC-qE-CTz"/>
<constraint firstItem="WHD-fd-dhU" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="mjr-Xm-Z79"/>
<constraint firstItem="WHD-fd-dhU" firstAttribute="leading" secondItem="fIM-wX-ThP" secondAttribute="leading" id="n92-TL-EOh"/>
<constraint firstAttribute="bottom" secondItem="fIM-wX-ThP" secondAttribute="bottom" priority="750" constant="100" id="nvR-sM-xyu"/>
<constraint firstItem="fIM-wX-ThP" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="pxi-l5-vSk"/>
<constraint firstItem="tFe-fM-7UZ" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="qHd-7e-hwP"/>
<constraint firstItem="aiB-UR-Quk" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="rok-Oz-Hfe"/>
<constraint firstItem="eHu-E9-yMk" firstAttribute="top" secondItem="NYv-x5-X0G" secondAttribute="bottom" constant="8" id="sHf-0Z-bMJ"/>
<constraint firstItem="WHD-fd-dhU" firstAttribute="trailing" secondItem="fIM-wX-ThP" secondAttribute="trailing" id="sMj-GC-DPU"/>
<constraint firstItem="eHu-E9-yMk" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="tmc-q1-o9K"/>
<constraint firstAttribute="trailing" secondItem="tFe-fM-7UZ" secondAttribute="trailing" id="zYh-8O-PJL"/>
</constraints>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<point key="canvasLocation" x="138.40000000000001" y="152.47376311844079"/>
</view>
</objects>
<resources>
<image name="rwdevcon-bg" width="1440" height="2880"/>
</resources>
</document>

View File

@ -0,0 +1,9 @@
import Foundation
import LocalAuthentication
var biometricType: LABiometryType {
let authContext = LAContext()
return authContext.biometryType
}

View File

@ -0,0 +1,13 @@
import Foundation
extension DispatchQueue {
class func delay(_ delay: Double, closure: @escaping ()->()) {
DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + delay,
execute: closure
)
}
}

View File

@ -0,0 +1,22 @@
import UIKit
class FriendCell: UITableViewCell {
@IBOutlet var nameLabel: UILabel!
@IBOutlet var avatarImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
avatarImageView.clipsToBounds = true
avatarImageView.layer.cornerRadius = avatarImageView.bounds.width / 2
}
override func prepareForReuse() {
super.prepareForReuse()
avatarImageView.image = nil
}
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="64" id="KGk-i7-Jjw" customClass="FriendCell" customModule="Friendvatars" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="64"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="63.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="hKH-Xg-NJn">
<rect key="frame" x="16" y="8" width="47.5" height="47.5"/>
<constraints>
<constraint firstAttribute="width" secondItem="hKH-Xg-NJn" secondAttribute="height" multiplier="1:1" id="RU9-aU-BaN"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mxB-ad-p9W">
<rect key="frame" x="71.5" y="21" width="224.5" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="mxB-ad-p9W" firstAttribute="leading" secondItem="hKH-Xg-NJn" secondAttribute="trailing" constant="8" id="6Lv-Ir-hCs"/>
<constraint firstItem="mxB-ad-p9W" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="Gfd-3v-WBE"/>
<constraint firstAttribute="trailingMargin" secondItem="mxB-ad-p9W" secondAttribute="trailing" constant="8" id="MMg-vQ-Zwg"/>
<constraint firstAttribute="bottom" secondItem="hKH-Xg-NJn" secondAttribute="bottom" constant="8" id="hY6-Ld-eLy"/>
<constraint firstItem="hKH-Xg-NJn" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="prX-yv-ZMz"/>
<constraint firstItem="hKH-Xg-NJn" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="8" id="xem-fJ-fj3"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="avatarImageView" destination="hKH-Xg-NJn" id="397-KH-M7f"/>
<outlet property="nameLabel" destination="mxB-ad-p9W" id="kXC-oB-eTA"/>
</connections>
<point key="canvasLocation" x="-120" y="-75"/>
</tableViewCell>
</objects>
</document>

View File

@ -0,0 +1,103 @@
import UIKit
import CryptoSwift
final class FriendsViewController: UITableViewController {
var friends: [User] = []
var imageCache = NSCache<NSString, UIImage>()
init() {
super.init(style: .grouped)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Zabezpieczona wiadomość"
let reuseIdentifier = String(describing: FriendCell.self)
tableView.register(
UINib(nibName: reuseIdentifier, bundle: nil),
forCellReuseIdentifier: reuseIdentifier
)
navigationItem.leftBarButtonItem = UIBarButtonItem(
title: "Wyloguj się",
style: .plain,
target: self,
action: #selector(signOut)
)
friends = [
User(name: "Zakodowana1", email: "ukryty tekst1"),
User(name: "Zakodowana2", email: "ukryty tekst2"),
User(name: "Zakodowana3", email: "ukryty tekst3"),
User(name: "Zakodowana4", email: "ukryty tekst4")
]
}
// MARK: - Actions
@objc private func signOut() {
try? AuthController.signOut()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return friends.isEmpty ? 1 : 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section == 0 ? 1 : friends.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 64
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return section == 0 ? "Ja" : "Ukryte wiadomości"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: FriendCell.self)) as? FriendCell else {
fatalError()
}
let user = indexPath.section == 0 ? Settings.currentUser! : friends[indexPath.row]
cell.nameLabel.text = user.name
if let image = imageCache.object(forKey: user.email as NSString) {
cell.avatarImageView.image = image
} else {
let emailHash = user.email.trimmingCharacters(in: .whitespacesAndNewlines)
.lowercased()
.sha1()
if let url = URL(string: "https://www.gravatar.com/avatar/" + emailHash) {
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, let image = UIImage(data: data) else {
return
}
self.imageCache.setObject(image, forKey: user.email as NSString)
DispatchQueue.main.async {
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
}.resume()
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}

43
Friendvatars/Info.plist Normal file
View File

@ -0,0 +1,43 @@
<?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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,178 @@
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A struct for accessing generic password keychain items.
*/
import Foundation
struct KeychainPasswordItem {
// MARK: Types
enum KeychainError: Error {
case noPassword
case unexpectedPasswordData
case unexpectedItemData
case unhandledError(status: OSStatus)
}
// MARK: Properties
let service: String
private(set) var account: String
let accessGroup: String?
// MARK: Intialization
init(service: String, account: String, accessGroup: String? = nil) {
self.service = service
self.account = account
self.accessGroup = accessGroup
}
// MARK: Keychain access
func readPassword() throws -> String {
/*
Build a query to find the item that matches the service, account and
access group.
*/
var query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
query[kSecMatchLimit as String] = kSecMatchLimitOne
query[kSecReturnAttributes as String] = kCFBooleanTrue
query[kSecReturnData as String] = kCFBooleanTrue
// Try to fetch the existing keychain item that matches the query.
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
// Check the return status and throw an error if appropriate.
guard status != errSecItemNotFound else { throw KeychainError.noPassword }
guard status == noErr else { throw KeychainError.unhandledError(status: status) }
// Parse the password string from the query result.
guard let existingItem = queryResult as? [String : AnyObject],
let passwordData = existingItem[kSecValueData as String] as? Data,
let password = String(data: passwordData, encoding: String.Encoding.utf8)
else {
throw KeychainError.unexpectedPasswordData
}
return password
}
func savePassword(_ password: String) throws {
// Encode the password into an Data object.
let encodedPassword = password.data(using: String.Encoding.utf8)!
do {
// Check for an existing item in the keychain.
try _ = readPassword()
// Update the existing item with the new password.
var attributesToUpdate = [String : AnyObject]()
attributesToUpdate[kSecValueData as String] = encodedPassword as AnyObject?
let query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
// Throw an error if an unexpected status was returned.
guard status == noErr else { throw KeychainError.unhandledError(status: status) }
}
catch KeychainError.noPassword {
/*
No password was found in the keychain. Create a dictionary to save
as a new keychain item.
*/
var newItem = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
newItem[kSecValueData as String] = encodedPassword as AnyObject?
// Add a the new item to the keychain.
let status = SecItemAdd(newItem as CFDictionary, nil)
// Throw an error if an unexpected status was returned.
guard status == noErr else { throw KeychainError.unhandledError(status: status) }
}
}
mutating func renameAccount(_ newAccountName: String) throws {
// Try to update an existing item with the new account name.
var attributesToUpdate = [String : AnyObject]()
attributesToUpdate[kSecAttrAccount as String] = newAccountName as AnyObject?
let query = KeychainPasswordItem.keychainQuery(withService: service, account: self.account, accessGroup: accessGroup)
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
// Throw an error if an unexpected status was returned.
guard status == noErr || status == errSecItemNotFound else { throw KeychainError.unhandledError(status: status) }
self.account = newAccountName
}
func deleteItem() throws {
// Delete the existing item from the keychain.
let query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
let status = SecItemDelete(query as CFDictionary)
// Throw an error if an unexpected status was returned.
guard status == noErr || status == errSecItemNotFound else { throw KeychainError.unhandledError(status: status) }
}
static func passwordItems(forService service: String, accessGroup: String? = nil) throws -> [KeychainPasswordItem] {
// Build a query for all items that match the service and access group.
var query = KeychainPasswordItem.keychainQuery(withService: service, accessGroup: accessGroup)
query[kSecMatchLimit as String] = kSecMatchLimitAll
query[kSecReturnAttributes as String] = kCFBooleanTrue
query[kSecReturnData as String] = kCFBooleanFalse
// Fetch matching items from the keychain.
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
// If no items were found, return an empty array.
guard status != errSecItemNotFound else { return [] }
// Throw an error if an unexpected status was returned.
guard status == noErr else { throw KeychainError.unhandledError(status: status) }
// Cast the query result to an array of dictionaries.
guard let resultData = queryResult as? [[String : AnyObject]] else { throw KeychainError.unexpectedItemData }
// Create a `KeychainPasswordItem` for each dictionary in the query result.
var passwordItems = [KeychainPasswordItem]()
for result in resultData {
guard let account = result[kSecAttrAccount as String] as? String else { throw KeychainError.unexpectedItemData }
let passwordItem = KeychainPasswordItem(service: service, account: account, accessGroup: accessGroup)
passwordItems.append(passwordItem)
}
return passwordItems
}
// MARK: Convenience
private static func keychainQuery(withService service: String, account: String? = nil, accessGroup: String? = nil) -> [String : AnyObject] {
var query = [String : AnyObject]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrService as String] = service as AnyObject?
if let account = account {
query[kSecAttrAccount as String] = account as AnyObject?
}
if let accessGroup = accessGroup {
query[kSecAttrAccessGroup as String] = accessGroup as AnyObject?
}
return query
}
}

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="rwdevcon-bg" translatesAutoresizingMaskIntoConstraints="NO" id="thr-yb-z25">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="rw-logo" translatesAutoresizingMaskIntoConstraints="NO" id="skm-4Q-SEq">
<rect key="frame" x="20" y="166" width="335" height="335"/>
<constraints>
<constraint firstAttribute="width" secondItem="skm-4Q-SEq" secondAttribute="height" multiplier="1:1" id="F6J-6J-J5s"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="thr-yb-z25" secondAttribute="trailing" id="0Yk-op-Sbr"/>
<constraint firstItem="skm-4Q-SEq" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="0tf-Kh-S2U"/>
<constraint firstItem="skm-4Q-SEq" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Bcu-3y-fUS" secondAttribute="top" constant="20" id="45c-ps-A1j"/>
<constraint firstAttribute="trailing" secondItem="skm-4Q-SEq" secondAttribute="trailing" constant="20" id="Aji-Ek-k2q"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="thr-yb-z25" secondAttribute="bottom" id="FXS-f4-xfH"/>
<constraint firstItem="skm-4Q-SEq" firstAttribute="width" secondItem="skm-4Q-SEq" secondAttribute="height" multiplier="1:1" id="Q4h-h8-kju"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="skm-4Q-SEq" secondAttribute="bottom" constant="20" id="TPw-KF-H85"/>
<constraint firstItem="thr-yb-z25" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="bHm-5w-uXH"/>
<constraint firstItem="thr-yb-z25" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="mnU-3N-lrW"/>
<constraint firstItem="skm-4Q-SEq" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" id="uY3-7w-Cr7"/>
<constraint firstItem="skm-4Q-SEq" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="wkC-oo-tPK"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="rw-logo" width="512" height="512"/>
<image name="rwdevcon-bg" width="1104" height="1104"/>
</resources>
</document>

View File

@ -0,0 +1,22 @@
import UIKit
final class NavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.tintColor = .white
navigationBar.barTintColor = .rwGreen
navigationBar.prefersLargeTitles = true
navigationBar.titleTextAttributes = [
NSAttributedStringKey.foregroundColor: UIColor.white
]
navigationBar.largeTitleTextAttributes = navigationBar.titleTextAttributes
}
}

View File

@ -0,0 +1,28 @@
import Foundation
final class Settings {
private enum Keys: String {
case user = "current_user"
}
static var currentUser: User? {
get {
guard let data = UserDefaults.standard.data(forKey: Keys.user.rawValue) else {
return nil
}
return try? JSONDecoder().decode(User.self, from: data)
}
set {
if let data = try? JSONEncoder().encode(newValue) {
UserDefaults.standard.set(data, forKey: Keys.user.rawValue)
} else {
UserDefaults.standard.removeObject(forKey: Keys.user.rawValue)
}
UserDefaults.standard.synchronize()
}
}
}

View File

@ -0,0 +1,72 @@
import UIKit
final class SplashViewController: UIViewController {
override var prefersStatusBarHidden: Bool {
return true
}
private let backgroundImageView = UIImageView()
private let logoImageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if AuthController.isSignedIn {
AppController.shared.handleAuthState()
} else {
DispatchQueue.delay(1) {
self.animateAndDismiss()
}
}
}
private func setupView() {
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
backgroundImageView.contentMode = .scaleAspectFill
backgroundImageView.image = #imageLiteral(resourceName: "rwdevcon-bg")
logoImageView.translatesAutoresizingMaskIntoConstraints = false
logoImageView.contentMode = .scaleAspectFit
logoImageView.image = #imageLiteral(resourceName: "rw-logo")
view.addSubview(backgroundImageView)
view.addSubview(logoImageView)
NSLayoutConstraint.activate([
backgroundImageView.topAnchor.constraint(equalTo: view.topAnchor),
backgroundImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
backgroundImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backgroundImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
logoImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
logoImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor),
logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
logoImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
private func animateAndDismiss() {
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 0.3
animation.fromValue = 1
animation.toValue = 0
CATransaction.begin()
CATransaction.setCompletionBlock {
AppController.shared.handleAuthState()
}
logoImageView.layer.add(animation, forKey: "scale")
logoImageView.transform = CGAffineTransform(scaleX: 0, y: 0)
CATransaction.commit()
}
}

View File

@ -0,0 +1,8 @@
import UIKit
extension UIColor {
static let rwGreen = UIColor(red: 0.0/255.0, green: 104.0/255.0, blue: 55.0/255.0, alpha: 1.0)
}

9
Friendvatars/User.swift Normal file
View File

@ -0,0 +1,9 @@
import Foundation
struct User: Codable {
let name: String
let email: String
}

7
Podfile Normal file
View File

@ -0,0 +1,7 @@
platform :ios, '8.0'
use_frameworks!
target 'Friendvatars' do
pod 'CryptoSwift'
pod 'KeychainAccess'
end

20
Podfile.lock Normal file
View File

@ -0,0 +1,20 @@
PODS:
- CryptoSwift (0.8.1)
- KeychainAccess (3.1.2)
DEPENDENCIES:
- CryptoSwift
- KeychainAccess
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- CryptoSwift
- KeychainAccess
SPEC CHECKSUMS:
CryptoSwift: 4b07d5b508c1eb67bfa314a727b705f8048a85de
KeychainAccess: b3816fddcf28aa29d94b10ec305cd52be14c472b
PODFILE CHECKSUM: 2ccd80ba9984103c7eb7f1175a88d0a90df6c731
COCOAPODS: 1.5.3

10
Pods/CryptoSwift/LICENSE generated Normal file
View File

@ -0,0 +1,10 @@
Copyright (C) 2014-2017 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.

431
Pods/CryptoSwift/README.md generated Normal file
View File

@ -0,0 +1,431 @@
[![Platform](https://img.shields.io/badge/Platforms-ios%20%7C%20macos%20%7C%20watchos%20%7C%20tvos%20%7C%20linux-4E4E4E.svg?colorA=EF5138)](http://cocoadocs.org/docsets/CryptoSwift)
[![Swift support](https://img.shields.io/badge/Swift-3.1%20%7C%203.2%20%7C%204.0-lightgrey.svg?colorA=EF5138&colorB=4E4E4E)](#swift-versions-support)
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/CryptoSwift.svg?style=flat&label=CocoaPods)](https://cocoapods.org/pods/CryptoSwift)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat&colorB=64A5DE)](https://github.com/apple/swift-package-manager)
[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat&colorB=64A5DE)](https://github.com/apple/swift-package-manager)
[![Twitter](https://img.shields.io/badge/twitter-@krzyzanowskim-blue.svg?style=flat&colorB=64A5DE&label=Twitter)](http://twitter.com/krzyzanowskim)
# CryptoSwift
Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift))
# Table of Contents
- [Requirements](#requirements)
- [Features](#features)
- [Contribution](#contribution)
- [Installation](#installation)
- [Swift versions](#swift-versions-support)
- [Usage](#usage)
- [Author](#author)
- [License](#license)
- [Changelog](#changelog)
## Requirements
Good mood
## Features
- Easy to use
- Convenient extensions for String and Data
- Support for incremental updates (stream, ...)
- iOS, macOS, AppleTV, watchOS, Linux support
## Donation
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=92Z6U3LBHF9J4) to make the CryptoSwift awesome! Thank you.
#### Hash (Digest)
- [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)
- [SHA3](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
#### 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)
- [Blowfish](https://www.schneier.com/academic/blowfish/)
#### 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))
#### Password-Based Key Derivation Function
- [PBKDF1](http://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1)
- [PBKDF2](http://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2)
- [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function)
#### Data padding
- PKCS#5
- [PKCS#7](http://tools.ietf.org/html/rfc5652#section-6.3)
- [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding)
- No padding
## Why
[Why?](https://github.com/krzyzanowskim/CryptoSwift/issues/5) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/issues/5#issuecomment-53379391).
## Contribution
For the latest version, please check [develop](https://github.com/krzyzanowskim/CryptoSwift/tree/develop) branch. Changes from this branch will be merged into the [master](https://github.com/krzyzanowskim/CryptoSwift/tree/master) branch at some point.
- If you want to contribute, submit a [pull request](https://github.com/krzyzanowskim/CryptoSwift/pulls) against a development `develop` branch.
- 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
It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance.
#### 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)
Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target
![](https://cloud.githubusercontent.com/assets/758033/18415615/d5edabb0-77f8-11e6-8c94-f41d9fc2b8cb.png)
##### iOS, macOS, watchOS, tvOS
In the project, you'll find [single scheme](http://promisekit.org/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms:
- CryptoSwift
#### Swift versions support
- Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13
- Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3
- Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2
- Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9
- Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0
- Swift 4.0, branch [master](https://github.com/krzyzanowskim/CryptoSwift/tree/master) version >= 0.7.1
#### CocoaPods
You can use [CocoaPods](http://cocoapods.org/?q=cryptoSwift).
```ruby
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'CryptoSwift'
end
```
or for newest version from specified branch of code:
```ruby
pod 'CryptoSwift', :git => "https://github.com/krzyzanowskim/CryptoSwift", :branch => "master"
```
Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that my impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin.
#### 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). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/issues/492#issuecomment-330822874).
#### Swift Package Manager
You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
```swift
dependencies: [
.Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0)
]
```
or more strict
```swift
dependencies: [
.Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", "0.7.2"),
]
```
See: [Package.swift - manual](http://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/)
## Usage
* [Basics (data types, conversion, ...)](#basics)
* [Digest (MD5, SHA...)](#calculate-digest)
* [Message authenticators (HMAC...)](#message-authenticators-1)
* [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions)
* [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function)
* [Data Padding](#data-padding)
* [ChaCha20](#chacha20)
* [Rabbit](#rabbit)
* [Blowfish](#blowfish)
* [Advanced Encryption Standard (AES)](#aes)
also check [Playground](/CryptoSwift.playground/Contents.swift)
##### Basics
```swift
import CryptoSwift
```
CryptoSwift uses array of bytes aka `Array<UInt8>` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes.
##### Data types conversion
For you convenience **CryptoSwift** provides two functions to easily convert array of bytes to `Data` and another way around:
Data from bytes:
```swift
let data = Data(bytes: [0x01, 0x02, 0x03])
```
`Data` to `Array<UInt8>`
```swift
let bytes = data.bytes // [1,2,3]
```
[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding:
```swift
let bytes = Array<UInt8>(hex: "0x010203") // [1,2,3]
let hex = bytes.toHexString() // "010203"
```
Build bytes out of `String`
```swift
let bytes: Array<UInt8> = "password".bytes // Array("password".utf8)
```
Also... check out helpers that work with **Base64** encoded data:
```swift
"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
bytes.toBase64()
```
##### Calculate Digest
Hashing a data or array of bytes (aka `Array<UInt8>`)
```swift
/* Hash struct usage */
let bytes:Array<UInt8> = [0x01, 0x02, 0x03]
let digest = input.md5()
let digest = Digest.md5(bytes)
```
```swift
let data = Data(bytes: [0x01, 0x02, 0x03])
let hash = data.md5()
let hash = data.sha1()
let hash = data.sha224()
let hash = data.sha256()
let hash = data.sha384()
let hash = data.sha512()
```
```swift
do {
var digest = MD5()
let partial1 = try digest.update(withBytes: [0x31, 0x32])
let partial2 = try digest.update(withBytes: [0x33])
let result = try digest.finish()
} catch { }
```
Hashing a String and printing result
```swift
let hash = "123".md5() // "123".bytes.md5()
```
##### Calculate CRC
```swift
bytes.crc16()
data.crc16()
bytes.crc32()
data.crc32()
```
##### Message authenticators
```swift
// Calculate Message Authentication Code (MAC) for message
let key:Array<UInt8> = [1,2,3,4,5,6,7,8,9,10,...]
try Poly1305(key: key).authenticate(bytes)
try HMAC(key: key, variant: .sha256).authenticate(bytes)
```
##### Password-Based Key Derivation Functions
```swift
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, variant: .sha256).calculate()
```
##### HMAC-based Key Derivation Function
```swift
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
try HKDF(password: password, salt: salt, variant: .sha256).calculate()
```
##### Data Padding
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
Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize)
```
#### Working with Ciphers
##### ChaCha20
```swift
let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message)
let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted)
```
##### Rabbit
```swift
let encrypted = try Rabbit(key: key, iv: iv).encrypt(message)
let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
```
##### Blowfish
```swift
let encrypted = try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).encrypt(message)
let decrypted = try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
```
##### AES
Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need manually disable/enable padding, you can do this by setting parameter for __AES__ class*
Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length:
- AES-128 = 16 bytes
- AES-192 = 24 bytes
- AES-256 = 32 bytes
AES-256 example
```swift
try AES(key: [1,2,3,...,32], blockMode: .CBC(iv: [1,2,3,...,16]), padding: .pkcs7)
```
###### All at once
```swift
do {
let aes = try AES(key: "passwordpassword", iv: "drowssapdrowssap") // aes128
let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8))
} catch { }
```
###### Incremental updates
Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files.
```swift
do {
var encryptor = try AES(key: "passwordpassword", iv: "drowssapdrowssap").makeEncryptor()
var ciphertext = Array<UInt8>()
// aggregate partial results
ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8))
// finish at the end
ciphertext += try encryptor.finish()
print(ciphertext.toHexString())
} catch {
print(error)
}
```
See [Playground](/CryptoSwift.playground/Contents.swift) for sample code that work with stream.
###### AES Advanced usage
```swift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: Array<UInt8> = AES.randomIV(AES.blockSize)
do {
let encrypted = try AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).encrypt(input)
let decrypted = try AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
} catch {
print(error)
}
```
AES without data padding
```swift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let encrypted: Array<UInt8> = try! AES(key: Array("secret0key000000".utf8), blockMode: .CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)
```
Using convenience extensions
```swift
let plain = Data(bytes: [0x01, 0x02, 0x03])
let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv))
let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
```
## Author
CryptoSwift is owned and maintained by [Marcin Krzyżanowski](http://www.krzyzanowskim.com)
You can follow me on Twitter at [@krzyzanowskim](http://twitter.com/krzyzanowskim) for project updates and releases.
## License
Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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

@ -0,0 +1,142 @@
//
// AES.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// MARK: Cryptors
extension AES: Cryptors {
public func makeEncryptor() throws -> AES.Encryptor {
return try AES.Encryptor(aes: self)
}
public func makeDecryptor() throws -> AES.Decryptor {
return try AES.Decryptor(aes: self)
}
}
// MARK: Encryptor
extension AES {
public struct Encryptor: Updatable {
private var worker: BlockModeWorker
private let padding: Padding
private var accumulated = Array<UInt8>()
private var processedBytesTotalCount: Int = 0
private let paddingRequired: Bool
init(aes: AES) throws {
padding = aes.padding
worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.encrypt)
paddingRequired = aes.blockMode.options.contains(.paddingRequired)
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
accumulated += bytes
if isLast {
accumulated = padding.add(to: accumulated, blockSize: AES.blockSize)
}
var processedBytes = 0
var encrypted = Array<UInt8>(reserveCapacity: accumulated.count)
for chunk in accumulated.batched(by: AES.blockSize) {
if isLast || (accumulated.count - processedBytes) >= AES.blockSize {
encrypted += worker.encrypt(chunk)
processedBytes += chunk.count
}
}
accumulated.removeFirst(processedBytes)
processedBytesTotalCount += processedBytes
return encrypted
}
}
}
// MARK: Decryptor
extension AES {
public struct Decryptor: RandomAccessCryptor {
private var worker: BlockModeWorker
private let padding: Padding
private var accumulated = Array<UInt8>()
private var processedBytesTotalCount: Int = 0
private let paddingRequired: Bool
private var offset: Int = 0
private var offsetToRemove: Int = 0
init(aes: AES) throws {
padding = aes.padding
switch aes.blockMode {
case .CFB, .OFB, .CTR:
// CFB, OFB, CTR uses encryptBlock to decrypt
worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.encrypt)
default:
worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.decrypt)
}
paddingRequired = aes.blockMode.options.contains(.paddingRequired)
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
// prepend "offset" number of bytes at the begining
if offset > 0 {
accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
offsetToRemove = offset
offset = 0
} else {
accumulated += bytes
}
var processedBytes = 0
var plaintext = Array<UInt8>(reserveCapacity: accumulated.count)
for chunk in accumulated.batched(by: AES.blockSize) {
if isLast || (accumulated.count - processedBytes) >= AES.blockSize {
plaintext += worker.decrypt(chunk)
// remove "offset" from the beginning of first chunk
if offsetToRemove > 0 {
plaintext.removeFirst(offsetToRemove)
offsetToRemove = 0
}
processedBytes += chunk.count
}
}
accumulated.removeFirst(processedBytes)
processedBytesTotalCount += processedBytes
if isLast {
plaintext = padding.remove(from: plaintext, blockSize: AES.blockSize)
}
return plaintext
}
@discardableResult public mutating func seek(to position: Int) -> Bool {
guard var worker = self.worker as? RandomAccessBlockModeWorker else {
return false
}
worker.counter = UInt(position / AES.blockSize)
self.worker = worker
offset = position % AES.blockSize
accumulated = []
return true
}
}
}

View File

@ -0,0 +1,532 @@
//
// AES.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Implementation of Gladman algorithm http://www.gladman.me.uk/AES
//
/// The Advanced Encryption Standard (AES)
public final class AES: BlockCipher {
public enum Error: Swift.Error {
/// Data padding is required
case dataPaddingRequired
/// Invalid Data
case invalidData
}
public enum Variant: 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
}
}
private lazy var variantNr: Int = self.variant.Nr
private lazy var variantNb: Int = self.variant.Nb
private lazy var variantNk: Int = self.variant.Nk
public static let blockSize: Int = 16 // 128 /8
public var variant: Variant {
switch key.count * 8 {
case 128:
return .aes128
case 192:
return .aes192
case 256:
return .aes256
default:
preconditionFailure("Unknown AES variant for given key.")
}
}
// Parameters
let key: Key
let blockMode: BlockMode
let padding: Padding
//
private lazy var expandedKey: Array<Array<UInt32>> = self.expandKey(self.key, variant: self.variant)
private lazy var expandedKeyInv: Array<Array<UInt32>> = self.expandKeyInv(self.key, variant: self.variant)
private lazy var sBoxes: (sBox: Array<UInt32>, invSBox: Array<UInt32>) = self.calculateSBox()
private lazy var sBox: Array<UInt32> = self.sBoxes.sBox
private lazy var sBoxInv: Array<UInt32> = self.sBoxes.invSBox
// Parameters for Linear Congruence Generators
private static let Rcon: Array<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 static let T0: Array<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 static let T0_INV: Array<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 static let T1: Array<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 static let T1_INV: Array<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 static let T2: Array<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 static let T2_INV: Array<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 static let T3: Array<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 static let T3_INV: Array<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 static let U1: Array<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 static let U2: Array<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 static let U3: Array<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 static let U4: Array<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]
/// Initialize AES with variant calculated out of key length:
/// - 16 bytes (AES-128)
/// - 24 bytes (AES-192)
/// - 32 bytes (AES-256)
///
/// - parameter key: Key. Length of the key decides on AES variant.
/// - parameter iv: Initialization Vector (Optional for some blockMode values)
/// - parameter blockMode: Cipher mode of operation
/// - parameter padding: Padding method. .pkcs7, .noPadding, .zeroPadding, ...
///
/// - throws: AES.Error
///
/// - returns: Instance
public init(key: Array<UInt8>, blockMode: BlockMode, padding: Padding = .pkcs7) throws {
self.key = Key(bytes: key)
self.blockMode = blockMode
self.padding = padding
}
internal func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
if blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
return Array(block)
}
let rounds = variantNr
let rk = expandedKey
let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
var b0 = b00 | b01 | b02 | b03
let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
var b1 = b10 | b11 | b12 | b13
let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
var b2 = b20 | b21 | b22 | b23
let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
var b3 = b30 | b31 | b32 | b33
let tLength = 4
let t = UnsafeMutablePointer<UInt32>.allocate(capacity: tLength)
t.initialize(to: 0, count: tLength)
defer {
t.deinitialize(count: tLength)
t.deallocate(capacity: tLength)
}
for r in 0..<rounds - 1 {
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
let lb00 = AES.T0[Int(t[0] & 0xff)]
let lb01 = AES.T1[Int((t[1] >> 8) & 0xff)]
let lb02 = AES.T2[Int((t[2] >> 16) & 0xff)]
let lb03 = AES.T3[Int(t[3] >> 24)]
b0 = lb00 ^ lb01 ^ lb02 ^ lb03
let lb10 = AES.T0[Int(t[1] & 0xff)]
let lb11 = AES.T1[Int((t[2] >> 8) & 0xff)]
let lb12 = AES.T2[Int((t[3] >> 16) & 0xff)]
let lb13 = AES.T3[Int(t[0] >> 24)]
b1 = lb10 ^ lb11 ^ lb12 ^ lb13
let lb20 = AES.T0[Int(t[2] & 0xff)]
let lb21 = AES.T1[Int((t[3] >> 8) & 0xff)]
let lb22 = AES.T2[Int((t[0] >> 16) & 0xff)]
let lb23 = AES.T3[Int(t[1] >> 24)]
b2 = lb20 ^ lb21 ^ lb22 ^ lb23
let lb30 = AES.T0[Int(t[3] & 0xff)]
let lb31 = AES.T1[Int((t[0] >> 8) & 0xff)]
let lb32 = AES.T2[Int((t[1] >> 16) & 0xff)]
let lb33 = AES.T3[Int(t[2] >> 24)]
b3 = lb30 ^ lb31 ^ lb32 ^ lb33
}
// last round
let r = rounds - 1
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
// rounds
b0 = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0]
b1 = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
b2 = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
b3 = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
let encrypted: Array<UInt8> = [
UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff),
]
return encrypted
}
internal func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
if blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
return Array(block)
}
let rounds = variantNr
let rk = expandedKeyInv
// Save miliseconds by not using `block.toUInt32Array()`
let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
var b0 = b00 | b01 | b02 | b03
let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
var b1 = b10 | b11 | b12 | b13
let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
var b2 = b20 | b21 | b22 | b23
let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
var b3 = b30 | b31 | b32 | b33
let tLength = 4
let t = UnsafeMutablePointer<UInt32>.allocate(capacity: tLength)
t.initialize(to: 0, count: tLength)
defer {
t.deinitialize(count: tLength)
t.deallocate(capacity: tLength)
}
for r in (2...rounds).reversed() {
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
let b00 = AES.T0_INV[Int(t[0] & 0xff)]
let b01 = AES.T1_INV[Int((t[3] >> 8) & 0xff)]
let b02 = AES.T2_INV[Int((t[2] >> 16) & 0xff)]
let b03 = AES.T3_INV[Int(t[1] >> 24)]
b0 = b00 ^ b01 ^ b02 ^ b03
let b10 = AES.T0_INV[Int(t[1] & 0xff)]
let b11 = AES.T1_INV[Int((t[0] >> 8) & 0xff)]
let b12 = AES.T2_INV[Int((t[3] >> 16) & 0xff)]
let b13 = AES.T3_INV[Int(t[2] >> 24)]
b1 = b10 ^ b11 ^ b12 ^ b13
let b20 = AES.T0_INV[Int(t[2] & 0xff)]
let b21 = AES.T1_INV[Int((t[1] >> 8) & 0xff)]
let b22 = AES.T2_INV[Int((t[0] >> 16) & 0xff)]
let b23 = AES.T3_INV[Int(t[3] >> 24)]
b2 = b20 ^ b21 ^ b22 ^ b23
let b30 = AES.T0_INV[Int(t[3] & 0xff)]
let b31 = AES.T1_INV[Int((t[2] >> 8) & 0xff)]
let b32 = AES.T2_INV[Int((t[1] >> 16) & 0xff)]
let b33 = AES.T3_INV[Int(t[0] >> 24)]
b3 = b30 ^ b31 ^ b32 ^ b33
}
// last round
t[0] = b0 ^ rk[1][0]
t[1] = b1 ^ rk[1][1]
t[2] = b2 ^ rk[1][2]
t[3] = b3 ^ 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)
b0 = 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)
b1 = 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)
b2 = 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)
b3 = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
let result: Array<UInt8> = [
UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff),
]
return result
}
}
private extension AES {
private func expandKeyInv(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
let rounds = variantNr
var rk2: Array<Array<UInt32>> = expandKey(key, variant: variant)
for r in 1..<rounds {
for i in 0..<4 {
let w = rk2[r][i]
let u1 = AES.U1[Int(B0(w))]
let u2 = AES.U2[Int(B1(w))]
let u3 = AES.U3[Int(B2(w))]
let u4 = AES.U4[Int(B3(w))]
rk2[r][i] = u1 ^ u2 ^ u3 ^ u4
}
}
return rk2
}
private func expandKey(_ key: Key, variant _: Variant) -> Array<Array<UInt32>> {
func convertExpandedKey(_ expanded: Array<UInt8>) -> Array<Array<UInt32>> {
return expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map({ Array($0) })
}
/*
* 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: Array<UInt8>) -> Array<UInt8> {
precondition(word.count == 4)
var result = word
for i in 0..<4 {
result[i] = UInt8(sBox[Int(word[i])])
}
return result
}
@inline(__always)
func subWordInPlace(_ word: inout Array<UInt8>) {
precondition(word.count == 4)
word[0] = UInt8(sBox[Int(word[0])])
word[1] = UInt8(sBox[Int(word[1])])
word[2] = UInt8(sBox[Int(word[2])])
word[3] = UInt8(sBox[Int(word[3])])
}
let wLength = variantNb * (variantNr + 1) * 4
let w = UnsafeMutablePointer<UInt8>.allocate(capacity: wLength)
w.initialize(to: 0, count: wLength)
defer {
w.deinitialize(count: wLength)
w.deallocate(capacity: wLength)
}
for i in 0..<variantNk {
for wordIdx in 0..<4 {
w[(4 * i) + wordIdx] = key[(4 * i) + wordIdx]
}
}
var tmp: Array<UInt8>
for i in variantNk..<variantNb * (variantNr + 1) {
tmp = Array<UInt8>(repeating: 0, count: 4)
for wordIdx in 0..<4 {
tmp[wordIdx] = w[4 * (i - 1) + wordIdx]
}
if (i % variantNk) == 0 {
tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: 4))
tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk]
} else if variantNk > 6 && (i % variantNk) == 4 {
subWordInPlace(&tmp)
}
// xor array of bytes
for wordIdx in 0..<4 {
w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx]
}
}
return convertExpandedKey(Array(UnsafeBufferPointer(start: w, count: wLength)))
}
@inline(__always)
private func B0(_ x: UInt32) -> UInt32 {
return x & 0xff
}
@inline(__always)
private func B1(_ x: UInt32) -> UInt32 {
return (x >> 8) & 0xff
}
@inline(__always)
private func B2(_ x: UInt32) -> UInt32 {
return (x >> 16) & 0xff
}
@inline(__always)
private func B3(_ x: UInt32) -> UInt32 {
return (x >> 24) & 0xff
}
@inline(__always)
private func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
var result: UInt32 = 0
result |= UInt32(B1(AES.T0[Int(x0 & 255)]))
result |= UInt32(B1(AES.T0[Int((x1 >> 8) & 255)])) << 8
result |= UInt32(B1(AES.T0[Int((x2 >> 16) & 255)])) << 16
result |= UInt32(B1(AES.T0[Int(x3 >> 24)])) << 24
return result
}
private func calculateSBox() -> (sBox: Array<UInt32>, invSBox: Array<UInt32>) {
let sboxLength = 256
let sbox = UnsafeMutablePointer<UInt32>.allocate(capacity: sboxLength)
let invsbox = UnsafeMutablePointer<UInt32>.allocate(capacity: sboxLength)
sbox.initialize(to: 0, count: sboxLength)
invsbox.initialize(to: 0, count: sboxLength)
defer {
sbox.deinitialize(count: sboxLength)
sbox.deallocate(capacity: sboxLength)
invsbox.deinitialize(count: sboxLength)
invsbox.deallocate(capacity: sboxLength)
}
sbox[0] = 0x63
var p: UInt8 = 1, q: UInt8 = 1
repeat {
p = p ^ (UInt8(truncatingIfNeeded: 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, by: 1) ^ rotateLeft(q, by: 2) ^ rotateLeft(q, by: 3) ^ rotateLeft(q, by: 4)
sbox[Int(p)] = UInt32(s)
invsbox[Int(s)] = UInt32(p)
} while (p != 1)
return (sBox: Array(UnsafeBufferPointer(start: sbox, count: sboxLength)), invSBox: Array(UnsafeBufferPointer(start: invsbox, count: sboxLength)))
}
}
// MARK: Cipher
extension AES: Cipher {
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
let chunks = bytes.batched(by: AES.blockSize)
var oneTimeCryptor = try self.makeEncryptor()
var out = Array<UInt8>(reserveCapacity: bytes.count)
for chunk in chunks {
out += try oneTimeCryptor.update(withBytes: chunk, isLast: false)
}
// Padding may be added at the very end
out += try oneTimeCryptor.finish()
if blockMode.options.contains(.paddingRequired) && (out.count % AES.blockSize != 0) {
throw Error.dataPaddingRequired
}
return out
}
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
if blockMode.options.contains(.paddingRequired) && (bytes.count % AES.blockSize != 0) {
throw Error.dataPaddingRequired
}
var oneTimeCryptor = try self.makeDecryptor()
let chunks = bytes.batched(by: AES.blockSize)
if chunks.isEmpty {
throw Error.invalidData
}
var out = Array<UInt8>(reserveCapacity: bytes.count)
var lastIdx = chunks.startIndex
chunks.indices.formIndex(&lastIdx, offsetBy: chunks.count - 1)
// To properly remove padding, `isLast` has to be known when called with the last chunk of ciphertext
// Last chunk of ciphertext may contains padded data so next call to update(..) won't be able to remove it
for idx in chunks.indices {
out += try oneTimeCryptor.update(withBytes: chunks[idx], isLast: idx == lastIdx)
}
return out
}
}

View File

@ -0,0 +1,85 @@
//
// ArrayExtension.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
extension Array {
init(reserveCapacity: Int) {
self = Array<Element>()
self.reserveCapacity(reserveCapacity)
}
var slice: ArraySlice<Element> {
return self[self.startIndex..<self.endIndex]
}
}
extension Array {
/// split in chunks with given chunk size
@available(*, deprecated: 0.8.0, message: "")
public func chunks(size chunksize: Int) -> Array<Array<Element>> {
var words = Array<Array<Element>>()
words.reserveCapacity(count / chunksize)
for idx in stride(from: chunksize, through: count, by: chunksize) {
words.append(Array(self[idx - chunksize..<idx])) // slow for large table
}
let remainder = suffix(count % chunksize)
if !remainder.isEmpty {
words.append(Array(remainder))
}
return words
}
}
extension Array where Element == UInt8 {
public init(hex: String) {
self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount)
var buffer: UInt8?
var skip = hex.hasPrefix("0x") ? 2 : 0
for char in hex.unicodeScalars.lazy {
guard skip == 0 else {
skip -= 1
continue
}
guard char.value >= 48 && char.value <= 102 else {
removeAll()
return
}
let v: UInt8
let c: UInt8 = UInt8(char.value)
switch c {
case let c where c <= 57:
v = c - 48
case let c where c >= 65 && c <= 70:
v = c - 55
case let c where c >= 97:
v = c - 87
default:
removeAll()
return
}
if let b = buffer {
append(b << 4 | v)
buffer = nil
} else {
buffer = v
}
}
if let b = buffer {
append(b)
}
}
}

View File

@ -0,0 +1,83 @@
//
// Array+Extensions.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
public extension Array where Element == UInt8 {
public func toHexString() -> String {
return `lazy`.reduce("") {
var s = String($1, radix: 16)
if s.count == 1 {
s = "0" + s
}
return $0 + s
}
}
}
public extension Array where Element == UInt8 {
public func md5() -> [Element] {
return Digest.md5(self)
}
public func sha1() -> [Element] {
return Digest.sha1(self)
}
public func sha224() -> [Element] {
return Digest.sha224(self)
}
public func sha256() -> [Element] {
return Digest.sha256(self)
}
public func sha384() -> [Element] {
return Digest.sha384(self)
}
public func sha512() -> [Element] {
return Digest.sha512(self)
}
public func sha2(_ variant: SHA2.Variant) -> [Element] {
return Digest.sha2(self, variant: variant)
}
public func sha3(_ variant: SHA3.Variant) -> [Element] {
return Digest.sha3(self, variant: variant)
}
public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
return Checksum.crc32(self, seed: seed, reflect: reflect)
}
public func crc16(seed: UInt16? = nil) -> UInt16 {
return Checksum.crc16(self, seed: seed)
}
public func encrypt(cipher: Cipher) throws -> [Element] {
return try cipher.encrypt(slice)
}
public func decrypt(cipher: Cipher) throws -> [Element] {
return try cipher.decrypt(slice)
}
public func authenticate<A: Authenticator>(with authenticator: A) throws -> [Element] {
return try authenticator.authenticate(self)
}
}

View File

@ -0,0 +1,21 @@
//
// MAC.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
/// Message authentication code.
public protocol Authenticator {
/// Calculate Message Authentication Code (MAC) for message.
func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8>
}

View File

@ -0,0 +1,65 @@
//
// BatchedCollection.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
struct BatchedCollectionIndex<Base: Collection> {
let range: Range<Base.Index>
}
extension BatchedCollectionIndex: Comparable {
static func ==<Base>(lhs: BatchedCollectionIndex<Base>, rhs: BatchedCollectionIndex<Base>) -> Bool {
return lhs.range.lowerBound == rhs.range.lowerBound
}
static func < <Base>(lhs: BatchedCollectionIndex<Base>, rhs: BatchedCollectionIndex<Base>) -> Bool {
return lhs.range.lowerBound < rhs.range.lowerBound
}
}
protocol BatchedCollectionType: Collection {
associatedtype Base: Collection
}
struct BatchedCollection<Base: Collection>: Collection {
let base: Base
let size: Base.IndexDistance
typealias Index = BatchedCollectionIndex<Base>
private func nextBreak(after idx: Base.Index) -> Base.Index {
return base.index(idx, offsetBy: size, limitedBy: base.endIndex)
?? base.endIndex
}
var startIndex: Index {
return Index(range: base.startIndex..<nextBreak(after: base.startIndex))
}
var endIndex: Index {
return Index(range: base.endIndex..<base.endIndex)
}
func index(after idx: Index) -> Index {
return Index(range: idx.range.upperBound..<nextBreak(after: idx.range.upperBound))
}
subscript(idx: Index) -> Base.SubSequence {
return base[idx.range]
}
}
extension Collection {
func batched(by size: IndexDistance) -> BatchedCollection<Self> {
return BatchedCollection(base: self, size: size)
}
}

View File

@ -0,0 +1,27 @@
//
// Bit.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
public enum Bit: Int {
case zero
case one
}
extension Bit {
func inverted() -> Bit {
return self == .zero ? .one : .zero
}
}

View File

@ -0,0 +1,19 @@
//
// BlockCipher.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
protocol BlockCipher: Cipher {
static var blockSize: Int { get }
}

View File

@ -0,0 +1,77 @@
//
// BlockMode.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
typealias CipherOperationOnBlock = (_ block: ArraySlice<UInt8>) -> Array<UInt8>?
public enum BlockMode {
case ECB, CBC(iv: Array<UInt8>), PCBC(iv: Array<UInt8>), CFB(iv: Array<UInt8>), OFB(iv: Array<UInt8>), CTR(iv: Array<UInt8>)
public enum Error: Swift.Error {
/// Invalid key or IV
case invalidKeyOrInitializationVector
/// Invalid IV
case invalidInitializationVector
}
func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> BlockModeWorker {
switch self {
case .ECB:
return ECBModeWorker(cipherOperation: cipherOperation)
case let .CBC(iv):
if iv.count != blockSize {
throw Error.invalidInitializationVector
}
return CBCModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
case let .PCBC(iv):
if iv.count != blockSize {
throw Error.invalidInitializationVector
}
return PCBCModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
case let .CFB(iv):
if iv.count != blockSize {
throw Error.invalidInitializationVector
}
return CFBModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
case let .OFB(iv):
if iv.count != blockSize {
throw Error.invalidInitializationVector
}
return OFBModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
case let .CTR(iv):
if iv.count != blockSize {
throw Error.invalidInitializationVector
}
return CTRModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
}
}
var options: BlockModeOptions {
switch self {
case .ECB:
return .paddingRequired
case .CBC:
return [.initializationVectorRequired, .paddingRequired]
case .CFB:
return .initializationVectorRequired
case .CTR:
return .initializationVectorRequired
case .OFB:
return .initializationVectorRequired
case .PCBC:
return [.initializationVectorRequired, .paddingRequired]
}
}
}

View File

@ -0,0 +1,23 @@
//
// BlockModeOptions.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
struct BlockModeOptions: OptionSet {
let rawValue: Int
static let none = BlockModeOptions(rawValue: 0)
static let initializationVectorRequired = BlockModeOptions(rawValue: 1)
static let paddingRequired = BlockModeOptions(rawValue: 2)
}

View File

@ -0,0 +1,21 @@
//
// BlockModeWorker.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
protocol BlockModeWorker {
var cipherOperation: CipherOperationOnBlock { get }
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8>
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8>
}

View File

@ -0,0 +1,46 @@
//
// CBC.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Cipher-block chaining (CBC)
//
struct CBCModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.iv = iv
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
return Array(plaintext)
}
prev = ciphertext.slice
return ciphertext
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let plaintext = cipherOperation(ciphertext) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(prev ?? iv, plaintext)
prev = ciphertext
return result
}
}

View File

@ -0,0 +1,46 @@
//
// CFB.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Cipher feedback (CFB)
//
struct CFBModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.iv = iv
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(prev ?? iv) else {
return Array(plaintext)
}
prev = xor(plaintext, ciphertext.slice)
return Array(prev ?? [])
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let plaintext = cipherOperation(prev ?? iv) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(plaintext, ciphertext)
prev = ciphertext
return result
}
}

View File

@ -0,0 +1,52 @@
//
// CTR.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Counter (CTR)
//
struct CTRModeWorker: RandomAccessBlockModeWorker {
let cipherOperation: CipherOperationOnBlock
private let iv: ArraySlice<UInt8>
var counter: UInt = 0
init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.iv = iv
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
let nonce = buildNonce(iv, counter: UInt64(counter))
counter = counter + 1
guard let ciphertext = cipherOperation(nonce.slice) else {
return Array(plaintext)
}
return xor(plaintext, ciphertext)
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
return encrypt(ciphertext)
}
}
private func buildNonce(_ iv: ArraySlice<UInt8>, counter: UInt64) -> Array<UInt8> {
let noncePartLen = AES.blockSize / 2
let noncePrefix = Array(iv[iv.startIndex..<iv.startIndex.advanced(by: noncePartLen)])
let nonceSuffix = Array(iv[iv.startIndex.advanced(by: noncePartLen)..<iv.startIndex.advanced(by: iv.count)])
let c = UInt64(bytes: nonceSuffix) + counter
return noncePrefix + c.bytes()
}

View File

@ -0,0 +1,38 @@
//
// BlockMode.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Electronic codebook (ECB)
//
struct ECBModeWorker: BlockModeWorker {
typealias Element = Array<UInt8>
let cipherOperation: CipherOperationOnBlock
init(cipherOperation: @escaping CipherOperationOnBlock) {
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(plaintext) else {
return Array(plaintext)
}
return ciphertext
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
return encrypt(ciphertext)
}
}

View File

@ -0,0 +1,46 @@
//
// OFB.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Output Feedback (OFB)
//
struct OFBModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.iv = iv
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(prev ?? iv) else {
return Array(plaintext)
}
prev = ciphertext.slice
return xor(plaintext, ciphertext)
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let decrypted = cipherOperation(prev ?? iv) else {
return Array(ciphertext)
}
let plaintext: Array<UInt8> = xor(decrypted, ciphertext)
prev = decrypted.slice
return plaintext
}
}

View File

@ -0,0 +1,46 @@
//
// PCBM.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// Propagating Cipher Block Chaining (PCBC)
//
struct PCBCModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.iv = iv
self.cipherOperation = cipherOperation
}
mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
return Array(plaintext)
}
prev = xor(plaintext, ciphertext.slice)
return ciphertext
}
mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let plaintext = cipherOperation(ciphertext) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(prev ?? iv, plaintext)
prev = xor(plaintext.slice, ciphertext)
return result
}
}

View File

@ -0,0 +1,19 @@
//
// RandomAccessBlockModeWorker.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
protocol RandomAccessBlockModeWorker: BlockModeWorker {
var counter: UInt { set get }
}

View File

@ -0,0 +1,538 @@
//
// Blowfish.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// https://en.wikipedia.org/wiki/Blowfish_(cipher)
// Based on Paul Kocher implementation
//
public final class Blowfish {
public enum Error: Swift.Error {
/// Data padding is required
case dataPaddingRequired
/// Invalid key or IV
case invalidKeyOrInitializationVector
/// Invalid IV
case invalidInitializationVector
}
public static let blockSize: Int = 8 // 64 bit
fileprivate let blockMode: BlockMode
fileprivate let padding: Padding
private var decryptWorker: BlockModeWorker!
private var encryptWorker: BlockModeWorker!
private let N = 16 // rounds
private var P: Array<UInt32>
private var S: Array<Array<UInt32>>
private let origP: Array<UInt32> = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822,
0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377,
0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5,
0xb5470917, 0x9216d5d9, 0x8979fb1b,
]
private let origS: Array<Array<UInt32>> = [
[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
],
[
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
],
[
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
],
[
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
],
]
public init(key: Array<UInt8>, blockMode: BlockMode = .CBC(iv: Array<UInt8>(repeating: 0, count: Blowfish.blockSize)), padding: Padding) throws {
precondition(key.count >= 5 && key.count <= 56)
self.blockMode = blockMode
self.padding = padding
S = origS
P = origP
expandKey(key: key)
try setupBlockModeWorkers()
}
private func setupBlockModeWorkers() throws {
encryptWorker = try blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encrypt)
switch blockMode {
case .CFB, .OFB, .CTR:
decryptWorker = try blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encrypt)
default:
decryptWorker = try blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: decrypt)
}
}
private func reset() {
S = origS
P = origP
// todo expand key
}
private func expandKey(key: Array<UInt8>) {
var j = 0
for i in 0..<(N + 2) {
var data: UInt32 = 0x0
for _ in 0..<4 {
data = (data << 8) | UInt32(key[j])
j += 1
if j >= key.count {
j = 0
}
}
P[i] ^= data
}
var datal: UInt32 = 0
var datar: UInt32 = 0
for i in stride(from: 0, to: N + 2, by: 2) {
encryptBlowfishBlock(l: &datal, r: &datar)
P[i] = datal
P[i + 1] = datar
}
for i in 0..<4 {
for j in stride(from: 0, to: 256, by: 2) {
encryptBlowfishBlock(l: &datal, r: &datar)
S[i][j] = datal
S[i][j + 1] = datar
}
}
}
fileprivate func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
var result = Array<UInt8>()
var l = UInt32(bytes: block[block.startIndex..<block.startIndex.advanced(by: 4)])
var r = UInt32(bytes: block[block.startIndex.advanced(by: 4)..<block.startIndex.advanced(by: 8)])
encryptBlowfishBlock(l: &l, r: &r)
// because everything is too complex to be solved in reasonable time o_O
result += [
UInt8((l >> 24) & 0xff),
UInt8((l >> 16) & 0xff),
]
result += [
UInt8((l >> 8) & 0xff),
UInt8((l >> 0) & 0xff),
]
result += [
UInt8((r >> 24) & 0xff),
UInt8((r >> 16) & 0xff),
]
result += [
UInt8((r >> 8) & 0xff),
UInt8((r >> 0) & 0xff),
]
return result
}
fileprivate func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
var result = Array<UInt8>()
var l = UInt32(bytes: block[block.startIndex..<block.startIndex.advanced(by: 4)])
var r = UInt32(bytes: block[block.startIndex.advanced(by: 4)..<block.startIndex.advanced(by: 8)])
decryptBlowfishBlock(l: &l, r: &r)
// because everything is too complex to be solved in reasonable time o_O
result += [
UInt8((l >> 24) & 0xff),
UInt8((l >> 16) & 0xff),
]
result += [
UInt8((l >> 8) & 0xff),
UInt8((l >> 0) & 0xff),
]
result += [
UInt8((r >> 24) & 0xff),
UInt8((r >> 16) & 0xff),
]
result += [
UInt8((r >> 8) & 0xff),
UInt8((r >> 0) & 0xff),
]
return result
}
/// Encrypts the 8-byte padded buffer
///
/// - Parameters:
/// - l: left half
/// - r: right half
fileprivate func encryptBlowfishBlock(l: inout UInt32, r: inout UInt32) {
var Xl = l
var Xr = r
for i in 0..<N {
Xl = Xl ^ P[i]
Xr = F(x: Xl) ^ Xr
(Xl, Xr) = (Xr, Xl)
}
(Xl, Xr) = (Xr, Xl)
Xr = Xr ^ P[self.N]
Xl = Xl ^ P[self.N + 1]
l = Xl
r = Xr
}
/// Decrypts the 8-byte padded buffer
///
/// - Parameters:
/// - l: left half
/// - r: right half
fileprivate func decryptBlowfishBlock(l: inout UInt32, r: inout UInt32) {
var Xl = l
var Xr = r
for i in (2...N + 1).reversed() {
Xl = Xl ^ P[i]
Xr = F(x: Xl) ^ Xr
(Xl, Xr) = (Xr, Xl)
}
(Xl, Xr) = (Xr, Xl)
Xr = Xr ^ P[1]
Xl = Xl ^ P[0]
l = Xl
r = Xr
}
private func F(x: UInt32) -> UInt32 {
let f1 = S[0][Int(x >> 24) & 0xff]
let f2 = S[1][Int(x >> 16) & 0xff]
let f3 = S[2][Int(x >> 8) & 0xff]
let f4 = S[3][Int(x & 0xff)]
return ((f1 &+ f2) ^ f3) &+ f4
}
}
extension Blowfish: Cipher {
/// Encrypt the 8-byte padded buffer, block by block. Note that for amounts of data larger than a block, it is not safe to just call encrypt() on successive blocks.
///
/// - Parameter bytes: Plaintext data
/// - Returns: Encrypted data
public func encrypt<C: Collection>(_ bytes: C) throws -> Array<UInt8> where C.Element == UInt8, C.IndexDistance == Int, C.Index == Int {
let bytes = padding.add(to: Array(bytes), blockSize: Blowfish.blockSize) // FIXME: Array(bytes) copies
var out = Array<UInt8>()
out.reserveCapacity(bytes.count)
for chunk in bytes.batched(by: Blowfish.blockSize) {
out += encryptWorker.encrypt(chunk)
}
if blockMode.options.contains(.paddingRequired) && (out.count % Blowfish.blockSize != 0) {
throw Error.dataPaddingRequired
}
return out
}
/// Decrypt the 8-byte padded buffer
///
/// - Parameter bytes: Ciphertext data
/// - Returns: Plaintext data
public func decrypt<C: Collection>(_ bytes: C) throws -> Array<UInt8> where C.Element == UInt8, C.IndexDistance == Int, C.Index == Int {
if blockMode.options.contains(.paddingRequired) && (bytes.count % Blowfish.blockSize != 0) {
throw Error.dataPaddingRequired
}
var out = Array<UInt8>()
out.reserveCapacity(bytes.count)
for chunk in Array(bytes).batched(by: Blowfish.blockSize) {
out += decryptWorker.decrypt(chunk) // FIXME: copying here is innefective
}
out = padding.remove(from: out, blockSize: Blowfish.blockSize)
return out
}
}

View File

@ -0,0 +1,336 @@
//
// ChaCha20.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// https://tools.ietf.org/html/rfc7539
//
public final class ChaCha20: BlockCipher {
public enum Error: Swift.Error {
case invalidKeyOrInitializationVector
}
public static let blockSize = 64 // 512 / 8
fileprivate let key: Key
fileprivate var counter: Array<UInt8>
public init(key: Array<UInt8>, iv nonce: Array<UInt8>) throws {
precondition(nonce.count == 12 || nonce.count == 8)
if key.count != 32 {
throw Error.invalidKeyOrInitializationVector
}
self.key = Key(bytes: key)
if nonce.count == 8 {
counter = [0, 0, 0, 0, 0, 0, 0, 0] + nonce
} else {
counter = [0, 0, 0, 0] + nonce
}
assert(counter.count == 16)
}
/// https://tools.ietf.org/html/rfc7539#section-2.3.
fileprivate func core(block: inout Array<UInt8>, counter: Array<UInt8>, key: Array<UInt8>) {
precondition(block.count == ChaCha20.blockSize)
precondition(counter.count == 16)
precondition(key.count == 32)
let j0: UInt32 = 0x61707865
let j1: UInt32 = 0x3320646e // 0x3620646e sigma/tau
let j2: UInt32 = 0x79622d32
let j3: UInt32 = 0x6b206574
let j4: UInt32 = UInt32(bytes: key[0..<4]).bigEndian
let j5: UInt32 = UInt32(bytes: key[4..<8]).bigEndian
let j6: UInt32 = UInt32(bytes: key[8..<12]).bigEndian
let j7: UInt32 = UInt32(bytes: key[12..<16]).bigEndian
let j8: UInt32 = UInt32(bytes: key[16..<20]).bigEndian
let j9: UInt32 = UInt32(bytes: key[20..<24]).bigEndian
let j10: UInt32 = UInt32(bytes: key[24..<28]).bigEndian
let j11: UInt32 = UInt32(bytes: key[28..<32]).bigEndian
let j12: UInt32 = UInt32(bytes: counter[0..<4]).bigEndian
let j13: UInt32 = UInt32(bytes: counter[4..<8]).bigEndian
let j14: UInt32 = UInt32(bytes: counter[8..<12]).bigEndian
let j15: UInt32 = UInt32(bytes: counter[12..<16]).bigEndian
var (x0, x1, x2, x3, x4, x5, x6, x7) = (j0, j1, j2, j3, j4, j5, j6, j7)
var (x8, x9, x10, x11, x12, x13, x14, x15) = (j8, j9, j10, j11, j12, j13, j14, j15)
for _ in 0..<10 { // 20 rounds
x0 = x0 &+ x4
x12 ^= x0
x12 = (x12 << 16) | (x12 >> 16)
x8 = x8 &+ x12
x4 ^= x8
x4 = (x4 << 12) | (x4 >> 20)
x0 = x0 &+ x4
x12 ^= x0
x12 = (x12 << 8) | (x12 >> 24)
x8 = x8 &+ x12
x4 ^= x8
x4 = (x4 << 7) | (x4 >> 25)
x1 = x1 &+ x5
x13 ^= x1
x13 = (x13 << 16) | (x13 >> 16)
x9 = x9 &+ x13
x5 ^= x9
x5 = (x5 << 12) | (x5 >> 20)
x1 = x1 &+ x5
x13 ^= x1
x13 = (x13 << 8) | (x13 >> 24)
x9 = x9 &+ x13
x5 ^= x9
x5 = (x5 << 7) | (x5 >> 25)
x2 = x2 &+ x6
x14 ^= x2
x14 = (x14 << 16) | (x14 >> 16)
x10 = x10 &+ x14
x6 ^= x10
x6 = (x6 << 12) | (x6 >> 20)
x2 = x2 &+ x6
x14 ^= x2
x14 = (x14 << 8) | (x14 >> 24)
x10 = x10 &+ x14
x6 ^= x10
x6 = (x6 << 7) | (x6 >> 25)
x3 = x3 &+ x7
x15 ^= x3
x15 = (x15 << 16) | (x15 >> 16)
x11 = x11 &+ x15
x7 ^= x11
x7 = (x7 << 12) | (x7 >> 20)
x3 = x3 &+ x7
x15 ^= x3
x15 = (x15 << 8) | (x15 >> 24)
x11 = x11 &+ x15
x7 ^= x11
x7 = (x7 << 7) | (x7 >> 25)
x0 = x0 &+ x5
x15 ^= x0
x15 = (x15 << 16) | (x15 >> 16)
x10 = x10 &+ x15
x5 ^= x10
x5 = (x5 << 12) | (x5 >> 20)
x0 = x0 &+ x5
x15 ^= x0
x15 = (x15 << 8) | (x15 >> 24)
x10 = x10 &+ x15
x5 ^= x10
x5 = (x5 << 7) | (x5 >> 25)
x1 = x1 &+ x6
x12 ^= x1
x12 = (x12 << 16) | (x12 >> 16)
x11 = x11 &+ x12
x6 ^= x11
x6 = (x6 << 12) | (x6 >> 20)
x1 = x1 &+ x6
x12 ^= x1
x12 = (x12 << 8) | (x12 >> 24)
x11 = x11 &+ x12
x6 ^= x11
x6 = (x6 << 7) | (x6 >> 25)
x2 = x2 &+ x7
x13 ^= x2
x13 = (x13 << 16) | (x13 >> 16)
x8 = x8 &+ x13
x7 ^= x8
x7 = (x7 << 12) | (x7 >> 20)
x2 = x2 &+ x7
x13 ^= x2
x13 = (x13 << 8) | (x13 >> 24)
x8 = x8 &+ x13
x7 ^= x8
x7 = (x7 << 7) | (x7 >> 25)
x3 = x3 &+ x4
x14 ^= x3
x14 = (x14 << 16) | (x14 >> 16)
x9 = x9 &+ x14
x4 ^= x9
x4 = (x4 << 12) | (x4 >> 20)
x3 = x3 &+ x4
x14 ^= x3
x14 = (x14 << 8) | (x14 >> 24)
x9 = x9 &+ x14
x4 ^= x9
x4 = (x4 << 7) | (x4 >> 25)
}
x0 = x0 &+ j0
x1 = x1 &+ j1
x2 = x2 &+ j2
x3 = x3 &+ j3
x4 = x4 &+ j4
x5 = x5 &+ j5
x6 = x6 &+ j6
x7 = x7 &+ j7
x8 = x8 &+ j8
x9 = x9 &+ j9
x10 = x10 &+ j10
x11 = x11 &+ j11
x12 = x12 &+ j12
x13 = x13 &+ j13
x14 = x14 &+ j14
x15 = x15 &+ j15
block.replaceSubrange(0..<4, with: x0.bigEndian.bytes())
block.replaceSubrange(4..<8, with: x1.bigEndian.bytes())
block.replaceSubrange(8..<12, with: x2.bigEndian.bytes())
block.replaceSubrange(12..<16, with: x3.bigEndian.bytes())
block.replaceSubrange(16..<20, with: x4.bigEndian.bytes())
block.replaceSubrange(20..<24, with: x5.bigEndian.bytes())
block.replaceSubrange(24..<28, with: x6.bigEndian.bytes())
block.replaceSubrange(28..<32, with: x7.bigEndian.bytes())
block.replaceSubrange(32..<36, with: x8.bigEndian.bytes())
block.replaceSubrange(36..<40, with: x9.bigEndian.bytes())
block.replaceSubrange(40..<44, with: x10.bigEndian.bytes())
block.replaceSubrange(44..<48, with: x11.bigEndian.bytes())
block.replaceSubrange(48..<52, with: x12.bigEndian.bytes())
block.replaceSubrange(52..<56, with: x13.bigEndian.bytes())
block.replaceSubrange(56..<60, with: x14.bigEndian.bytes())
block.replaceSubrange(60..<64, with: x15.bigEndian.bytes())
}
// XORKeyStream
func process(bytes: Array<UInt8>, counter: inout Array<UInt8>, key: Array<UInt8>) -> Array<UInt8> {
precondition(counter.count == 16)
precondition(key.count == 32)
var block = Array<UInt8>(repeating: 0, count: ChaCha20.blockSize)
var bytes = bytes // TODO: check bytes[bytes.indices]
var out = Array<UInt8>(reserveCapacity: bytes.count)
while bytes.count >= ChaCha20.blockSize {
core(block: &block, counter: counter, key: key)
for (i, x) in block.enumerated() {
out.append(bytes[i] ^ x)
}
var u: UInt32 = 1
for i in 0..<4 {
u += UInt32(counter[i])
counter[i] = UInt8(u & 0xFF)
u >>= 8
}
bytes = Array(bytes[ChaCha20.blockSize..<bytes.endIndex])
}
if bytes.count > 0 {
core(block: &block, counter: counter, key: key)
for (i, v) in bytes.enumerated() {
out.append(v ^ block[i])
}
}
return out
}
}
// MARK: Cipher
extension ChaCha20: Cipher {
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
return process(bytes: Array(bytes), counter: &counter, key: Array(key))
}
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
return try encrypt(bytes)
}
}
// MARK: Encryptor
extension ChaCha20 {
public struct Encryptor: Updatable {
private var accumulated = Array<UInt8>()
private let chacha: ChaCha20
init(chacha: ChaCha20) {
self.chacha = chacha
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
accumulated += bytes
var encrypted = Array<UInt8>()
encrypted.reserveCapacity(accumulated.count)
for chunk in accumulated.batched(by: ChaCha20.blockSize) {
if isLast || accumulated.count >= ChaCha20.blockSize {
encrypted += try chacha.encrypt(chunk)
accumulated.removeFirst(chunk.count) // TODO: improve performance
}
}
return encrypted
}
}
}
// MARK: Decryptor
extension ChaCha20 {
public struct Decryptor: Updatable {
private var accumulated = Array<UInt8>()
private var offset: Int = 0
private var offsetToRemove: Int = 0
private let chacha: ChaCha20
init(chacha: ChaCha20) {
self.chacha = chacha
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = true) throws -> Array<UInt8> {
// prepend "offset" number of bytes at the begining
if offset > 0 {
accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
offsetToRemove = offset
offset = 0
} else {
accumulated += bytes
}
var plaintext = Array<UInt8>()
plaintext.reserveCapacity(accumulated.count)
for chunk in accumulated.batched(by: ChaCha20.blockSize) {
if isLast || accumulated.count >= ChaCha20.blockSize {
plaintext += try chacha.decrypt(chunk)
// remove "offset" from the beginning of first chunk
if offsetToRemove > 0 {
plaintext.removeFirst(offsetToRemove) // TODO: improve performance
offsetToRemove = 0
}
accumulated.removeFirst(chunk.count)
}
}
return plaintext
}
}
}
// MARK: Cryptors
extension ChaCha20: Cryptors {
public func makeEncryptor() -> ChaCha20.Encryptor {
return Encryptor(chacha: self)
}
public func makeDecryptor() -> ChaCha20.Decryptor {
return Decryptor(chacha: self)
}
}

View File

@ -0,0 +1,134 @@
//
// Checksum.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
/// CRC - cyclic redundancy check code.
public final class Checksum {
private static let table32: Array<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: Array<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: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
var crc: UInt32 = seed != nil ? seed! : 0xffffffff
for chunk in message.batched(by: 256) {
for b in chunk {
let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xff)
crc = (crc >> 8) ^ Checksum.table32[idx]
}
}
return (reflect ? crc : reversed(crc)) ^ 0xffffffff
}
func crc16(_ message: Array<UInt8>, seed: UInt16? = nil) -> UInt16 {
var crc: UInt16 = seed != nil ? seed! : 0x0000
for chunk in message.batched(by: 256) {
for b in chunk {
crc = (crc >> 8) ^ Checksum.table16[Int((crc ^ UInt16(b)) & 0xff)]
}
}
return crc
}
}
// MARK: Public interface
public extension Checksum {
/// Calculate CRC32
///
/// - parameter message: Message
/// - parameter seed: Seed value (Optional)
/// - parameter reflect: is reflect (default true)
///
/// - returns: Calculated code
static func crc32(_ message: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
return Checksum().crc32(message, seed: seed, reflect: reflect)
}
/// Calculate CRC16
///
/// - parameter message: Message
/// - parameter seed: Seed value (Optional)
///
/// - returns: Calculated code
static func crc16(_ message: Array<UInt8>, seed: UInt16? = nil) -> UInt16 {
return Checksum().crc16(message, seed: seed)
}
}

View File

@ -0,0 +1,46 @@
//
// Cipher.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
public enum CipherError: Error {
case encrypt
case decrypt
}
public protocol Cipher: class {
/// Encrypt given bytes at once
///
/// - parameter bytes: Plaintext data
/// - returns: Encrypted data
func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8>
func encrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8>
/// Decrypt given bytes at once
///
/// - parameter bytes: Ciphertext data
/// - returns: Plaintext data
func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8>
func decrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8>
}
extension Cipher {
public func encrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
return try encrypt(bytes.slice)
}
public func decrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
return try decrypt(bytes.slice)
}
}

View File

@ -0,0 +1,47 @@
//
// Collection+Extension.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
extension Collection where Self.Element == UInt8, Self.Index == Int {
// Big endian order
func toUInt32Array() -> Array<UInt32> {
if isEmpty {
return []
}
var result = Array<UInt32>(reserveCapacity: 16)
for idx in stride(from: startIndex, to: endIndex, by: 4) {
let val = UInt32(bytes: self, fromIndex: idx).bigEndian
result.append(val)
}
return result
}
// Big endian order
func toUInt64Array() -> Array<UInt64> {
if isEmpty {
return []
}
var result = Array<UInt64>(reserveCapacity: 32)
for idx in stride(from: startIndex, to: endIndex, by: 8) {
let val = UInt64(bytes: self, fromIndex: idx).bigEndian
result.append(val)
}
return result
}
}

View File

@ -0,0 +1,48 @@
//
// Cryptors.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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) || os(Android) || os(FreeBSD)
import Glibc
#else
import Darwin
#endif
/// Worker cryptor/decryptor of `Updatable` types
public protocol Cryptors: class {
associatedtype EncryptorType: Updatable
associatedtype DecryptorType: Updatable
/// Cryptor suitable for encryption
func makeEncryptor() throws -> EncryptorType
/// Cryptor suitable for decryption
func makeDecryptor() throws -> DecryptorType
/// Generate array of random bytes. Helper function.
static func randomIV(_ blockSize: Int) -> Array<UInt8>
}
extension Cryptors {
public static func randomIV(_ blockSize: Int) -> Array<UInt8> {
var randomIV: Array<UInt8> = Array<UInt8>()
randomIV.reserveCapacity(blockSize)
for randomByte in RandomBytesSequence(size: blockSize) {
randomIV.append(randomByte)
}
return randomIV
}
}

View File

@ -0,0 +1,80 @@
//
// Hash.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
@available(*, deprecated: 0.6.0, renamed: "Digest")
public typealias Hash = Digest
/// Hash functions to calculate Digest.
public struct Digest {
/// Calculate MD5 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func md5(_ bytes: Array<UInt8>) -> Array<UInt8> {
return MD5().calculate(for: bytes)
}
/// Calculate SHA1 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha1(_ bytes: Array<UInt8>) -> Array<UInt8> {
return SHA1().calculate(for: bytes)
}
/// Calculate SHA2-224 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha224(_ bytes: Array<UInt8>) -> Array<UInt8> {
return sha2(bytes, variant: .sha224)
}
/// Calculate SHA2-256 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha256(_ bytes: Array<UInt8>) -> Array<UInt8> {
return sha2(bytes, variant: .sha256)
}
/// Calculate SHA2-384 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha384(_ bytes: Array<UInt8>) -> Array<UInt8> {
return sha2(bytes, variant: .sha384)
}
/// Calculate SHA2-512 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha512(_ bytes: Array<UInt8>) -> Array<UInt8> {
return sha2(bytes, variant: .sha512)
}
/// Calculate SHA2 Digest
/// - parameter bytes: input message
/// - parameter variant: SHA-2 variant
/// - returns: Digest bytes
public static func sha2(_ bytes: Array<UInt8>, variant: SHA2.Variant) -> Array<UInt8> {
return SHA2(variant: variant).calculate(for: bytes)
}
/// Calculate SHA3 Digest
/// - parameter bytes: input message
/// - parameter variant: SHA-3 variant
/// - returns: Digest bytes
public static func sha3(_ bytes: Array<UInt8>, variant: SHA3.Variant) -> Array<UInt8> {
return SHA3(variant: variant).calculate(for: bytes)
}
}

View File

@ -0,0 +1,19 @@
//
// Digest.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
internal protocol DigestType {
func calculate(for bytes: Array<UInt8>) -> Array<UInt8>
}

View File

@ -0,0 +1,25 @@
//
// AES+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension AES {
/// Initialize with CBC block mode.
public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws {
try self.init(key: key.bytes, blockMode: .CBC(iv: iv.bytes), padding: padding)
}
}

View File

@ -0,0 +1,34 @@
//
// Array+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
public extension Array where Element == UInt8 {
public func toBase64() -> String? {
return Data(bytes: self).base64EncodedString()
}
public init(base64: String) {
self.init()
guard let decodedData = Data(base64Encoded: base64) else {
return
}
append(contentsOf: decodedData.bytes)
}
}

View File

@ -0,0 +1,25 @@
//
// Blowfish+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension Blowfish {
/// Initialize with CBC block mode.
public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws {
try self.init(key: key.bytes, blockMode: .CBC(iv: iv.bytes), padding: padding)
}
}

View File

@ -0,0 +1,24 @@
//
// ChaCha20+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension ChaCha20 {
public convenience init(key: String, iv: String) throws {
try self.init(key: key.bytes, iv: iv.bytes)
}
}

View File

@ -0,0 +1,94 @@
//
// PGPDataExtension.swift
// SwiftPGP
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension Data {
/// Two octet checksum as defined in RFC-4880. Sum of all octets, mod 65536
public func checksum() -> UInt16 {
var s: UInt32 = 0
var bytesArray = bytes
for i in 0..<bytesArray.count {
s = s + UInt32(bytesArray[i])
}
s = s % 65536
return UInt16(s)
}
public func md5() -> Data {
return Data(bytes: Digest.md5(bytes))
}
public func sha1() -> Data {
return Data(bytes: Digest.sha1(bytes))
}
public func sha224() -> Data {
return Data(bytes: Digest.sha224(bytes))
}
public func sha256() -> Data {
return Data(bytes: Digest.sha256(bytes))
}
public func sha384() -> Data {
return Data(bytes: Digest.sha384(bytes))
}
public func sha512() -> Data {
return Data(bytes: Digest.sha512(bytes))
}
public func sha3(_ variant: SHA3.Variant) -> Data {
return Data(bytes: Digest.sha3(bytes, variant: variant))
}
public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> Data {
return Data(bytes: Checksum.crc32(bytes, seed: seed, reflect: reflect).bytes())
}
public func crc16(seed: UInt16? = nil) -> Data {
return Data(bytes: Checksum.crc16(bytes, seed: seed).bytes())
}
public func encrypt(cipher: Cipher) throws -> Data {
return Data(bytes: try cipher.encrypt(bytes.slice))
}
public func decrypt(cipher: Cipher) throws -> Data {
return Data(bytes: try cipher.decrypt(bytes.slice))
}
public func authenticate(with authenticator: Authenticator) throws -> Data {
return Data(bytes: try authenticator.authenticate(bytes))
}
}
extension Data {
public init(hex: String) {
self.init(bytes: Array<UInt8>(hex: hex))
}
public var bytes: Array<UInt8> {
return Array(self)
}
public func toHexString() -> String {
return bytes.toHexString()
}
}

View File

@ -0,0 +1,24 @@
//
// HMAC+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension HMAC {
public convenience init(key: String, variant: HMAC.Variant = .md5) throws {
self.init(key: key.bytes, variant: variant)
}
}

View File

@ -0,0 +1,28 @@
//
// Rabbit+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension Rabbit {
public convenience init(key: String) throws {
try self.init(key: key.bytes)
}
public convenience init(key: String, iv: String) throws {
try self.init(key: key.bytes, iv: iv.bytes)
}
}

View File

@ -0,0 +1,43 @@
//
// String+Extension.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
extension String {
/// Return Base64 back to String
public func decryptBase64ToString(cipher: Cipher) throws -> String {
guard let decodedData = Data(base64Encoded: self, options: []) else {
throw CipherError.decrypt
}
let decrypted = try decodedData.decrypt(cipher: cipher)
if let decryptedString = String(data: decrypted, encoding: String.Encoding.utf8) {
return decryptedString
}
throw CipherError.decrypt
}
public func decryptBase64(cipher: Cipher) throws -> Array<UInt8> {
guard let decodedData = Data(base64Encoded: self, options: []) else {
throw CipherError.decrypt
}
return try decodedData.decrypt(cipher: cipher).bytes
}
}

View File

@ -0,0 +1,28 @@
//
// Utils+Foundation.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
import Foundation
func perf(_ text: String, closure: () -> Void) {
let measurementStart = Date()
closure()
let measurementStop = Date()
let executionTime = measurementStop.timeIntervalSince(measurementStart)
print("\(text) \(executionTime)")
}

View File

@ -0,0 +1,56 @@
//
// Generics.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
/** build bit pattern from array of bits */
@_specialize(exported: true, where T == UInt8)
func integerFrom<T: FixedWidthInteger>(_ bits: Array<Bit>) -> T {
var bitPattern: T = 0
for idx in bits.indices {
if bits[idx] == Bit.one {
let bit = T(UInt64(1) << UInt64(idx))
bitPattern = bitPattern | bit
}
}
return bitPattern
}
/// Array of bytes. Caution: don't use directly because generic is slow.
///
/// - parameter value: integer value
/// - parameter length: length of output array. By default size of value type
///
/// - returns: Array of bytes
@_specialize(exported: true, where T == Int)
@_specialize(exported: true, where T == UInt)
@_specialize(exported: true, where T == UInt8)
@_specialize(exported: true, where T == UInt16)
@_specialize(exported: true, where T == UInt32)
@_specialize(exported: true, where T == UInt64)
func arrayOfBytes<T: FixedWidthInteger>(value: T, length totalBytes: Int = MemoryLayout<T>.size) -> Array<UInt8> {
let valuePointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
valuePointer.pointee = value
let bytesPointer = UnsafeMutablePointer<UInt8>(OpaquePointer(valuePointer))
var bytes = Array<UInt8>(repeating: 0, count: totalBytes)
for j in 0..<min(MemoryLayout<T>.size, totalBytes) {
bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
}
valuePointer.deinitialize()
valuePointer.deallocate(capacity: 1)
return bytes
}

View File

@ -0,0 +1,87 @@
//
// HKDF.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
// https://www.ietf.org/rfc/rfc5869.txt
//
#if os(Linux) || os(Android) || os(FreeBSD)
import Glibc
#else
import Darwin
#endif
/// A key derivation function.
///
/// HKDF - HMAC-based Extract-and-Expand Key Derivation Function.
public struct HKDF {
public enum Error: Swift.Error {
case invalidInput
case derivedKeyTooLong
}
private let numBlocks: Int // l
private let dkLen: Int
private let info: Array<UInt8>
fileprivate let prk: Array<UInt8>
fileprivate let variant: HMAC.Variant
/// - parameters:
/// - variant: hash variant
/// - salt: optional salt (if not provided, it is set to a sequence of variant.digestLength zeros)
/// - info: optional context and application specific information
/// - keyLength: intended length of derived key
public init(password: Array<UInt8>, salt: Array<UInt8>? = nil, info: Array<UInt8>? = nil, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha256) throws {
guard !password.isEmpty else {
throw Error.invalidInput
}
let dkLen = keyLength ?? variant.digestLength
let keyLengthFinal = Double(dkLen)
let hLen = Double(variant.digestLength)
let numBlocks = Int(ceil(keyLengthFinal / hLen)) // l = ceil(keyLength / hLen)
guard numBlocks <= 255 else {
throw Error.derivedKeyTooLong
}
/// HKDF-Extract(salt, password) -> PRK
/// - PRK - a pseudo-random key; it is used by calculate()
self.prk = try HMAC(key: salt ?? [], variant: variant).authenticate(password)
self.info = info ?? []
self.variant = variant
self.dkLen = dkLen
self.numBlocks = numBlocks
}
public func calculate() throws -> Array<UInt8> {
let hmac = HMAC(key: self.prk, variant: self.variant)
var ret = Array<UInt8>()
ret.reserveCapacity(self.numBlocks * self.variant.digestLength)
var value = Array<UInt8>()
for i in 1...self.numBlocks {
value.append(contentsOf: self.info)
value.append(UInt8(i))
let bytes = try hmac.authenticate(value)
ret.append(contentsOf: bytes)
/// update value to use it as input for next iteration
value = bytes
}
return Array(ret.prefix(dkLen))
}
}

View File

@ -0,0 +1,107 @@
//
// HMAC.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
public final class HMAC: Authenticator {
public enum Error: Swift.Error {
case authenticateError
case invalidInput
}
public enum Variant {
case sha1, sha256, sha384, sha512, md5
var digestLength: Int {
switch self {
case .sha1:
return SHA1.digestLength
case .sha256:
return SHA2.Variant.sha256.digestLength
case .sha384:
return SHA2.Variant.sha384.digestLength
case .sha512:
return SHA2.Variant.sha512.digestLength
case .md5:
return MD5.digestLength
}
}
func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8>? {
switch self {
case .sha1:
return Digest.sha1(bytes)
case .sha256:
return Digest.sha256(bytes)
case .sha384:
return Digest.sha384(bytes)
case .sha512:
return Digest.sha512(bytes)
case .md5:
return Digest.md5(bytes)
}
}
func blockSize() -> Int {
switch self {
case .md5:
return MD5.blockSize
case .sha1, .sha256:
return 64
case .sha384, .sha512:
return 128
}
}
}
var key: Array<UInt8>
let variant: Variant
public init(key: Array<UInt8>, variant: HMAC.Variant = .md5) {
self.variant = variant
self.key = key
if key.count > variant.blockSize() {
if let hash = variant.calculateHash(key) {
self.key = hash
}
}
if key.count < variant.blockSize() {
self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize())
}
}
// MARK: Authenticator
public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
var opad = Array<UInt8>(repeating: 0x5c, count: variant.blockSize())
for idx in key.indices {
opad[idx] = key[idx] ^ opad[idx]
}
var ipad = Array<UInt8>(repeating: 0x36, count: variant.blockSize())
for idx in key.indices {
ipad[idx] = key[idx] ^ ipad[idx]
}
guard let ipadAndMessageHash = variant.calculateHash(ipad + bytes),
let result = variant.calculateHash(opad + ipadAndMessageHash) else {
throw Error.authenticateError
}
// return Array(result[0..<10]) // 80 bits
return result
}
}

View File

@ -0,0 +1,39 @@
//
// IntExtension.swift
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 12/08/14.
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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) || os(Android) || os(FreeBSD)
import Glibc
#else
import Darwin
#endif
/* array of bits */
extension Int {
init(bits: [Bit]) {
self.init(bitPattern: integerFrom(bits) as UInt)
}
}
extension FixedWidthInteger {
@_transparent
func bytes(totalBytes: Int = MemoryLayout<Self>.size) -> Array<UInt8> {
return arrayOfBytes(value: self, length: totalBytes)
// TODO: adjust bytes order
// var value = self
// return withUnsafeBytes(of: &value, Array.init).reversed()
}
}

View File

@ -0,0 +1,167 @@
//
// MD5.swift
// CryptoSwift
//
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.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.
//
public final class MD5: DigestType {
static let blockSize: Int = 64
static let digestLength: Int = 16 // 128 / 8
fileprivate static let hashInitialValue: Array<UInt32> = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
fileprivate var accumulated = Array<UInt8>()
fileprivate var processedBytesTotalCount: Int = 0
fileprivate var accumulatedHash: Array<UInt32> = MD5.hashInitialValue
/** specifies the per-round shift amounts */
private let s: Array<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: Array<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,
]
public init() {
}
public func calculate(for bytes: Array<UInt8>) -> Array<UInt8> {
do {
return try update(withBytes: bytes.slice, isLast: true)
} catch {
fatalError()
}
}
// mutating currentHash in place is way faster than returning new result
fileprivate func process(block chunk: ArraySlice<UInt8>, currentHash: inout Array<UInt32>) {
assert(chunk.count == 16 * 4)
// Initialize hash value for this chunk:
var A: UInt32 = currentHash[0]
var B: UInt32 = currentHash[1]
var C: UInt32 = currentHash[2]
var D: UInt32 = currentHash[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
// break chunk into sixteen 32-bit words M[j], 0 j 15 and get M[g] value
let gAdvanced = g << 2
var Mg = UInt32(chunk[chunk.startIndex &+ gAdvanced])
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 1]) << 8
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 2]) << 16
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 3]) << 24
B = B &+ rotateLeft(A &+ F &+ k[j] &+ Mg, by: s[j])
A = dTemp
}
currentHash[0] = currentHash[0] &+ A
currentHash[1] = currentHash[1] &+ B
currentHash[2] = currentHash[2] &+ C
currentHash[3] = currentHash[3] &+ D
}
}
extension MD5: Updatable {
public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
accumulated += bytes
if isLast {
let lengthInBits = (processedBytesTotalCount + accumulated.count) * 8
let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b
// Step 1. Append padding
bitPadding(to: &accumulated, blockSize: MD5.blockSize, allowance: 64 / 8)
// Step 2. Append Length a 64-bit representation of lengthInBits
accumulated += lengthBytes.reversed()
}
var processedBytes = 0
for chunk in accumulated.batched(by: MD5.blockSize) {
if isLast || (accumulated.count - processedBytes) >= MD5.blockSize {
process(block: chunk, currentHash: &accumulatedHash)
processedBytes += chunk.count
}
}
accumulated.removeFirst(processedBytes)
processedBytesTotalCount += processedBytes
// output current hash
var result = Array<UInt8>()
result.reserveCapacity(MD5.digestLength)
for hElement in accumulatedHash {
let hLE = hElement.littleEndian
result += Array<UInt8>(arrayLiteral: UInt8(hLE & 0xff), UInt8((hLE >> 8) & 0xff), UInt8((hLE >> 16) & 0xff), UInt8((hLE >> 24) & 0xff))
}
// reset hash value for instance
if isLast {
accumulatedHash = MD5.hashInitialValue
}
return result
}
}

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