Skip to content

Commit

Permalink
Include cryptography
Browse files Browse the repository at this point in the history
  • Loading branch information
Obbut committed Sep 1, 2016
1 parent 83d4eb7 commit 8a14994
Show file tree
Hide file tree
Showing 43 changed files with 2,207 additions and 17 deletions.
21 changes: 13 additions & 8 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ import PackageDescription

var package = Package(
name: "MongoKitten",
targets: [
Target(name: "MongoKitten", dependencies: [
"MongoMD5",
"MongoSCRAM",
"MongoSHA1"
]),
Target(name: "MongoMD5", dependencies: ["MongoCryptoEssentials"]),
Target(name: "MongoSCRAM", dependencies: ["MongoPBKDF2"]),
Target(name: "MongoPBKDF2", dependencies: ["MongoHMAC"]),
Target(name: "MongoHMAC", dependencies: ["MongoCryptoEssentials"]),
Target(name: "MongoSHA1", dependencies: ["MongoCryptoEssentials"]),
Target(name: "MongoCryptoEssentials")
],
dependencies: [
// For MongoCR authentication
.Package(url: "https://github.com/CryptoKitten/MD5.git", majorVersion: 0, minor: 13),

// For SCRAM-SHA-1 authentication
.Package(url: "https://github.com/CryptoKitten/SCRAM.git", majorVersion: 0, minor: 13),
.Package(url: "https://github.com/CryptoKitten/SHA1.git", majorVersion: 0, minor: 13),

// For MongoDB Documents
.Package(url: "https://github.com/OpenKitten/BSON.git", majorVersion: 3, minor: 6),

// Provides sockets
.Package(url: "https://github.com/czechboy0/Socks.git", majorVersion: 0, minor: 12),

]
)

Expand Down
103 changes: 103 additions & 0 deletions Sources/MongoCryptoEssentials/ArrayProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Originally based on CryptoSwift by Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.

import Foundation

public protocol ArrayProtocol: RangeReplaceableCollection, ExpressibleByArrayLiteral {
func arrayValue() -> [Generator.Element]
}

extension Array: ArrayProtocol {
public func arrayValue() -> [Iterator.Element] {
return self
}
}

public extension ArrayProtocol where Iterator.Element == UInt8 {
public var hexString: String {
#if os(Linux)
return self.lazy.reduce("") { $0 + (NSString(format:"%02x", $1).description) }
#else
let s = self.lazy.reduce("") { $0 + String(format:"%02x", $1) }

return s
#endif
}

public var checksum: UInt16? {
guard let bytesArray = self as? [UInt8] else {
return nil
}

var s:UInt32 = 0
for i in 0..<bytesArray.count {
s = s + UInt32(bytesArray[i])
}
s = s % 65536
return UInt16(s)
}

public var base64: String {
let bytesArray = self as? [UInt8] ?? []

#if os(Linux)
return NSData(bytes: bytesArray).base64EncodedString([])
#else
return NSData(bytes: bytesArray).base64EncodedString(options: [])
#endif
}

public init(base64: String) {
self.init()

guard let decodedData = NSData(base64: base64) else {
return
}

self.append(contentsOf: decodedData.byteArray)
}

public init(hexString: String) {
var data = [UInt8]()

var gen = hexString.characters.makeIterator()
while let c1 = gen.next(), let c2 = gen.next() {
let s = String([c1, c2])

guard let d = UInt8(s, radix: 16) else {
break
}

data.append(d)
}

self.init(data)
}
}

extension Array {

/** split in chunks with given chunk size */
public func chunks(chunkSize: Int) -> [Array<Element>] {
var words = [[Element]]()
words.reserveCapacity(self.count / chunkSize)
for idx in stride(from: chunkSize, through: self.count, by: chunkSize) {
let word = Array(self[idx - chunkSize..<idx]) // this is slow for large table
words.append(word)
}
let reminder = Array(self.suffix(self.count % chunkSize))
if (reminder.count > 0) {
words.append(reminder)
}
return words
}
}
157 changes: 157 additions & 0 deletions Sources/MongoCryptoEssentials/Base64.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Base64.swift
//
// The MIT License (MIT)
//
// Copyright (c) 2015 Zewo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

public struct Base64 {
/**
Decodes the base64 encoded string into an array of UInt8 representing
bytes. Throws an Base64DecodingError.invalidCharacter if the input string
is not encoded in valid Base64.

- parameters:
- string: the string to decode
- returns: an array of bytes.
*/
public static func decode(_ string: String) throws -> [UInt8] {
let ascii: [UInt8] = [
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 62, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
]

var decoded = [UInt8]()
var unreadBytes = 0

for character in string.utf8 {
// If we don't get a valid Base64 Character (excluding =):
if ascii[Int(character)] > 63 {

// If it's '=', which is padding, we are done with the string!
if character == 61 {
break
}
// Otherwise this is not a valid Base64 encoded string
else {
throw Base64DecodingError.invalidCharacter
}
}

unreadBytes += 1
}

func byte(_ index: Int) -> Int {
return Int(Array(string.utf8)[index])
}

var index = 0

while unreadBytes > 4 {
decoded.append(ascii[byte(index + 0)] << 2 | ascii[byte(index + 1)] >> 4)
decoded.append(ascii[byte(index + 1)] << 4 | ascii[byte(index + 2)] >> 2)
decoded.append(ascii[byte(index + 2)] << 6 | ascii[byte(index + 3)])
index += 4
unreadBytes -= 4
}

if unreadBytes > 1 {
decoded.append(ascii[byte(index + 0)] << 2 | ascii[byte(index + 1)] >> 4)
}

if unreadBytes > 2 {
decoded.append(ascii[byte(index + 1)] << 4 | ascii[byte(index + 2)] >> 2)
}

if unreadBytes > 3 {
decoded.append(ascii[byte(index + 2)] << 6 | ascii[byte(index + 3)])
}

return decoded
}

public static func encode(_ data: [UInt8], specialChars: String = "+/", paddingChar: Character? = "=") -> String {
let base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + specialChars
var encoded: String = ""

func appendCharacterFromBase(_ character: Int) {
encoded.append(base64[base64.index(base64.startIndex, offsetBy: character)])
}

func byte(_ index: Int) -> Int {
return Int(data[index])
}

let decodedBytes = data.map { Int($0) }

var i = 0

while i < decodedBytes.count - 2 {
appendCharacterFromBase(( byte(i) >> 2) & 0x3F)
appendCharacterFromBase(((byte(i) & 0x3) << 4) | ((byte(i + 1) & 0xF0) >> 4))
appendCharacterFromBase(((byte(i + 1) & 0xF) << 2) | ((byte(i + 2) & 0xC0) >> 6))
appendCharacterFromBase( byte(i + 2) & 0x3F)
i += 3
}

if i < decodedBytes.count {
appendCharacterFromBase((byte(i) >> 2) & 0x3F)

if i == decodedBytes.count - 1 {
appendCharacterFromBase(((byte(i) & 0x3) << 4))
if let paddingChar = paddingChar {
encoded.append(paddingChar)
}
} else {
appendCharacterFromBase(((byte(i) & 0x3) << 4) | ((byte(i + 1) & 0xF0) >> 4))
appendCharacterFromBase(((byte(i + 1) & 0xF) << 2))
}

if let paddingChar = paddingChar {
encoded.append(paddingChar)
}
}

return encoded
}

public static func urlSafeEncode(_ data: [UInt8]) -> String {
return Base64.encode(data, specialChars: "-_", paddingChar: nil)
}
}

enum Base64DecodingError: Error {
case invalidCharacter
}
39 changes: 39 additions & 0 deletions Sources/MongoCryptoEssentials/BlockMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Originally based on CryptoSwift by Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.

public typealias CipherBlockOperation = (_ block: [UInt8]) -> [UInt8]?

public protocol BlockMode {
static var options: BlockModeOptions { get }
static var blockType: InputBlockType { get }

static func makeDecryptionIterator(iv: [UInt8], cipherOperation: @escaping CipherBlockOperation, inputGenerator: AnyIterator<[UInt8]>) -> AnyIterator<[UInt8]>

static func makeEncryptionIterator(iv: [UInt8], cipherOperation: @escaping CipherBlockOperation, inputGenerator: AnyIterator<[UInt8]>) -> AnyIterator<[UInt8]>
}

public enum InputBlockType {
case encrypt
case decrypt
}

public struct BlockModeOptions: OptionSet {
public let rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}

public static let none = BlockModeOptions(rawValue: 0)
public static let initializationVectorRequired = BlockModeOptions(rawValue: 1)
public static let paddingRequired = BlockModeOptions(rawValue: 2)
}
34 changes: 34 additions & 0 deletions Sources/MongoCryptoEssentials/BytesSequence.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Originally based on CryptoSwift by Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.

import Foundation

public struct BytesSequence: Sequence {
let chunkSize: Int
let data: [UInt8]

public init(chunkSize: Int, data: [UInt8]) {
self.chunkSize = chunkSize
self.data = data
}

public func makeIterator() -> AnyIterator<ArraySlice<UInt8>> {
var offset:Int = 0

return AnyIterator {
let end = Swift.min(self.chunkSize, self.data.count - offset)
let result = self.data[offset..<offset + end]
offset += result.count
return result.count > 0 ? result : nil
}
}
}
Loading

0 comments on commit 8a14994

Please sign in to comment.