├── .gitignore ├── .travis.yml ├── Keys.xcodeproj ├── xcuserdata │ └── remaerd.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── remaerd.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ ├── CommonCrypto iOS.xcscheme │ │ ├── CommonCrypto macOS.xcscheme │ │ ├── Keys iOS.xcscheme │ │ └── Keys macOS.xcscheme └── project.pbxproj ├── CommonCrypto ├── macosx.modulemap ├── iphoneos.modulemap ├── iphonesimulator.modulemap ├── CommonCrypto.xcconfig └── Info.plist ├── EncryptedDataGenerator.coffee ├── Tests ├── keys-public.pem ├── Info.plist ├── SymmetricKeyTests.swift ├── keys-private.pem ├── PasswordTests.swift └── AsymmetricKeysTests.swift ├── Keys ├── Keys.h ├── Info.plist ├── Keys.swift ├── Password.swift ├── Hash.swift ├── SymmetricKey.swift ├── AsymmetricKeys-macOS.swift ├── AsymmetricKeys.swift └── AsymmetricKeys-iOS.swift ├── LICENSE ├── README-CHINESE.MD └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | 3 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_project: Keys.xcodeproj # path to your xcodeproj folder 3 | xcode_scheme: Keys iOS -------------------------------------------------------------------------------- /Keys.xcodeproj/xcuserdata/remaerd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Keys.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CommonCrypto/macosx.modulemap: -------------------------------------------------------------------------------- 1 | module CommonCrypto [system] { 2 | header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/CommonCrypto/CommonCrypto.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /Keys.xcodeproj/project.xcworkspace/xcuserdata/remaerd.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remaerd/Keys/HEAD/Keys.xcodeproj/project.xcworkspace/xcuserdata/remaerd.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CommonCrypto/iphoneos.modulemap: -------------------------------------------------------------------------------- 1 | module CommonCrypto [system] { 2 | header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /CommonCrypto/iphonesimulator.modulemap: -------------------------------------------------------------------------------- 1 | module CommonCrypto [system] { 2 | header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /EncryptedDataGenerator.coffee: -------------------------------------------------------------------------------- 1 | ursa = require('ursa') 2 | fs = require('fs') 3 | 4 | publicKey = ursa.createPublicKey(fs.readFileSync('./Tests/keys-public.pem')) 5 | privateKey = ursa.createPrivateKey(fs.readFileSync('./Tests/keys-private.pem')) 6 | 7 | signature = privateKey.hashAndSign('sha1','Hello World','utf8','base64') 8 | 9 | console.log(signature) -------------------------------------------------------------------------------- /CommonCrypto/CommonCrypto.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // CommonCrypto.xcconfig 3 | // Crypto 4 | // 5 | // Created by Sam Soffes on 4/21/15. 6 | // Copyright (c) 2015 Sam Soffes. All rights reserved. 7 | // 8 | 9 | MODULEMAP_FILE[sdk=iphoneos*] = $(SRCROOT)/CommonCrypto/iphoneos.modulemap 10 | MODULEMAP_FILE[sdk=iphonesimulator*] = $(SRCROOT)/CommonCrypto/iphonesimulator.modulemap 11 | MODULEMAP_FILE[sdk=macosx*] = $(SRCROOT)/CommonCrypto/macosx.modulemap 12 | -------------------------------------------------------------------------------- /Tests/keys-public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3EdOH5KnV9u0o3oT5pFu 3 | GsInuH3likl7jeVXkMDux8iZDUb5Xsu4wAldsfK/MZoplifhg6tUu/DT3Zedwz8G 4 | 5PCEatMEVXV/BYM162XXzH6Qnk2HpbwjCimO78sQs+sTbj3YjJngQPuNEJCsvaaS 5 | JpFxvMQNq8LY4Oi5h4Gd4BH0E6ZUM0QuFkxnQ5+J1JNHvUEiZUS0M3x/f4xgwGU1 6 | dCXJqGcbbq0kKsgW8pppmUQiwAVX1i623osVUo/l2QsHKBhTx4wEeBvWdw+bILTi 7 | YRvfI1VBxvklhQ7wVrvRnsfPxlvX2q4m+cbHuPczmaNiPWW//JofjaKQHYhLbGEV 8 | awIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /Keys/Keys.h: -------------------------------------------------------------------------------- 1 | // 2 | // Keys.h 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/8/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Keys. 12 | FOUNDATION_EXPORT double KeysVersionNumber; 13 | 14 | //! Project version string for Keys. 15 | FOUNDATION_EXPORT const unsigned char KeysVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Keys/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /CommonCrypto/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Tests/SymmetricKeyTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymmetricKeyTests.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/11/15. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Keys 11 | 12 | 13 | class SymmetricKeyTests: XCTestCase { 14 | 15 | func testCreateRandomSymmetricKey() { 16 | let key = SymmetricKey() 17 | print(key.cryptoKey) 18 | XCTAssertNotNil(key.hmacKey) 19 | print(key.IV) 20 | print(key.options) 21 | } 22 | 23 | 24 | func testCrypto() { 25 | let key = SymmetricKey() 26 | let data = "Hello World!".data(using: String.Encoding.utf8)! 27 | do { 28 | let encryptedData = try key.encrypt(data) 29 | let decryptedData = try key.decrypt(encryptedData) 30 | XCTAssertEqual(data, decryptedData) 31 | } catch { 32 | XCTFail("Cannot encrypt and decrypt data properly") 33 | } 34 | } 35 | 36 | 37 | func testSignature() { 38 | let key = SymmetricKey() 39 | let data = "Hello World!".data(using: String.Encoding.utf8)! 40 | do { 41 | let signature = try key.signature(data) 42 | let result = try key.verify(data,signature: signature) 43 | XCTAssertTrue(result) 44 | } catch { 45 | XCTFail("Cannot sign and verify data properly") 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For Keys software 4 | 5 | Copyright (c) 2013-2015, Zheng Xing Zhi 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name Facebook nor the names of its contributors may be used to 19 | endorse or promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Tests/keys-private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA3EdOH5KnV9u0o3oT5pFuGsInuH3likl7jeVXkMDux8iZDUb5 3 | Xsu4wAldsfK/MZoplifhg6tUu/DT3Zedwz8G5PCEatMEVXV/BYM162XXzH6Qnk2H 4 | pbwjCimO78sQs+sTbj3YjJngQPuNEJCsvaaSJpFxvMQNq8LY4Oi5h4Gd4BH0E6ZU 5 | M0QuFkxnQ5+J1JNHvUEiZUS0M3x/f4xgwGU1dCXJqGcbbq0kKsgW8pppmUQiwAVX 6 | 1i623osVUo/l2QsHKBhTx4wEeBvWdw+bILTiYRvfI1VBxvklhQ7wVrvRnsfPxlvX 7 | 2q4m+cbHuPczmaNiPWW//JofjaKQHYhLbGEVawIDAQABAoIBAHJD2tat8Hi204Fp 8 | tiEIl6DxzkD5rbSKYbk9mqrQKg0glaQ5iOoPq4qSUTQZw+wrGB94GJeArLfBOWXd 9 | XE0HyL/BtC7lv33FMVresX2mmsbNcJ9tgEwMx/Bhlm/1Wni6HJ43HrnwqE+NLaPG 10 | KJVIbs/q6qEM4jqTHIWus28DYa31K3/syhGLef75XSef097CUJWP/BM2urYMYgbg 11 | O3o4LbwnRxZsddAOKBC7UL6L9xW+8wfzjiCk5AlLXqOQpTkl75YRJiYpIT+V4mC6 12 | W+LyUHMBm4pcpzrAyoZz8fgQOphbLC2UX2Vd+x4LlNm7/6B3ReEvBGxqAsoYrZIE 13 | DYGC2oECgYEA+iZ0db8GOcxVoewgqkVphm9LhERv2NV14ILcxVPdCdxskJvSwpIt 14 | NLUbyYs/jhugLuN0cmu4/QsDWGbQkDDB26y/VsK3taOUaHhR69q9OGeYA9AAEscl 15 | 8yMS2iEEwavyR2ty9s1XNIaJqw3xAioOv1BtRxVWe+S3qRgwNP6sQ1sCgYEA4W4F 16 | XW1sSLr0Dxnj7wWktvlQio415JQZqDWwONGfCFkvLuKvLu3CaXV3hNfDCMe5Juzf 17 | STSzcGeM2+xyEVvvV8pCdMF72LCCt0pW78h3SsBrf+huYg8oEZYi0cZACJCBVwLN 18 | EeVEoTaN58PtkuePxO3WXOzRfGk+0pQTgVjUYzECgYEAnk6l1zpr8zoIW2/3ACrr 19 | bGOUtAEnk18LuWi31L2NHkd8AUxL5kziBQA0tKjGMOX0ypexwxO/P4yvsktm5Emm 20 | 9aHueTbDUlVSf4bduVh19XNB9e+1jCyyLJveu2K4AuURb/dlCyHKdXhLOZCaHJeH 21 | O7XnYlvznnaRcJbZM0CUvg8CgYBLl3EFGyQsX0Rnq+7av7G0CXYQgA9iTqcr2JT2 22 | +JOzYPSJbEoCGogOhO1HBnLIBvD3NIbLLXjeQFrjhC3b1FA1yATw0dCNoOK0Q6FT 23 | Vo1p64wgn/gjuaFeBFI4tZnTRWGZo77QOWkCBiEfjnujvzJefsJa9q5oYYJHao// 24 | 16GggQKBgQChMLkkEshPtGq1tj1bzCVlrBhQK9J5EPhuFcPwdhyBNLekWH/iE/hn 25 | 4N0CJOwd/k7wTYr6vV53U1J4HVI7dq+YJuSuSZeJnJMbFksaH86u3x+sbqq57oJ9 26 | 9B0HJFxfTaXLsTixpDIDiiPymR75Ky9XlxA4X2p9gZM2bwl4siIbwA== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /Keys.xcodeproj/xcuserdata/remaerd.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CommonCrypto iOS.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 9 11 | 12 | CommonCrypto macOS.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 10 16 | 17 | Keys iOS.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 7 21 | 22 | Keys macOS.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 8 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 03580A7E1B75246100F4AB36 31 | 32 | primary 33 | 34 | 35 | 03580A901B7524B400F4AB36 36 | 37 | primary 38 | 39 | 40 | 03580A9D1B75250E00F4AB36 41 | 42 | primary 43 | 44 | 45 | 03580AAA1B75253000F4AB36 46 | 47 | primary 48 | 49 | 50 | 03B715251B7A45A200A15ECF 51 | 52 | primary 53 | 54 | 55 | 03B715341B7A45EF00A15ECF 56 | 57 | primary 58 | 59 | 60 | 03B7154A1B7A47BB00A15ECF 61 | 62 | primary 63 | 64 | 65 | 03B715591B7A481100A15ECF 66 | 67 | primary 68 | 69 | 70 | 03B715681B7A484500A15ECF 71 | 72 | primary 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Keys/Keys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Keys.swift 3 | // Keys 4 | // 5 | // 通用的密钥协议与随机参数扩展 6 | // 7 | // Created by Sean Cheng on 8/8/15. 8 | // 9 | 10 | import Foundation 11 | import CommonCrypto 12 | 13 | 14 | // 用于生成 SecKey 时用到的临时 Keychain 标签 15 | public var TemporaryKeyTag = "com.zhengxingzhi.keys.temp" 16 | 17 | 18 | /// 密钥强度 19 | public enum KeyStrength { 20 | case weak 21 | case regular 22 | case strong 23 | } 24 | 25 | 26 | /// 可用于加密内容的密钥 27 | public protocol Encryptable { 28 | 29 | /// 加密数据 30 | func encrypt(_ data:Data) throws -> Data 31 | 32 | /// 验证数据 33 | func verify(_ data:Data, signature: Data) throws -> Bool 34 | 35 | /// 加密数据后嵌入数据验证码 36 | // func encryptThenMac(data:NSData) throws -> NSData 37 | } 38 | 39 | 40 | /// 可用于解密内容的密钥 41 | public protocol Decryptable { 42 | 43 | /// 解密数据 44 | func decrypt(_ data:Data) throws -> Data 45 | 46 | /// 获得数据验证码 47 | func signature(_ data:Data) throws -> Data 48 | 49 | /// 验证数据后再解密 50 | // func verifyThenDecrypt(data:NSData) throws -> NSData 51 | } 52 | 53 | 54 | public extension String { 55 | 56 | /// 随机字串符 57 | static func randomString(_ length:Int) -> String { 58 | 59 | let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 60 | var string = "" 61 | 62 | for _ in 0 ..< letters.length { 63 | let index = Int(arc4random_uniform(UInt32(letters.length))) 64 | let character = String(letters.character(at: index)) 65 | string += character 66 | } 67 | 68 | return string 69 | } 70 | } 71 | 72 | 73 | public extension Data 74 | { 75 | /// 随机 NSData 数据 76 | static func randomData(_ length:Int) -> Data 77 | { 78 | var data = Data(count:length) 79 | var pointer : UnsafeMutablePointer? = nil 80 | data.withUnsafeMutableBytes { (ptr : UnsafeMutablePointer) in pointer = ptr } 81 | _ = SecRandomCopyBytes(kSecRandomDefault, length, pointer!) 82 | return data 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Tests/PasswordTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PasswordTests.swift 3 | // Tests 4 | // 5 | // Created by Sean Cheng on 8/11/15. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import Keys 11 | 12 | 13 | class PasswordTests: XCTestCase { 14 | 15 | func testCreatePassword() { 16 | do { 17 | let password = try Password(password: "HelloWorld") 18 | print(password) 19 | } catch { 20 | XCTFail("Cannot create password") 21 | } 22 | } 23 | 24 | 25 | func testRandomPassword() { 26 | let password = Password.new() 27 | print(password) 28 | // XCTAssertTrue(password != nil, "Cannot create random password") 29 | } 30 | 31 | 32 | func testPasswordSimilarity() { 33 | do { 34 | let password = try Password(password:"HelloWorld") 35 | let newPassword = try Password(password:"HelloWorld", salt:password.salt, roundCount: password.rounds) 36 | print(password.data.base64EncodedString()) 37 | print(newPassword.data.base64EncodedString()) 38 | XCTAssertEqual(password.data, newPassword.data) 39 | } catch { 40 | XCTFail("Cannot create password") 41 | } 42 | } 43 | 44 | 45 | func testPasswordUnique() { 46 | do { 47 | let password = try Password(password:"HelloWorld") 48 | let newPassword = try Password(password:"HelloWorld") 49 | print(password.data.base64EncodedString()) 50 | print(newPassword.data.base64EncodedString()) 51 | XCTAssertNotEqual(password.data, newPassword.data) 52 | } catch { 53 | XCTFail("Cannot create password") 54 | } 55 | } 56 | 57 | 58 | func testWrapSymmetricKey() { 59 | do { 60 | let key = SymmetricKey() 61 | 62 | var password = try Password(password:"Hello") 63 | let encryptedKeyData = try password.encrypt(key) 64 | let decryptedKey = try password.decrypt(encryptedKeyData.key, IV: encryptedKeyData.IV) 65 | XCTAssertTrue(decryptedKey.cryptoKey == key.cryptoKey, "Invalid wrapping symmetric key") 66 | } catch { 67 | XCTFail("Cannot wrap symmetric key") 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Keys.xcodeproj/xcshareddata/xcschemes/CommonCrypto iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Keys.xcodeproj/xcshareddata/xcschemes/CommonCrypto macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Keys.xcodeproj/xcshareddata/xcschemes/Keys iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Keys.xcodeproj/xcshareddata/xcschemes/Keys macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Keys/Password.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Password.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/8/15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | 13 | /// 密码。 用于加密对对称密钥。 不能直接用于加密数据。 14 | public struct Password { 15 | 16 | public enum Exception : Error { 17 | case cannotCreatePassword 18 | } 19 | 20 | 21 | public let salt : Data 22 | public let options : Options 23 | public let rounds : Int 24 | 25 | let data : Data 26 | 27 | 28 | public struct Options 29 | { 30 | public let saltSize : Int 31 | public let PBKDF : CCPBKDFAlgorithm 32 | public let PRF : CCPseudoRandomAlgorithm 33 | } 34 | 35 | 36 | public static var DefaultOptions : Options 37 | { 38 | return Options( 39 | saltSize: 8, 40 | PBKDF: CCPBKDFAlgorithm(kCCPBKDF2), 41 | PRF: CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA512)) 42 | } 43 | 44 | 45 | public lazy var key : SymmetricKey = 46 | { 47 | return try! SymmetricKey(key: self.data, options: SymmetricKey.DefaultOptions) 48 | }() 49 | 50 | 51 | public static func new(_ strength: KeyStrength = KeyStrength.regular) -> Password 52 | { 53 | let randomString = String.randomString(15) 54 | let key = try! Password(password: randomString) 55 | return key 56 | } 57 | 58 | 59 | public init(password:String, salt:Data = Data.randomData(Password.DefaultOptions.saltSize), roundCount: Int? = nil, options: Options = Password.DefaultOptions) throws 60 | { 61 | var saltPointer : UnsafePointer? = nil 62 | salt.withUnsafeBytes { (pointer : UnsafePointer) in saltPointer = pointer } 63 | 64 | let passwordData = password.data(using: String.Encoding.utf8)! 65 | var passwordPointer : UnsafePointer? = nil 66 | passwordData.withUnsafeBytes { (pointer : UnsafePointer) in passwordPointer = pointer } 67 | 68 | let derivedDataLength : Int 69 | 70 | switch Int(options.PRF) 71 | { 72 | case kCCPRFHmacAlgSHA1: derivedDataLength = Int(CC_SHA1_DIGEST_LENGTH); break; 73 | case kCCPRFHmacAlgSHA224: derivedDataLength = Int(CC_SHA224_DIGEST_LENGTH); break; 74 | case kCCPRFHmacAlgSHA256: derivedDataLength = Int(CC_SHA256_DIGEST_LENGTH); break; 75 | case kCCPRFHmacAlgSHA384: derivedDataLength = Int(CC_SHA384_DIGEST_LENGTH); break; 76 | case kCCPRFHmacAlgSHA512: derivedDataLength = Int(CC_SHA512_DIGEST_LENGTH); break; 77 | default: throw Exception.cannotCreatePassword 78 | } 79 | 80 | var derivedData = Data(count:derivedDataLength) 81 | var derivedDataPointer : UnsafeMutablePointer? = nil 82 | derivedData.withUnsafeMutableBytes { (pointer : UnsafeMutablePointer) in derivedDataPointer = pointer } 83 | 84 | let count: UInt32 85 | if roundCount != nil { count = UInt32(roundCount!) } 86 | else { count = CCCalibratePBKDF(options.PBKDF, passwordData.count, salt.count, options.PRF, derivedDataLength, 300 ) } 87 | 88 | let result = CCKeyDerivationPBKDF(options.PBKDF, passwordPointer!, passwordData.count, saltPointer!, salt.count, options.PRF, count, derivedDataPointer, derivedDataLength) 89 | if Int(result) != kCCSuccess { throw Exception.cannotCreatePassword } 90 | 91 | self.data = derivedData 92 | self.rounds = Int(count) 93 | self.salt = salt 94 | self.options = options 95 | } 96 | 97 | 98 | /// 加密对称密钥 99 | mutating public func encrypt(_ key:SymmetricKey) throws -> (key: Data, IV: Data) { 100 | do { 101 | var _data = key.cryptoKey 102 | if let hmacKey = key.hmacKey { _data.append(hmacKey as Data) } 103 | let encryptKey = try self.key.encrypt(_data) 104 | return (encryptKey, key.IV) 105 | } catch { 106 | throw error 107 | } 108 | } 109 | 110 | 111 | /// 解密对称密钥 112 | mutating public func decrypt(_ key:Data, IV: Data, options: SymmetricKey.Options = SymmetricKey.DefaultOptions) throws -> SymmetricKey { 113 | do { 114 | let keyData = try self.key.decrypt(key) 115 | let symmetricKey = try SymmetricKey(key: keyData, IV: IV, options: options) 116 | return symmetricKey 117 | } catch { 118 | throw error 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Tests/AsymmetricKeysTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsymmetricKeysTests.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/11/15. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import Keys 11 | 12 | 13 | class AsymmetricKeyTests: XCTestCase { 14 | 15 | func testOpenSSLKey() { 16 | let publicKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-public", withExtension: "pem")!) 17 | let privateKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-private", withExtension: "pem")!) 18 | let secretData = "Hello Me".data(using: String.Encoding.utf8)! 19 | do { 20 | let publicKey = try PublicKey(publicKey: publicKeyData) 21 | print(publicKey) 22 | let privateKey = try PrivateKey(privateKey: privateKeyData) 23 | print(privateKey) 24 | let secret = try publicKey.encrypt(secretData) 25 | let decryptedSecret = try privateKey.decrypt(secret) 26 | XCTAssertEqual(secretData, decryptedSecret) 27 | } catch { 28 | XCTFail() 29 | } 30 | } 31 | 32 | 33 | func testAsymmetricKey() { 34 | let keys = AsymmetricKeys.generateKeyPair() 35 | let secretData = "Hello World".data(using: String.Encoding.utf8)! 36 | do { 37 | let secret = try keys.publicKey.encrypt(secretData) 38 | let decryptedSecret = try keys.privateKey.decrypt(secret) 39 | XCTAssertEqual(secretData, decryptedSecret) 40 | } catch { 41 | XCTFail() 42 | } 43 | } 44 | 45 | 46 | func testDecryptNodeJSEncryptedData() { 47 | let encryptedString = "POeVBWNhsXOcZAw8R/pv6edPIdVM9p1Ux47BMKuWHggLfkUpT3LaGKzwcYA2zInpBnf4GEZzq7wR5/LO14QvCMLWPwgQ/SYlgFkaPA4+lIsUIGEMRGD76YPwmiulgctHiukhQxSpq0ObvJyuLis9+3uS5uUvAoYBhAiuPujgf0t47+bSc3ToB1HgCiPyw12e5zKl0RvjYGClb06ID5jPzA9SwtucKrAanyAz4L0P/aQNqTpIlmhrc6ht+ObxgVq55SL4n7vn2JPGq6zllpv/aNrNzu/BnesU8VH6GWzXG29v8LrKnZwNHDW7VvoMnJ3PNCXLb19tocJLnP6/WF26WQ==" 48 | let data = Data(base64Encoded: encryptedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)! 49 | let privateKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-private", withExtension: "pem")!) 50 | do { 51 | let privateKey = try PrivateKey(privateKey:privateKeyData) 52 | let decryptedData = try privateKey.decrypt(data) 53 | let decryptedString = NSString(data: decryptedData, encoding: String.Encoding.utf8.rawValue) 54 | XCTAssertEqual(decryptedString, "Hello World") 55 | } catch { 56 | XCTFail() 57 | } 58 | } 59 | 60 | 61 | func testSignAndVerify() { 62 | let keys = AsymmetricKeys.generateKeyPair() 63 | let data = "Hello World".data(using: String.Encoding.utf8)! 64 | do { 65 | let signature = try keys.privateKey.signature(data) 66 | let result = try keys.publicKey.verify(data, signature: signature) 67 | XCTAssertTrue(result) 68 | } catch { 69 | XCTFail() 70 | } 71 | } 72 | 73 | 74 | func testOpenSSLKeySignAndVerify() { 75 | let publicKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-public", withExtension: "pem")!) 76 | let privateKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-private", withExtension: "pem")!) 77 | let secretData = "Hello Me".data(using: String.Encoding.utf8)! 78 | do { 79 | let publicKey = try PublicKey(publicKey: publicKeyData) 80 | let privateKey = try PrivateKey(privateKey: privateKeyData) 81 | let signature = try privateKey.signature(secretData) 82 | let result = try publicKey.verify(secretData, signature: signature) 83 | XCTAssertTrue(result) 84 | } catch { 85 | XCTFail() 86 | } 87 | } 88 | 89 | 90 | func testVerifyOpenSSLSignedData() { 91 | let signatureString = "V32BIi/KI3neTd9BCScitCHoI3a6n/AS44DdT3sXy6JdY5+sDLIFhroByRLirUxhI2MO3Zj9mPf2GFVl11K862tawO8BLMZtH28t9ipHIDeFZc2nuMMeAyEm9jhejvj92hidmfZ+r7HGTNKTMdcxJAiHztHopoU2AF0lJkEvuLHc4Yllrg6d/G54AUqRbKz0RFlHwXVL0lgyobKFrLdkH2PwuORglTvOvceUSMm2cM39bqqTxg6n8f9pG3nWt7pXQ2W3lJGYUIhm4JhLDuq96TpRj44UWH4kF3YT1nqnVzF+u3AKhGSiFbcsBkTeAI2M4tTouiE1d+tz/UzlM/1egw==" 92 | let secretData = "Hello World".data(using: String.Encoding.utf8)! 93 | let publicKeyData = try! Data(contentsOf: Bundle(for: self.classForCoder).url(forResource: "keys-public", withExtension: "pem")!) 94 | let signatureData = Data(base64Encoded: signatureString, options: .ignoreUnknownCharacters)! 95 | do { 96 | let publicKey = try PublicKey(publicKey: publicKeyData) 97 | let result = try publicKey.verify(secretData, signature: signatureData) 98 | XCTAssertTrue(result) 99 | } catch { 100 | XCTFail() 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Keys/Hash.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Hash.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/9/15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | 13 | public extension Data { 14 | 15 | var MD2: Data { 16 | var hash = [UInt8](repeating: 0, count: Int(CC_MD2_DIGEST_LENGTH)) 17 | var pointer : UnsafeRawPointer? = nil 18 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 19 | CC_MD2(pointer, CC_LONG(count), &hash) 20 | return Data(bytes: pointer!, count: Int(CC_MD2_DIGEST_LENGTH)) 21 | } 22 | 23 | 24 | var MD4: Data { 25 | var hash = [UInt8](repeating: 0, count: Int(CC_MD4_DIGEST_LENGTH)) 26 | var pointer : UnsafeRawPointer? = nil 27 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 28 | CC_MD4(pointer, CC_LONG(count), &hash) 29 | return Data(bytes: pointer!, count: Int(CC_MD4_DIGEST_LENGTH)) 30 | } 31 | 32 | 33 | var MD5: Data { 34 | var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) 35 | var pointer : UnsafeRawPointer? = nil 36 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 37 | CC_MD5(pointer, CC_LONG(count), &hash) 38 | return Data(bytes: pointer!, count: Int(CC_MD5_DIGEST_LENGTH)) 39 | } 40 | 41 | 42 | var SHA1: Data { 43 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH)) 44 | var pointer : UnsafeRawPointer? = nil 45 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 46 | CC_SHA1(pointer, CC_LONG(count), &hash) 47 | return Data(bytes: pointer!, count: Int(CC_SHA1_DIGEST_LENGTH)) 48 | } 49 | 50 | 51 | var SHA224: Data { 52 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA224_DIGEST_LENGTH)) 53 | var pointer : UnsafeRawPointer? = nil 54 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 55 | CC_SHA224(pointer, CC_LONG(count), &hash) 56 | return Data(bytes: pointer!, count: Int(CC_SHA224_DIGEST_LENGTH)) 57 | } 58 | 59 | 60 | var SHA256: Data { 61 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) 62 | var pointer : UnsafeRawPointer? = nil 63 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 64 | CC_SHA256(pointer, CC_LONG(count), &hash) 65 | return Data(bytes: pointer!, count: Int(CC_SHA256_DIGEST_LENGTH)) 66 | } 67 | 68 | 69 | var SHA384: Data { 70 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA384_DIGEST_LENGTH)) 71 | var pointer : UnsafeRawPointer? = nil 72 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 73 | CC_SHA384(pointer, CC_LONG(count), &hash) 74 | return Data(bytes: pointer!, count: Int(CC_SHA384_DIGEST_LENGTH)) 75 | } 76 | 77 | 78 | var SHA512: Data { 79 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH)) 80 | var pointer : UnsafeRawPointer? = nil 81 | withUnsafeBytes({ (ptr) in pointer = ptr.baseAddress }) 82 | CC_SHA512(pointer, CC_LONG(count), &hash) 83 | return Data(bytes: pointer!, count: Int(CC_SHA512_DIGEST_LENGTH)) 84 | } 85 | } 86 | 87 | 88 | public extension String { 89 | 90 | var MD2: String? { 91 | return String(digestData: hashData?.MD2, length: CC_MD2_DIGEST_LENGTH) 92 | } 93 | 94 | 95 | var MD4: String? { 96 | return String(digestData: hashData?.MD4, length: CC_MD4_DIGEST_LENGTH) 97 | } 98 | 99 | 100 | var MD5: String? { 101 | return String(digestData: hashData?.MD5, length: CC_MD5_DIGEST_LENGTH) 102 | } 103 | 104 | 105 | var SHA1: String? { 106 | return String(digestData: hashData?.SHA1, length: CC_SHA1_DIGEST_LENGTH) 107 | } 108 | 109 | 110 | var SHA224: String? { 111 | return String(digestData: hashData?.SHA224, length: CC_SHA224_DIGEST_LENGTH) 112 | } 113 | 114 | 115 | var SHA256: String? { 116 | return String(digestData: hashData?.SHA256, length: CC_SHA256_DIGEST_LENGTH) 117 | } 118 | 119 | 120 | var SHA384: String? { 121 | return String(digestData: hashData?.SHA384, length: CC_SHA384_DIGEST_LENGTH) 122 | } 123 | 124 | 125 | var SHA512: String? { 126 | return String(digestData: hashData?.SHA512, length: CC_SHA512_DIGEST_LENGTH) 127 | } 128 | 129 | 130 | fileprivate var hashData: Data? 131 | { 132 | return data(using: String.Encoding.utf8, allowLossyConversion: false) 133 | } 134 | 135 | 136 | fileprivate init?(digestData: Data?, length: Int32) { 137 | guard let digestData = digestData else { return nil } 138 | var digest = [UInt8](repeating: 0, count: Int(length)) 139 | (digestData as NSData).getBytes(&digest, length: Int(length) * MemoryLayout.size) 140 | 141 | var string = "" 142 | for i in 0.. Data { 82 | let encryptedData = NSMutableData(length: data.count + self.options.algoritmBlockSize)! 83 | var encryptedMoved : Int = 0 84 | var keyPointer : UnsafePointer? = nil 85 | self.cryptoKey.withUnsafeBytes({ (ptr) in keyPointer = ptr}) 86 | var ivPointer : UnsafePointer? = nil 87 | self.IV.withUnsafeBytes({ (ptr) in ivPointer = ptr}) 88 | let result = CCCrypt(CCOperation(kCCEncrypt), self.options.algoritm, self.options.options, keyPointer, self.cryptoKey.count, ivPointer, (data as NSData).bytes, data.count, encryptedData.mutableBytes, encryptedData.length, &encryptedMoved) 89 | encryptedData.length = encryptedMoved 90 | if result != CCCryptorStatus(kCCSuccess) { throw SymmetricKeyError.encryptError } 91 | else { return encryptedData as Data } 92 | } 93 | 94 | 95 | public func decrypt(_ data: Data) throws -> Data { 96 | let decryptedData = NSMutableData(length: data.count + self.options.algoritmBlockSize)! 97 | var decryptedMoved = 0 98 | var keyPointer : UnsafePointer? = nil 99 | self.cryptoKey.withUnsafeBytes({ (ptr) in keyPointer = ptr}) 100 | var ivPointer : UnsafePointer? = nil 101 | self.IV.withUnsafeBytes({ (ptr) in ivPointer = ptr}) 102 | let result = CCCrypt(CCOperation(kCCDecrypt), self.options.algoritm, self.options.options, keyPointer, self.cryptoKey.count, ivPointer, (data as NSData).bytes, data.count, decryptedData.mutableBytes, decryptedData.length, &decryptedMoved) 103 | decryptedData.length = decryptedMoved 104 | if result != CCCryptorStatus(kCCSuccess) { throw SymmetricKeyError.decryptError } 105 | else { return decryptedData as Data } 106 | } 107 | 108 | 109 | public func signature(_ data: Data) throws -> Data { 110 | let hash = data.SHA256 111 | var key = self.hmacKey 112 | if key == nil { key = self.cryptoKey } 113 | let signature = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))! 114 | CCHmac(self.options.hmac, (key! as NSData).bytes, key!.count, (hash as NSData).bytes, hash.count, signature.mutableBytes) 115 | return signature as Data 116 | } 117 | 118 | 119 | public func verify(_ data: Data, signature: Data) throws -> Bool { 120 | do { 121 | let signatureData = try self.signature(data) 122 | if signatureData == signature { return true } 123 | else { return false } 124 | } catch { 125 | throw error 126 | } 127 | } 128 | 129 | 130 | // public func encryptThenMac(data: NSData) throws -> NSData { 131 | // return NSData() 132 | // } 133 | // 134 | // 135 | // public func verifyThenDecrypt(data: NSData) throws -> NSData { 136 | // return NSData() 137 | // } 138 | } 139 | 140 | -------------------------------------------------------------------------------- /Keys/AsymmetricKeys-macOS.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsymmetricKeys-macOS.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/10/15. 6 | // 7 | // 8 | 9 | 10 | import Security 11 | 12 | 13 | public extension PublicKey { 14 | 15 | public func encrypt(_ data: Data) throws -> Data { 16 | let error : UnsafeMutablePointer?>? = nil 17 | let transform = SecEncryptTransformCreate(self.key, error) 18 | if transform.bytes != nil { throw Exception.cannotEncryptData } 19 | let dataRef = CFDataCreate(kCFAllocatorDefault, (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count), data.count) 20 | SecTransformSetAttribute(transform, kSecTransformInputAttributeName, dataRef!, error) 21 | if error != nil { throw Exception.cannotEncryptData } 22 | let encryptedData = SecTransformExecute(transform, error) as? Data 23 | if encryptedData == nil { throw Exception.cannotEncryptData } 24 | return encryptedData! 25 | } 26 | 27 | 28 | public func verify(_ data: Data, signature: Data) throws -> Bool { 29 | let error : UnsafeMutablePointer?>? = nil 30 | let transform = SecVerifyTransformCreate(self.key, signature as CFData?, error) 31 | if error != nil || transform == nil { throw Exception.cannotVerifyData } 32 | let dataRef = CFDataCreate(kCFAllocatorDefault, (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count), data.count) 33 | SecTransformSetAttribute(transform!, kSecTransformInputAttributeName, dataRef!, error) 34 | SecTransformSetAttribute(transform!, kSecPaddingKey, kSecPaddingPKCS1Key, error) 35 | SecTransformSetAttribute(transform!, kSecDigestTypeAttribute, kSecDigestSHA1, error) 36 | SecTransformSetAttribute(transform!, kSecDigestLengthAttribute, 160 as CFTypeRef, error) 37 | if error != nil { throw Exception.cannotVerifyData } 38 | let result = SecTransformExecute(transform!, error) as? Bool 39 | if error != nil { throw Exception.cannotVerifyData } 40 | if result == true { return true } 41 | else { return false } 42 | } 43 | } 44 | 45 | 46 | public extension PrivateKey { 47 | 48 | public func decrypt(_ data: Data) throws -> Data { 49 | let error : UnsafeMutablePointer?>? = nil 50 | let transform = SecDecryptTransformCreate(self.key, error) 51 | if error != nil { throw Exception.cannotDecryptData } 52 | let dataRef = CFDataCreate(kCFAllocatorDefault, (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count), data.count) 53 | SecTransformSetAttribute(transform, kSecTransformInputAttributeName, dataRef!, error) 54 | if error != nil { throw Exception.cannotDecryptData } 55 | let decryptedData = SecTransformExecute(transform, error) as? Data 56 | if decryptedData == nil { throw Exception.cannotDecryptData } 57 | return decryptedData! 58 | } 59 | 60 | 61 | public func signature(_ data: Data) throws -> Data { 62 | let error : UnsafeMutablePointer?>? = nil 63 | let transform = SecSignTransformCreate(self.key, error) 64 | if transform == nil { throw Exception.cannotSignData } 65 | let dataRef = CFDataCreate(kCFAllocatorDefault, (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count), data.count) 66 | SecTransformSetAttribute(transform!, kSecTransformInputAttributeName, dataRef!, error) 67 | SecTransformSetAttribute(transform!, kSecPaddingKey, kSecPaddingPKCS1Key, error) 68 | SecTransformSetAttribute(transform!, kSecDigestTypeAttribute, kSecDigestSHA1, error) 69 | SecTransformSetAttribute(transform!, kSecDigestLengthAttribute, 160 as CFTypeRef, error) 70 | if error != nil { throw Exception.cannotSignData } 71 | let signature = SecTransformExecute(transform!, error) as? Data 72 | if signature == nil { throw Exception.cannotSignData } 73 | return signature! 74 | } 75 | } 76 | 77 | 78 | public extension AsymmetricKeys { 79 | 80 | static func secKeyFromData(_ data:Data, publicKey: Bool) throws -> SecKey { 81 | 82 | let query :[String:AnyObject] = [ 83 | String(kSecClass): kSecClassKey, 84 | String(kSecAttrKeyType): kSecAttrKeyTypeRSA, 85 | String(kSecAttrApplicationTag): TemporaryKeyTag as AnyObject ] 86 | SecItemDelete(query as CFDictionary) 87 | 88 | var result : OSStatus = 0 89 | var format : SecExternalFormat = SecExternalFormat.formatOpenSSL 90 | var itemType : SecExternalItemType 91 | if publicKey == true { itemType = SecExternalItemType.itemTypePublicKey } 92 | else { itemType = SecExternalItemType.itemTypePrivateKey } 93 | var items : CFArray? 94 | result = SecItemImport(data as CFData, nil, &format, &itemType, SecItemImportExportFlags.pemArmour, nil, nil, &items) 95 | 96 | if result != noErr { throw Exception.cannotCreateSecKeyFromData } 97 | return (items! as [AnyObject])[0] as! SecKey 98 | } 99 | } 100 | 101 | 102 | public extension PublicKey { 103 | 104 | public init(publicKey key: Data) throws { 105 | self.key = try AsymmetricKeys.secKeyFromData(key, publicKey: true) 106 | self.options = AsymmetricKeys.Options.Default 107 | self.tag = nil 108 | } 109 | } 110 | 111 | 112 | public extension PrivateKey { 113 | 114 | public init(privateKey key: Data) throws { 115 | self.key = try AsymmetricKeys.secKeyFromData(key, publicKey: false) 116 | self.options = AsymmetricKeys.Options.Default 117 | self.tag = nil 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Keys/AsymmetricKeys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsymmetricKeys.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/11/15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | 13 | // 非对称密钥组。 用于加密需要传输到其他设备时用到的数据。 14 | public struct AsymmetricKeys { 15 | 16 | public typealias Keys = (publicKey:PublicKey, privateKey:PrivateKey) 17 | 18 | 19 | public enum Exception : Error { 20 | case cannotCreateSecKeyFromData 21 | case notFound 22 | case deleteError 23 | } 24 | 25 | 26 | public struct Options { 27 | 28 | public let keySize : CFNumber 29 | public let cryptoPadding : SecPadding 30 | public let signaturePadding : SecPadding 31 | public let tag : String 32 | 33 | 34 | public static var Default : Options { 35 | return Options(tag: TemporaryKeyTag, size: 2048 as CFNumber, cryptoPadding: SecPadding.PKCS1, signaturePadding: SecPadding.PKCS1SHA1) 36 | } 37 | 38 | 39 | public init(tag:String, size:CFNumber, cryptoPadding: SecPadding, signaturePadding: SecPadding) { 40 | self.tag = tag 41 | self.keySize = size 42 | self.cryptoPadding = cryptoPadding 43 | self.signaturePadding = signaturePadding 44 | } 45 | } 46 | 47 | 48 | fileprivate static func generateSecKeys(_ options: Options) -> Keys 49 | { 50 | let parameters = [kSecAttrType as String:kSecAttrKeyTypeRSA, 51 | kSecAttrKeySizeInBits as String: options.keySize, 52 | kSecAttrLabel as String: options.tag] as [String : Any] 53 | var publicKeyPointer : SecKey? 54 | var privateKeyPointer : SecKey? 55 | SecKeyGeneratePair(parameters as CFDictionary, &publicKeyPointer, &privateKeyPointer) 56 | let publicKey = PublicKey(key: publicKeyPointer!, options: options) 57 | let privateKey = PrivateKey(key: privateKeyPointer!, options: options) 58 | return Keys(publicKey,privateKey) 59 | } 60 | 61 | 62 | public static func generateKeyPair(_ options:Options = Options.Default) -> Keys 63 | { 64 | return generateSecKeys(options) 65 | } 66 | 67 | 68 | public static func generateKeyPairs(_ options:Options = Options.Default) -> (cryptoKeys: Keys, validationKeys: Keys) { 69 | let cryptoKeys = generateSecKeys(options) 70 | let validationKeys = generateSecKeys(options) 71 | return (cryptoKeys: cryptoKeys, validationKeys: validationKeys) 72 | } 73 | 74 | 75 | public static func get(_ privateTag: String, publicTag: String, validationPrivateTag: String? = nil, validationPublicTag: String? = nil , options: Options = Options.Default) throws -> (cryptoKeys: Keys, validationKeys: Keys?) { 76 | 77 | func secKeyWithTag(_ tag:String) throws -> SecKey { 78 | let query = [ 79 | String(kSecClassKey): kSecClass, 80 | String(kSecAttrApplicationTag): tag, 81 | String(kSecAttrKeyType): kSecAttrKeyTypeRSA, 82 | String(kSecReturnRef): true 83 | ] as [String : Any] 84 | let keyPointer : UnsafeMutablePointer? = nil 85 | let result = SecItemCopyMatching(query as CFDictionary, keyPointer) 86 | if result != OSStatus(kCCSuccess) { throw Exception.notFound } 87 | else { return keyPointer!.pointee as! SecKey } 88 | } 89 | 90 | 91 | func keysWithTags(_ privateTag:String, publicTag:String) throws -> Keys { 92 | let privateKeyRef = try secKeyWithTag(privateTag) 93 | let publicKeyRef = try secKeyWithTag(publicTag) 94 | let privateKey = PrivateKey(key: privateKeyRef, options: options) 95 | let publicKey = PublicKey(key: publicKeyRef, options: options) 96 | return Keys(publicKey,privateKey) 97 | } 98 | 99 | 100 | do { 101 | let keys = try keysWithTags(privateTag, publicTag: publicTag) 102 | var validationKeys : Keys? 103 | if let publicT = validationPublicTag, let privateT = validationPrivateTag { 104 | validationKeys = try keysWithTags(privateT, publicTag: publicT) 105 | } 106 | return (cryptoKeys: keys, validationKeys: validationKeys) 107 | } catch { 108 | throw error 109 | } 110 | } 111 | 112 | 113 | public func save(_ privateTag: String, publicTag: String, validationPrivateTag: String? = nil, validationPublicTag: String? = nil) throws { 114 | 115 | } 116 | 117 | 118 | public func remove() throws { 119 | 120 | } 121 | 122 | 123 | public static func removeKeyWithTag(_ tag:String) throws { 124 | let query = [ 125 | String(kSecClassKey): kSecClass, 126 | String(kSecAttrApplicationTag): tag 127 | ] as [String : Any] 128 | let result = SecItemDelete(query as CFDictionary) 129 | if result != OSStatus(kCCSuccess) { throw Exception.deleteError } 130 | } 131 | } 132 | 133 | 134 | // 私钥。 用于加密与获得数据验证码 135 | public struct PrivateKey : Decryptable { 136 | 137 | public enum Exception : Error { 138 | case cannotDecryptData 139 | case cannotSignData 140 | } 141 | 142 | 143 | public var tag : String? 144 | public var key : SecKey 145 | public var options : AsymmetricKeys.Options 146 | 147 | 148 | fileprivate init(key:SecKey, options: AsymmetricKeys.Options) { 149 | self.options = options 150 | self.key = key 151 | } 152 | } 153 | 154 | 155 | // 公钥。 用于解密与验证数据 156 | public struct PublicKey : Encryptable { 157 | 158 | public enum Exception : Error { 159 | case cannotEncryptData 160 | case cannotVerifyData 161 | } 162 | 163 | 164 | public var tag : String? 165 | public var key : SecKey! 166 | public var options : AsymmetricKeys.Options 167 | 168 | 169 | fileprivate init(key:SecKey, options: AsymmetricKeys.Options) { 170 | self.options = options 171 | self.key = key 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/remaerd/Keys) 2 | [![Version](https://img.shields.io/github/release/soffes/Crypto.svg)](https://github.com/remaerd/Keys/releases) 3 | [![License](https://img.shields.io/pypi/l/Django.svg)](https://github.com/remaerd/Keys/blob/master/LICENSE) 4 | 5 | 6 | # Keys - Keys of data encryption 7 | [中文介绍](https://github.com/remaerd/Keys/blob/master/README-CHINESE.MD) 8 | 9 | ## Example 10 | 11 | ```swift 12 | let password = Password("Secret") 13 | let key = SymmetricKey() 14 | password.encrypt(data) 15 | let data = "Hello World!".dataUsingEncoding(NSUTF8StringEncoding)! 16 | let encryptedData = key.encrypt(data) 17 | let decryptedData = key.decrypt(encryptedData) 18 | print(decryptedData) // "Hello World!" 19 | ``` 20 | 21 | `Keys` is a data encryption framework for iOS / OS X. It's simplifies the most difficult parts of CommonCrypto, so you don't have to deal with those head stretching interfaces on your own. 22 | 23 | `Keys` is design to work with **Best practice encryption only**. If you are not familiar with Master Key encryption and Public Key cncryption, Please read the following materials to learn about how iMessage and 1Password protect your data. 24 | 25 | - 1Password https://support.1password.com/opvault-design/ 26 | - iMessage https://www.apple.com/business/docs/iOS_Security_Guide.pdf 27 | 28 | ## Three type of Keys 29 | 30 | There're three kind of keys in the framwork. Use them according to what you are encrypting. 31 | 32 | - **Symmetric Key** for encrypting / decrypting local data saving in the same device 33 | - **Asymmetric Keys** for encrypting / decrypting data need to be transfers between devices or servers. 34 | - **Password** for encrypting / decrypting Symmetric Keys 35 | 36 | 37 | ## Best practice 38 | 39 | ### Carthage 40 | 41 | Please intall [Carthage](https://github.com/carthage/carthage) then insert the following code into your `Cartfile`. 42 | 43 | ``` 44 | github "remaerd/Keys" 45 | ``` 46 | 47 | ### Encrypting local data 48 | 49 | When you need to encrypt a piece of data. You need to create a `SymmetricKey` object to encrypt the data. Then, create a `Password` object from users' `String` password. Finally, encrypt the `SymmetricKey` object with the `Password`. Encrypting your users's data with `String` password is consider dangerous and naïve, please never do this. Again, You must **NOT** encrypt data with users' `String` password. 50 | 51 | #### Creating `Password` object 52 | 53 | ```swift 54 | let password = Password("Hello") 55 | let salt = password.salt 56 | let rounds = password.rounds 57 | let data = password.data 58 | ``` 59 | 60 | When you create a new `Password` object with `String`. A random `salt` and `rounds` number will be generated with it. 61 | You need to save the `salt` and `rounds` data locally, or you will create different `Password` object with the same `String`. 62 | 63 | Do **NOT** save the `password.data` locally, or hackers will decrypt users' data by decrypting other encryption keys without the password. 64 | 65 | #### Creating `SymmetricKey` object 66 | 67 | ```swift 68 | let key = SymmetricKey() 69 | let encryptionKey = key.cryptoKey 70 | let iv = key.IV 71 | let hmacKey = key.hmacKey 72 | ``` 73 | 74 | When you are encrypting local data. You will need a `SymmetricKey` object to encrypt your data. Random Data will be generate safely, and you need to save the `cryptoKey`, `IV` and `hmacKey` of a `SymmetricKey` if you need to use the same `SymmetricKey` later. 75 | 76 | #### Encrypting data 77 | 78 | ```swift 79 | let key = SymmetricKey() 80 | let data = "Hello World!".dataUsingEncoding(NSUTF8StringEncoding)! 81 | do { 82 | let encryptedData = try key.encrypt(data) 83 | print(encryptedData) 84 | } catch { 85 | print("Cannot encrypt data") 86 | } 87 | ``` 88 | 89 | #### Decrypting data 90 | 91 | ```swift 92 | let key = SymmetricKey(key: keyData, hmacKey: hmacData, IV: IVData) 93 | do { 94 | let decryptedData = try key.decrypt(data) 95 | print(decryptedData) 96 | } catch { 97 | print("Cannot decrypt data") 98 | } 99 | ``` 100 | 101 | ### Encrypting data between devices / servers 102 | 103 | When you need to encrypt data between devices, 'AsymmetricKeys' is the only option. Imagine there're two keys for one safe. You open a safe with a key and put gold into it. And you give a different key to someone you trust, then he can open the safe with a different key, but he can't put gold into your safe. 104 | 105 | #### Creating `AsymmetricKeys` object 106 | 107 | ```swift 108 | let keys = AsymmetricKeys.generateKeyPair() 109 | let publicKey = keys.publicKey 110 | let privateKey = key.privateKey 111 | ``` 112 | 113 | When your create a pair of `AsymmetricKeys`, a `publicKey` and a `privateKey` will be generated. So you can use them to encrypt data, then send the other key and encrypted data to third-parties. 114 | 115 | It's a good practice to generate two pair of `AsymmetricKeys`, so you can encrypt / decrypt / sign / validate your data with these four keys. 116 | 117 | #### CommonCrypto vs. OpenSSL 118 | 119 | If you use ```AsymmetricKeys.generateKeyPair()``` to generate `AsymmetricKeys`. those keys only works between iOS devices. If you need to use those keys between servers or Android devices. you need to use **OpenSSL** to create RSA Asymmetric Keys. 120 | 121 | To encrypt iOS devices' data, do this: 122 | 123 | ```swift 124 | let data = "Hello World!".dataUsingEncoding(NSUTF8StringEncoding)! 125 | let keys = AsymmetricKeys.generateKeyPair() 126 | let publicKey = keys.publicKey 127 | let privateKey = keys.privateKey 128 | do { 129 | let encryptedData = try privateKey.encrypt(data) 130 | let decryptedData = try publicKey.decrypt(data) 131 | print(NSString(data: decryptedData, encoding: NSUTF8StringEncoding)) 132 | // Hello World 133 | } catch { 134 | print("Cannot encrypt data") 135 | } 136 | ``` 137 | 138 | If you need to transfer encrypted between iOS Device and your servers. Generate RSA keys like this with the terminal.app 139 | 140 | ```bash 141 | openssl genrsa -out private.pem 2048 142 | openssl rsa -in private.pem -pubout -out public.pub 143 | ``` 144 | 145 | The iOS client get the Public Key and encrypted data. So you can decrypt the data with the public key. 146 | 147 | ```swift 148 | let data = "Hello World!".dataUsingEncoding(NSUTF8StringEncoding)! 149 | let publicKeyData = NSData(contentsOfURL: NSBundle.mainBundle().URLForResource("keys-public", withExtension: "pem")!)! 150 | let privateKeyData = NSData(contentsOfURL: NSBundle.mainBundle().URLForResource("keys-private", withExtension: "pem")!)! 151 | do { 152 | let publicKey = try PublicKey(publicKey:privateKeyData) 153 | let privateKey = try PrivateKey(privateKey:privateKeyData) 154 | let encryptedData = try privateKey.encrypt(data) 155 | let decryptedData = try publicKey.decrypt(encryptedData) 156 | print(NSString(data: decryptedData, encoding: NSUTF8StringEncoding)) 157 | // Hello World 158 | } catch { 159 | print("Cannot decrypt data") 160 | } 161 | ``` 162 | 163 | -------------------------------------------------------------------------------- /Keys/AsymmetricKeys-iOS.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsymmetricKeys.swift 3 | // Keys 4 | // 5 | // Created by Sean Cheng on 8/8/15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | 13 | public extension PublicKey { 14 | 15 | func encrypt(_ data: Data) throws -> Data { 16 | let dataPointer = (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count) 17 | var encryptedDataLength = SecKeyGetBlockSize(self.key) 18 | var encryptedData = [UInt8](repeating: 0, count: Int(encryptedDataLength)) 19 | let result = SecKeyEncrypt(self.key, self.options.cryptoPadding, dataPointer, data.count, &encryptedData, &encryptedDataLength) 20 | if result != noErr { throw Exception.cannotEncryptData } 21 | return Data(bytes: UnsafePointer(encryptedData), count: encryptedDataLength) 22 | } 23 | 24 | 25 | func verify(_ data: Data, signature: Data) throws -> Bool { 26 | let hash = data.SHA1 27 | var result : OSStatus 28 | var pointer : UnsafePointer? = nil 29 | hash.withUnsafeBytes({ (ptr) in pointer = ptr}) 30 | let signaturePointer = (signature as NSData).bytes.bindMemory(to: UInt8.self, capacity: signature.count) 31 | result = SecKeyRawVerify(self.key, self.options.signaturePadding, pointer!, hash.count, signaturePointer, signature.count) 32 | if result != 0 { return false } else { return true } 33 | } 34 | } 35 | 36 | 37 | public extension PrivateKey { 38 | 39 | func decrypt(_ data: Data) throws -> Data { 40 | let dataPointer = (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count) 41 | var decryptedDataLength = SecKeyGetBlockSize(self.key) 42 | var decryptedData = [UInt8](repeating: 0, count: Int(decryptedDataLength)) 43 | let result = SecKeyDecrypt(self.key, self.options.cryptoPadding, dataPointer, data.count, &decryptedData, &decryptedDataLength) 44 | if result != noErr { throw Exception.cannotDecryptData } 45 | return Data(bytes: UnsafePointer(decryptedData), count: decryptedDataLength) 46 | } 47 | 48 | 49 | func signature(_ data: Data) throws -> Data { 50 | let hash = data.SHA1 51 | var signatureDataLength = SecKeyGetBlockSize(self.key) 52 | var signatureData = [UInt8](repeating: 0, count: Int(signatureDataLength)) 53 | var pointer : UnsafePointer? = nil 54 | hash.withUnsafeBytes({ (ptr) in pointer = ptr}) 55 | let status = SecKeyRawSign(self.key, self.options.signaturePadding, pointer!, hash.count, &signatureData, &signatureDataLength) 56 | if status != OSStatus(kCCSuccess) { throw Exception.cannotSignData } 57 | return Data(bytes: UnsafePointer(signatureData), count: signatureDataLength) 58 | } 59 | } 60 | 61 | 62 | public extension AsymmetricKeys { 63 | 64 | static func secKeyFromData(_ data:Data, publicKey:Bool) throws -> SecKey 65 | { 66 | func SecKeyBelowiOS9() throws -> SecKey 67 | { 68 | var query :[String:AnyObject] = [ 69 | String(kSecClass): kSecClassKey, 70 | String(kSecAttrKeyType): kSecAttrKeyTypeRSA, 71 | String(kSecAttrApplicationTag): TemporaryKeyTag as AnyObject ] 72 | SecItemDelete(query as CFDictionary) 73 | 74 | query[String(kSecValueData)] = data as AnyObject? 75 | if publicKey == true { 76 | query[String(kSecAttrKeyClass)] = kSecAttrKeyClassPublic 77 | } else { 78 | query[String(kSecAttrKeyClass)] = kSecAttrKeyClassPrivate 79 | } 80 | var persistentKey : CFTypeRef? 81 | var result : OSStatus = 0 82 | result = SecItemAdd(query as CFDictionary, &persistentKey) 83 | print(result) 84 | if result != noErr { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 85 | 86 | query[String(kSecValueData)] = nil 87 | query[String(kSecReturnPersistentRef)] = nil 88 | query[String(kSecReturnRef)] = true as AnyObject? 89 | 90 | var keyPointer: AnyObject? 91 | result = SecItemCopyMatching(query as CFDictionary, &keyPointer) 92 | if result != noErr { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 93 | return keyPointer as! SecKey 94 | } 95 | 96 | 97 | func SecKeyFromiOS10() throws -> SecKey 98 | { 99 | let error : UnsafeMutablePointer?>? = nil 100 | 101 | var query :[String:AnyObject] = [ 102 | String(kSecAttrKeyType): kSecAttrKeyTypeRSA, 103 | String(kSecAttrKeySizeInBits): 1024 as CFNumber ] 104 | if publicKey == true { query[String(kSecAttrKeyClass)] = kSecAttrKeyClassPublic } 105 | else { query[String(kSecAttrKeyClass)] = kSecAttrKeyClassPrivate } 106 | 107 | if #available(iOS 10.0, *) 108 | { 109 | let key = SecKeyCreateWithData(data as CFData, query as CFDictionary, error) 110 | if ((error) != nil || key == nil) { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 111 | return key! 112 | } 113 | else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 114 | } 115 | 116 | if #available(iOS 10.0, *) { return try SecKeyFromiOS10() } 117 | else { return try SecKeyBelowiOS9() } 118 | } 119 | } 120 | 121 | 122 | public extension PublicKey { 123 | 124 | init(publicKey key: Data, options: AsymmetricKeys.Options = AsymmetricKeys.Options.Default) throws { 125 | 126 | func stripPublicKeyHeader(_ data:Data) throws -> Data { 127 | 128 | var buffer = [UInt8](repeating: 0, count: data.count) 129 | (data as NSData).getBytes(&buffer, length: data.count) 130 | var index = 0 131 | if buffer[index] != 0x30 { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 132 | index += 1 133 | if buffer[index] > 0x80 { index += Int(buffer[index] - UInt8(0x80) + UInt8(1)) } else { index += 1 } 134 | let seqiod : [UInt8] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00] 135 | if memcmp(&buffer, seqiod, 15) == 1 { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 136 | 137 | index += 15 138 | 139 | if buffer[index] != 0x03 { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 140 | index += 1 141 | if buffer[index] > 0x80 { index += Int(buffer[index] - UInt8(0x80) + UInt8(1)) } else { index += 1 } 142 | if buffer[index] != 0 { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 143 | index += 1 144 | 145 | var noHeaderBuffer = [UInt8](repeating: 0, count: data.count - index) 146 | (data as NSData).getBytes(&noHeaderBuffer, range: NSRange(location: index, length: data.count - index)) 147 | 148 | return Data(bytes: UnsafePointer(noHeaderBuffer), count: noHeaderBuffer.count) 149 | } 150 | 151 | 152 | func generatePublicKeyFromData() throws -> SecKey { 153 | 154 | guard var keyString = String(data: key, encoding: String.Encoding.utf8) else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 155 | 156 | if (keyString.hasPrefix("-----BEGIN PUBLIC KEY-----\n") && ( keyString.hasSuffix("-----END PUBLIC KEY-----\n") || keyString.hasSuffix("-----END PUBLIC KEY-----"))) { 157 | keyString = keyString.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----", with: "") 158 | keyString = keyString.replacingOccurrences(of: "-----END PUBLIC KEY-----", with: "") 159 | keyString = keyString.replacingOccurrences(of: "\r", with: "") 160 | keyString = keyString.replacingOccurrences(of: "\n", with: "") 161 | keyString = keyString.replacingOccurrences(of: "\t", with: "") 162 | keyString = keyString.replacingOccurrences(of: " ", with: "") 163 | 164 | guard let data = Data(base64Encoded: keyString) else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 165 | 166 | let noHeaderKey = try stripPublicKeyHeader(data) 167 | return try AsymmetricKeys.secKeyFromData(noHeaderKey, publicKey: true) 168 | } 169 | 170 | throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData 171 | } 172 | 173 | do { self.key = try generatePublicKeyFromData() } 174 | catch { throw error } 175 | self.options = options 176 | self.tag = nil 177 | } 178 | } 179 | 180 | 181 | public extension PrivateKey { 182 | 183 | init(privateKey key: Data, options: AsymmetricKeys.Options = AsymmetricKeys.Options.Default) throws { 184 | 185 | func stripPrivateKeyHeader(_ data: Data) throws -> Data { 186 | 187 | var buffer = [UInt8](repeating: 0, count: data.count) 188 | (data as NSData).getBytes(&buffer, length: data.count) 189 | 190 | var index = 22 191 | if buffer[index] != 0x04 { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 192 | index += 1 193 | var length = buffer[index] 194 | index += 1 195 | let det = length & 0x80 196 | if det == 0 { length = length & 0x7f } else { 197 | var byteCount = length & 0x7f 198 | if Int(byteCount) + index > data.count { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 199 | var accum : UInt8 = 0 200 | var char = buffer[index] 201 | index += Int(byteCount) 202 | while byteCount != 0 { 203 | accum = (accum << 8) + char 204 | char += 1 205 | byteCount -= 1 206 | } 207 | length = accum 208 | } 209 | return data.subdata(in: Range(uncheckedBounds: (index,index + Int(length)))) 210 | } 211 | 212 | 213 | func generatePrivateKeyFromData() throws -> SecKey { 214 | 215 | guard var keyString = String(data: key, encoding: String.Encoding.utf8) else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 216 | 217 | if (keyString.hasPrefix("-----BEGIN RSA PRIVATE KEY-----\n") && ( keyString.hasSuffix("-----END RSA PRIVATE KEY-----\n") || keyString.hasSuffix("-----END RSA PRIVATE KEY-----"))) { 218 | keyString = keyString.replacingOccurrences(of:"-----BEGIN RSA PRIVATE KEY-----", with: "") 219 | keyString = keyString.replacingOccurrences(of:"-----END RSA PRIVATE KEY-----", with: "") 220 | keyString = keyString.replacingOccurrences(of:"\r", with: "") 221 | keyString = keyString.replacingOccurrences(of:"\n", with: "") 222 | keyString = keyString.replacingOccurrences(of:"\t", with: "") 223 | keyString = keyString.replacingOccurrences(of:" ", with: "") 224 | 225 | guard let data = Data(base64Encoded: keyString) else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 226 | return try AsymmetricKeys.secKeyFromData(data, publicKey: false) 227 | 228 | } else { throw AsymmetricKeys.Exception.cannotCreateSecKeyFromData } 229 | } 230 | 231 | 232 | self.key = try generatePrivateKeyFromData() 233 | self.options = options 234 | self.tag = nil 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /Keys.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0343E2D51BDA9E04007C2FD4 /* AsymmetricKeys-iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580AC71B75263B00F4AB36 /* AsymmetricKeys-iOS.swift */; }; 11 | 0343E2D61BDAA279007C2FD4 /* AsymmetricKeys-macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B7151C1B78D6E100A15ECF /* AsymmetricKeys-macOS.swift */; }; 12 | 0343E2D71BDAB18D007C2FD4 /* AsymmetricKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B7151E1B7A0A1900A15ECF /* AsymmetricKeys.swift */; }; 13 | 0343E2D81BDAB18E007C2FD4 /* AsymmetricKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B7151E1B7A0A1900A15ECF /* AsymmetricKeys.swift */; }; 14 | 03580AB41B75254C00F4AB36 /* Keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 03580AA01B75250E00F4AB36 /* Keys.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 03580AB51B75254D00F4AB36 /* Keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 03580AA01B75250E00F4AB36 /* Keys.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | 03580ABF1B75262100F4AB36 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580ABE1B75262100F4AB36 /* Keys.swift */; }; 17 | 03580AC01B75262100F4AB36 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580ABE1B75262100F4AB36 /* Keys.swift */; }; 18 | 03580AC21B75262B00F4AB36 /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580AC11B75262B00F4AB36 /* Password.swift */; }; 19 | 03580AC31B75262B00F4AB36 /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580AC11B75262B00F4AB36 /* Password.swift */; }; 20 | 03580AC51B75263500F4AB36 /* SymmetricKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580AC41B75263500F4AB36 /* SymmetricKey.swift */; }; 21 | 03580AC61B75263500F4AB36 /* SymmetricKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03580AC41B75263500F4AB36 /* SymmetricKey.swift */; }; 22 | 037C23B01BD9F4A1001B91D3 /* keys-private.pem in Resources */ = {isa = PBXBuildFile; fileRef = 037C23AE1BD9F4A1001B91D3 /* keys-private.pem */; }; 23 | 037C23B11BD9F4A1001B91D3 /* keys-private.pem in Resources */ = {isa = PBXBuildFile; fileRef = 037C23AE1BD9F4A1001B91D3 /* keys-private.pem */; }; 24 | 037C23B21BD9F4A1001B91D3 /* keys-public.pem in Resources */ = {isa = PBXBuildFile; fileRef = 037C23AF1BD9F4A1001B91D3 /* keys-public.pem */; }; 25 | 037C23B31BD9F4A1001B91D3 /* keys-public.pem in Resources */ = {isa = PBXBuildFile; fileRef = 037C23AF1BD9F4A1001B91D3 /* keys-public.pem */; }; 26 | 03B715191B774B5A00A15ECF /* Hash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715181B774B5A00A15ECF /* Hash.swift */; }; 27 | 03B715211B7A0AD700A15ECF /* Hash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715181B774B5A00A15ECF /* Hash.swift */; }; 28 | 03B7155D1B7A481100A15ECF /* PasswordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B7155C1B7A481100A15ECF /* PasswordTests.swift */; }; 29 | 03B7155F1B7A481100A15ECF /* Keys.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03580AAB1B75253000F4AB36 /* Keys.framework */; }; 30 | 03B7156E1B7A484500A15ECF /* Keys.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03580A9E1B75250E00F4AB36 /* Keys.framework */; }; 31 | 03B715741B7A48DB00A15ECF /* PasswordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B7155C1B7A481100A15ECF /* PasswordTests.swift */; }; 32 | 03B715761B7A492600A15ECF /* SymmetricKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715751B7A492600A15ECF /* SymmetricKeyTests.swift */; }; 33 | 03B715771B7A492600A15ECF /* SymmetricKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715751B7A492600A15ECF /* SymmetricKeyTests.swift */; }; 34 | 03B715791B7A493800A15ECF /* AsymmetricKeysTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715781B7A493800A15ECF /* AsymmetricKeysTests.swift */; }; 35 | 03B7157A1B7A493800A15ECF /* AsymmetricKeysTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B715781B7A493800A15ECF /* AsymmetricKeysTests.swift */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXContainerItemProxy section */ 39 | 03B715601B7A481100A15ECF /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 03580A741B75245400F4AB36 /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = 03580AAA1B75253000F4AB36; 44 | remoteInfo = "Keys OSX"; 45 | }; 46 | 03B7156F1B7A484500A15ECF /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 03580A741B75245400F4AB36 /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 03580A9D1B75250E00F4AB36; 51 | remoteInfo = "Keys iOS"; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | 03580A841B75246100F4AB36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 03580A881B75248200F4AB36 /* CommonCrypto.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CommonCrypto.xcconfig; sourceTree = ""; }; 58 | 03580A891B75248200F4AB36 /* iphoneos.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = iphoneos.modulemap; sourceTree = ""; }; 59 | 03580A8A1B75248200F4AB36 /* iphonesimulator.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = iphonesimulator.modulemap; sourceTree = ""; }; 60 | 03580A8B1B75248200F4AB36 /* macosx.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = macosx.modulemap; sourceTree = ""; }; 61 | 03580A9E1B75250E00F4AB36 /* Keys.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Keys.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 03580AA01B75250E00F4AB36 /* Keys.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Keys.h; sourceTree = ""; }; 63 | 03580AA21B75250E00F4AB36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 03580AAB1B75253000F4AB36 /* Keys.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Keys.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 03580ABE1B75262100F4AB36 /* Keys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = ""; }; 66 | 03580AC11B75262B00F4AB36 /* Password.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Password.swift; sourceTree = ""; }; 67 | 03580AC41B75263500F4AB36 /* SymmetricKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SymmetricKey.swift; sourceTree = ""; }; 68 | 03580AC71B75263B00F4AB36 /* AsymmetricKeys-iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AsymmetricKeys-iOS.swift"; sourceTree = ""; }; 69 | 037C23AE1BD9F4A1001B91D3 /* keys-private.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "keys-private.pem"; sourceTree = ""; }; 70 | 037C23AF1BD9F4A1001B91D3 /* keys-public.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "keys-public.pem"; sourceTree = ""; }; 71 | 03B715181B774B5A00A15ECF /* Hash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hash.swift; sourceTree = ""; }; 72 | 03B7151C1B78D6E100A15ECF /* AsymmetricKeys-macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AsymmetricKeys-macOS.swift"; sourceTree = ""; }; 73 | 03B7151E1B7A0A1900A15ECF /* AsymmetricKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsymmetricKeys.swift; sourceTree = ""; }; 74 | 03B7155A1B7A481100A15ECF /* Tests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 03B7155C1B7A481100A15ECF /* PasswordTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTests.swift; sourceTree = ""; }; 76 | 03B7155E1B7A481100A15ECF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 77 | 03B715691B7A484500A15ECF /* Tests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 03B715751B7A492600A15ECF /* SymmetricKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SymmetricKeyTests.swift; sourceTree = ""; }; 79 | 03B715781B7A493800A15ECF /* AsymmetricKeysTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsymmetricKeysTests.swift; sourceTree = ""; }; 80 | /* End PBXFileReference section */ 81 | 82 | /* Begin PBXFrameworksBuildPhase section */ 83 | 03580A9A1B75250E00F4AB36 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | 03580AA71B75253000F4AB36 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 03B715571B7A481100A15ECF /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 03B7155F1B7A481100A15ECF /* Keys.framework in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | 03B715661B7A484500A15ECF /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | 03B7156E1B7A484500A15ECF /* Keys.framework in Frameworks */, 110 | ); 111 | runOnlyForDeploymentPostprocessing = 0; 112 | }; 113 | /* End PBXFrameworksBuildPhase section */ 114 | 115 | /* Begin PBXGroup section */ 116 | 03580A731B75245400F4AB36 = { 117 | isa = PBXGroup; 118 | children = ( 119 | 03580A9F1B75250E00F4AB36 /* Keys */, 120 | 03580A811B75246100F4AB36 /* CommonCrypto */, 121 | 03B7155B1B7A481100A15ECF /* Tests */, 122 | 03580A801B75246100F4AB36 /* Products */, 123 | ); 124 | sourceTree = ""; 125 | }; 126 | 03580A801B75246100F4AB36 /* Products */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 03580A9E1B75250E00F4AB36 /* Keys.framework */, 130 | 03580AAB1B75253000F4AB36 /* Keys.framework */, 131 | 03B7155A1B7A481100A15ECF /* Tests-macOS.xctest */, 132 | 03B715691B7A484500A15ECF /* Tests-iOS.xctest */, 133 | ); 134 | name = Products; 135 | sourceTree = ""; 136 | }; 137 | 03580A811B75246100F4AB36 /* CommonCrypto */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 03580A881B75248200F4AB36 /* CommonCrypto.xcconfig */, 141 | 03580A891B75248200F4AB36 /* iphoneos.modulemap */, 142 | 03580A8A1B75248200F4AB36 /* iphonesimulator.modulemap */, 143 | 03580A8B1B75248200F4AB36 /* macosx.modulemap */, 144 | 03580A841B75246100F4AB36 /* Info.plist */, 145 | ); 146 | path = CommonCrypto; 147 | sourceTree = ""; 148 | }; 149 | 03580A9F1B75250E00F4AB36 /* Keys */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 03580ABE1B75262100F4AB36 /* Keys.swift */, 153 | 03580AC11B75262B00F4AB36 /* Password.swift */, 154 | 03580AC41B75263500F4AB36 /* SymmetricKey.swift */, 155 | 03B7151E1B7A0A1900A15ECF /* AsymmetricKeys.swift */, 156 | 03580AC71B75263B00F4AB36 /* AsymmetricKeys-iOS.swift */, 157 | 03B7151C1B78D6E100A15ECF /* AsymmetricKeys-macOS.swift */, 158 | 03B715181B774B5A00A15ECF /* Hash.swift */, 159 | 03580ABD1B75261100F4AB36 /* Miscellanous */, 160 | ); 161 | path = Keys; 162 | sourceTree = ""; 163 | }; 164 | 03580ABD1B75261100F4AB36 /* Miscellanous */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 03580AA01B75250E00F4AB36 /* Keys.h */, 168 | 03580AA21B75250E00F4AB36 /* Info.plist */, 169 | ); 170 | name = Miscellanous; 171 | sourceTree = ""; 172 | }; 173 | 03B7155B1B7A481100A15ECF /* Tests */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 03B7155C1B7A481100A15ECF /* PasswordTests.swift */, 177 | 03B715751B7A492600A15ECF /* SymmetricKeyTests.swift */, 178 | 03B715781B7A493800A15ECF /* AsymmetricKeysTests.swift */, 179 | 03B7155E1B7A481100A15ECF /* Info.plist */, 180 | 037C23AE1BD9F4A1001B91D3 /* keys-private.pem */, 181 | 037C23AF1BD9F4A1001B91D3 /* keys-public.pem */, 182 | ); 183 | path = Tests; 184 | sourceTree = ""; 185 | }; 186 | /* End PBXGroup section */ 187 | 188 | /* Begin PBXHeadersBuildPhase section */ 189 | 03580A9B1B75250E00F4AB36 /* Headers */ = { 190 | isa = PBXHeadersBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | 03580AB41B75254C00F4AB36 /* Keys.h in Headers */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | 03580AA81B75253000F4AB36 /* Headers */ = { 198 | isa = PBXHeadersBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 03580AB51B75254D00F4AB36 /* Keys.h in Headers */, 202 | ); 203 | runOnlyForDeploymentPostprocessing = 0; 204 | }; 205 | /* End PBXHeadersBuildPhase section */ 206 | 207 | /* Begin PBXNativeTarget section */ 208 | 03580A9D1B75250E00F4AB36 /* Keys iOS */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 03580AA31B75250E00F4AB36 /* Build configuration list for PBXNativeTarget "Keys iOS" */; 211 | buildPhases = ( 212 | 03580A991B75250E00F4AB36 /* Sources */, 213 | 03580A9A1B75250E00F4AB36 /* Frameworks */, 214 | 03580A9B1B75250E00F4AB36 /* Headers */, 215 | 03580A9C1B75250E00F4AB36 /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | ); 221 | name = "Keys iOS"; 222 | productName = Keys; 223 | productReference = 03580A9E1B75250E00F4AB36 /* Keys.framework */; 224 | productType = "com.apple.product-type.framework"; 225 | }; 226 | 03580AAA1B75253000F4AB36 /* Keys macOS */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = 03580AB01B75253000F4AB36 /* Build configuration list for PBXNativeTarget "Keys macOS" */; 229 | buildPhases = ( 230 | 03580AA61B75253000F4AB36 /* Sources */, 231 | 03580AA71B75253000F4AB36 /* Frameworks */, 232 | 03580AA81B75253000F4AB36 /* Headers */, 233 | 03580AA91B75253000F4AB36 /* Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | ); 239 | name = "Keys macOS"; 240 | productName = Keys; 241 | productReference = 03580AAB1B75253000F4AB36 /* Keys.framework */; 242 | productType = "com.apple.product-type.framework"; 243 | }; 244 | 03B715591B7A481100A15ECF /* Tests-macOS */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = 03B715621B7A481100A15ECF /* Build configuration list for PBXNativeTarget "Tests-macOS" */; 247 | buildPhases = ( 248 | 03B715561B7A481100A15ECF /* Sources */, 249 | 03B715571B7A481100A15ECF /* Frameworks */, 250 | 03B715581B7A481100A15ECF /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | 03B715611B7A481100A15ECF /* PBXTargetDependency */, 256 | ); 257 | name = "Tests-macOS"; 258 | productName = Tests; 259 | productReference = 03B7155A1B7A481100A15ECF /* Tests-macOS.xctest */; 260 | productType = "com.apple.product-type.bundle.unit-test"; 261 | }; 262 | 03B715681B7A484500A15ECF /* Tests-iOS */ = { 263 | isa = PBXNativeTarget; 264 | buildConfigurationList = 03B715711B7A484500A15ECF /* Build configuration list for PBXNativeTarget "Tests-iOS" */; 265 | buildPhases = ( 266 | 03B715651B7A484500A15ECF /* Sources */, 267 | 03B715661B7A484500A15ECF /* Frameworks */, 268 | 03B715671B7A484500A15ECF /* Resources */, 269 | ); 270 | buildRules = ( 271 | ); 272 | dependencies = ( 273 | 03B715701B7A484500A15ECF /* PBXTargetDependency */, 274 | ); 275 | name = "Tests-iOS"; 276 | productName = "Tests-iOS"; 277 | productReference = 03B715691B7A484500A15ECF /* Tests-iOS.xctest */; 278 | productType = "com.apple.product-type.bundle.unit-test"; 279 | }; 280 | /* End PBXNativeTarget section */ 281 | 282 | /* Begin PBXProject section */ 283 | 03580A741B75245400F4AB36 /* Project object */ = { 284 | isa = PBXProject; 285 | attributes = { 286 | LastSwiftUpdateCheck = 0700; 287 | LastUpgradeCheck = 1250; 288 | TargetAttributes = { 289 | 03580A9D1B75250E00F4AB36 = { 290 | CreatedOnToolsVersion = 7.0; 291 | LastSwiftMigration = 1250; 292 | }; 293 | 03580AAA1B75253000F4AB36 = { 294 | CreatedOnToolsVersion = 7.0; 295 | LastSwiftMigration = 1250; 296 | }; 297 | 03B715591B7A481100A15ECF = { 298 | CreatedOnToolsVersion = 7.0; 299 | LastSwiftMigration = 1250; 300 | }; 301 | 03B715681B7A484500A15ECF = { 302 | CreatedOnToolsVersion = 7.0; 303 | LastSwiftMigration = 1250; 304 | }; 305 | }; 306 | }; 307 | buildConfigurationList = 03580A771B75245400F4AB36 /* Build configuration list for PBXProject "Keys" */; 308 | compatibilityVersion = "Xcode 3.2"; 309 | developmentRegion = en; 310 | hasScannedForEncodings = 0; 311 | knownRegions = ( 312 | en, 313 | Base, 314 | ); 315 | mainGroup = 03580A731B75245400F4AB36; 316 | productRefGroup = 03580A801B75246100F4AB36 /* Products */; 317 | projectDirPath = ""; 318 | projectRoot = ""; 319 | targets = ( 320 | 03580A9D1B75250E00F4AB36 /* Keys iOS */, 321 | 03580AAA1B75253000F4AB36 /* Keys macOS */, 322 | 03B715681B7A484500A15ECF /* Tests-iOS */, 323 | 03B715591B7A481100A15ECF /* Tests-macOS */, 324 | ); 325 | }; 326 | /* End PBXProject section */ 327 | 328 | /* Begin PBXResourcesBuildPhase section */ 329 | 03580A9C1B75250E00F4AB36 /* Resources */ = { 330 | isa = PBXResourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | 03580AA91B75253000F4AB36 /* Resources */ = { 337 | isa = PBXResourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 03B715581B7A481100A15ECF /* Resources */ = { 344 | isa = PBXResourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | 037C23B11BD9F4A1001B91D3 /* keys-private.pem in Resources */, 348 | 037C23B31BD9F4A1001B91D3 /* keys-public.pem in Resources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | 03B715671B7A484500A15ECF /* Resources */ = { 353 | isa = PBXResourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 037C23B01BD9F4A1001B91D3 /* keys-private.pem in Resources */, 357 | 037C23B21BD9F4A1001B91D3 /* keys-public.pem in Resources */, 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | /* End PBXResourcesBuildPhase section */ 362 | 363 | /* Begin PBXSourcesBuildPhase section */ 364 | 03580A991B75250E00F4AB36 /* Sources */ = { 365 | isa = PBXSourcesBuildPhase; 366 | buildActionMask = 2147483647; 367 | files = ( 368 | 03B715191B774B5A00A15ECF /* Hash.swift in Sources */, 369 | 03580AC51B75263500F4AB36 /* SymmetricKey.swift in Sources */, 370 | 0343E2D71BDAB18D007C2FD4 /* AsymmetricKeys.swift in Sources */, 371 | 0343E2D51BDA9E04007C2FD4 /* AsymmetricKeys-iOS.swift in Sources */, 372 | 03580AC21B75262B00F4AB36 /* Password.swift in Sources */, 373 | 03580ABF1B75262100F4AB36 /* Keys.swift in Sources */, 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | 03580AA61B75253000F4AB36 /* Sources */ = { 378 | isa = PBXSourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | 03B715211B7A0AD700A15ECF /* Hash.swift in Sources */, 382 | 0343E2D61BDAA279007C2FD4 /* AsymmetricKeys-macOS.swift in Sources */, 383 | 0343E2D81BDAB18E007C2FD4 /* AsymmetricKeys.swift in Sources */, 384 | 03580AC61B75263500F4AB36 /* SymmetricKey.swift in Sources */, 385 | 03580AC31B75262B00F4AB36 /* Password.swift in Sources */, 386 | 03580AC01B75262100F4AB36 /* Keys.swift in Sources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | 03B715561B7A481100A15ECF /* Sources */ = { 391 | isa = PBXSourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | 03B7155D1B7A481100A15ECF /* PasswordTests.swift in Sources */, 395 | 03B715771B7A492600A15ECF /* SymmetricKeyTests.swift in Sources */, 396 | 03B7157A1B7A493800A15ECF /* AsymmetricKeysTests.swift in Sources */, 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | }; 400 | 03B715651B7A484500A15ECF /* Sources */ = { 401 | isa = PBXSourcesBuildPhase; 402 | buildActionMask = 2147483647; 403 | files = ( 404 | 03B715741B7A48DB00A15ECF /* PasswordTests.swift in Sources */, 405 | 03B715761B7A492600A15ECF /* SymmetricKeyTests.swift in Sources */, 406 | 03B715791B7A493800A15ECF /* AsymmetricKeysTests.swift in Sources */, 407 | ); 408 | runOnlyForDeploymentPostprocessing = 0; 409 | }; 410 | /* End PBXSourcesBuildPhase section */ 411 | 412 | /* Begin PBXTargetDependency section */ 413 | 03B715611B7A481100A15ECF /* PBXTargetDependency */ = { 414 | isa = PBXTargetDependency; 415 | target = 03580AAA1B75253000F4AB36 /* Keys macOS */; 416 | targetProxy = 03B715601B7A481100A15ECF /* PBXContainerItemProxy */; 417 | }; 418 | 03B715701B7A484500A15ECF /* PBXTargetDependency */ = { 419 | isa = PBXTargetDependency; 420 | target = 03580A9D1B75250E00F4AB36 /* Keys iOS */; 421 | targetProxy = 03B7156F1B7A484500A15ECF /* PBXContainerItemProxy */; 422 | }; 423 | /* End PBXTargetDependency section */ 424 | 425 | /* Begin XCBuildConfiguration section */ 426 | 03580A781B75245400F4AB36 /* Debug */ = { 427 | isa = XCBuildConfiguration; 428 | buildSettings = { 429 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 430 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 431 | CLANG_WARN_BOOL_CONVERSION = YES; 432 | CLANG_WARN_COMMA = YES; 433 | CLANG_WARN_CONSTANT_CONVERSION = YES; 434 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 435 | CLANG_WARN_EMPTY_BODY = YES; 436 | CLANG_WARN_ENUM_CONVERSION = YES; 437 | CLANG_WARN_INFINITE_RECURSION = YES; 438 | CLANG_WARN_INT_CONVERSION = YES; 439 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 440 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 441 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 442 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 443 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 444 | CLANG_WARN_STRICT_PROTOTYPES = YES; 445 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 446 | CLANG_WARN_UNREACHABLE_CODE = YES; 447 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 448 | ENABLE_STRICT_OBJC_MSGSEND = YES; 449 | ENABLE_TESTABILITY = YES; 450 | GCC_NO_COMMON_BLOCKS = YES; 451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 452 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 454 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 455 | GCC_WARN_UNUSED_FUNCTION = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 458 | MACOSX_DEPLOYMENT_TARGET = 10.9; 459 | ONLY_ACTIVE_ARCH = YES; 460 | }; 461 | name = Debug; 462 | }; 463 | 03580A791B75245400F4AB36 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 467 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 468 | CLANG_WARN_BOOL_CONVERSION = YES; 469 | CLANG_WARN_COMMA = YES; 470 | CLANG_WARN_CONSTANT_CONVERSION = YES; 471 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 472 | CLANG_WARN_EMPTY_BODY = YES; 473 | CLANG_WARN_ENUM_CONVERSION = YES; 474 | CLANG_WARN_INFINITE_RECURSION = YES; 475 | CLANG_WARN_INT_CONVERSION = YES; 476 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 477 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 478 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 479 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 480 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 481 | CLANG_WARN_STRICT_PROTOTYPES = YES; 482 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 483 | CLANG_WARN_UNREACHABLE_CODE = YES; 484 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 485 | ENABLE_STRICT_OBJC_MSGSEND = YES; 486 | GCC_NO_COMMON_BLOCKS = YES; 487 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 488 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 489 | GCC_WARN_UNDECLARED_SELECTOR = YES; 490 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 491 | GCC_WARN_UNUSED_FUNCTION = YES; 492 | GCC_WARN_UNUSED_VARIABLE = YES; 493 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 494 | MACOSX_DEPLOYMENT_TARGET = 10.9; 495 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 496 | }; 497 | name = Release; 498 | }; 499 | 03580AA41B75250E00F4AB36 /* Debug */ = { 500 | isa = XCBuildConfiguration; 501 | buildSettings = { 502 | ALWAYS_SEARCH_USER_PATHS = NO; 503 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 504 | CLANG_CXX_LIBRARY = "libc++"; 505 | CLANG_ENABLE_MODULES = YES; 506 | CLANG_ENABLE_OBJC_ARC = YES; 507 | CLANG_WARN_BOOL_CONVERSION = YES; 508 | CLANG_WARN_CONSTANT_CONVERSION = YES; 509 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 510 | CLANG_WARN_EMPTY_BODY = YES; 511 | CLANG_WARN_ENUM_CONVERSION = YES; 512 | CLANG_WARN_INT_CONVERSION = YES; 513 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 514 | CLANG_WARN_UNREACHABLE_CODE = YES; 515 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 516 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 517 | COPY_PHASE_STRIP = NO; 518 | CURRENT_PROJECT_VERSION = 1; 519 | DEBUG_INFORMATION_FORMAT = dwarf; 520 | DEFINES_MODULE = YES; 521 | DYLIB_COMPATIBILITY_VERSION = 1; 522 | DYLIB_CURRENT_VERSION = 1; 523 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 524 | ENABLE_STRICT_OBJC_MSGSEND = YES; 525 | ENABLE_TESTABILITY = YES; 526 | GCC_C_LANGUAGE_STANDARD = gnu99; 527 | GCC_DYNAMIC_NO_PIC = NO; 528 | GCC_NO_COMMON_BLOCKS = YES; 529 | GCC_OPTIMIZATION_LEVEL = 0; 530 | GCC_PREPROCESSOR_DEFINITIONS = ( 531 | "DEBUG=1", 532 | "$(inherited)", 533 | ); 534 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 535 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 536 | GCC_WARN_UNDECLARED_SELECTOR = YES; 537 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 538 | GCC_WARN_UNUSED_FUNCTION = YES; 539 | GCC_WARN_UNUSED_VARIABLE = YES; 540 | INFOPLIST_FILE = Keys/Info.plist; 541 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 542 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 543 | MTL_ENABLE_DEBUG_INFO = YES; 544 | ONLY_ACTIVE_ARCH = YES; 545 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.keys-ios"; 546 | PRODUCT_NAME = Keys; 547 | SDKROOT = iphoneos; 548 | SKIP_INSTALL = YES; 549 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 550 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 551 | SWIFT_VERSION = 5.0; 552 | TARGETED_DEVICE_FAMILY = "1,2"; 553 | VERSIONING_SYSTEM = "apple-generic"; 554 | VERSION_INFO_PREFIX = ""; 555 | }; 556 | name = Debug; 557 | }; 558 | 03580AA51B75250E00F4AB36 /* Release */ = { 559 | isa = XCBuildConfiguration; 560 | buildSettings = { 561 | ALWAYS_SEARCH_USER_PATHS = NO; 562 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 563 | CLANG_CXX_LIBRARY = "libc++"; 564 | CLANG_ENABLE_MODULES = YES; 565 | CLANG_ENABLE_OBJC_ARC = YES; 566 | CLANG_WARN_BOOL_CONVERSION = YES; 567 | CLANG_WARN_CONSTANT_CONVERSION = YES; 568 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 569 | CLANG_WARN_EMPTY_BODY = YES; 570 | CLANG_WARN_ENUM_CONVERSION = YES; 571 | CLANG_WARN_INT_CONVERSION = YES; 572 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 573 | CLANG_WARN_UNREACHABLE_CODE = YES; 574 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 575 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 576 | COPY_PHASE_STRIP = NO; 577 | CURRENT_PROJECT_VERSION = 1; 578 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 579 | DEFINES_MODULE = YES; 580 | DYLIB_COMPATIBILITY_VERSION = 1; 581 | DYLIB_CURRENT_VERSION = 1; 582 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 583 | ENABLE_NS_ASSERTIONS = NO; 584 | ENABLE_STRICT_OBJC_MSGSEND = YES; 585 | GCC_C_LANGUAGE_STANDARD = gnu99; 586 | GCC_NO_COMMON_BLOCKS = YES; 587 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 588 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 589 | GCC_WARN_UNDECLARED_SELECTOR = YES; 590 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 591 | GCC_WARN_UNUSED_FUNCTION = YES; 592 | GCC_WARN_UNUSED_VARIABLE = YES; 593 | INFOPLIST_FILE = Keys/Info.plist; 594 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 595 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 596 | MTL_ENABLE_DEBUG_INFO = NO; 597 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.keys-ios"; 598 | PRODUCT_NAME = Keys; 599 | SDKROOT = iphoneos; 600 | SKIP_INSTALL = YES; 601 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 602 | SWIFT_VERSION = 5.0; 603 | TARGETED_DEVICE_FAMILY = "1,2"; 604 | VALIDATE_PRODUCT = YES; 605 | VERSIONING_SYSTEM = "apple-generic"; 606 | VERSION_INFO_PREFIX = ""; 607 | }; 608 | name = Release; 609 | }; 610 | 03580AB11B75253000F4AB36 /* Debug */ = { 611 | isa = XCBuildConfiguration; 612 | buildSettings = { 613 | ALWAYS_SEARCH_USER_PATHS = NO; 614 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 615 | CLANG_CXX_LIBRARY = "libc++"; 616 | CLANG_ENABLE_MODULES = YES; 617 | CLANG_ENABLE_OBJC_ARC = YES; 618 | CLANG_WARN_BOOL_CONVERSION = YES; 619 | CLANG_WARN_CONSTANT_CONVERSION = YES; 620 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 621 | CLANG_WARN_EMPTY_BODY = YES; 622 | CLANG_WARN_ENUM_CONVERSION = YES; 623 | CLANG_WARN_INT_CONVERSION = YES; 624 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 625 | CLANG_WARN_UNREACHABLE_CODE = YES; 626 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 627 | COMBINE_HIDPI_IMAGES = YES; 628 | COPY_PHASE_STRIP = NO; 629 | CURRENT_PROJECT_VERSION = 1; 630 | DEBUG_INFORMATION_FORMAT = dwarf; 631 | DEFINES_MODULE = YES; 632 | DYLIB_COMPATIBILITY_VERSION = 1; 633 | DYLIB_CURRENT_VERSION = 1; 634 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 635 | ENABLE_STRICT_OBJC_MSGSEND = YES; 636 | ENABLE_TESTABILITY = YES; 637 | FRAMEWORK_VERSION = A; 638 | GCC_C_LANGUAGE_STANDARD = gnu99; 639 | GCC_DYNAMIC_NO_PIC = NO; 640 | GCC_NO_COMMON_BLOCKS = YES; 641 | GCC_OPTIMIZATION_LEVEL = 0; 642 | GCC_PREPROCESSOR_DEFINITIONS = ( 643 | "DEBUG=1", 644 | "$(inherited)", 645 | ); 646 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 647 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 648 | GCC_WARN_UNDECLARED_SELECTOR = YES; 649 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 650 | GCC_WARN_UNUSED_FUNCTION = YES; 651 | GCC_WARN_UNUSED_VARIABLE = YES; 652 | INFOPLIST_FILE = Keys/Info.plist; 653 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 654 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 655 | MTL_ENABLE_DEBUG_INFO = YES; 656 | ONLY_ACTIVE_ARCH = YES; 657 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.keys-macos"; 658 | PRODUCT_NAME = Keys; 659 | SDKROOT = macosx; 660 | SKIP_INSTALL = YES; 661 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 662 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 663 | SWIFT_VERSION = 5.0; 664 | VERSIONING_SYSTEM = "apple-generic"; 665 | VERSION_INFO_PREFIX = ""; 666 | }; 667 | name = Debug; 668 | }; 669 | 03580AB21B75253000F4AB36 /* Release */ = { 670 | isa = XCBuildConfiguration; 671 | buildSettings = { 672 | ALWAYS_SEARCH_USER_PATHS = NO; 673 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 674 | CLANG_CXX_LIBRARY = "libc++"; 675 | CLANG_ENABLE_MODULES = YES; 676 | CLANG_ENABLE_OBJC_ARC = YES; 677 | CLANG_WARN_BOOL_CONVERSION = YES; 678 | CLANG_WARN_CONSTANT_CONVERSION = YES; 679 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 680 | CLANG_WARN_EMPTY_BODY = YES; 681 | CLANG_WARN_ENUM_CONVERSION = YES; 682 | CLANG_WARN_INT_CONVERSION = YES; 683 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 684 | CLANG_WARN_UNREACHABLE_CODE = YES; 685 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 686 | COMBINE_HIDPI_IMAGES = YES; 687 | COPY_PHASE_STRIP = NO; 688 | CURRENT_PROJECT_VERSION = 1; 689 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 690 | DEFINES_MODULE = YES; 691 | DYLIB_COMPATIBILITY_VERSION = 1; 692 | DYLIB_CURRENT_VERSION = 1; 693 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 694 | ENABLE_NS_ASSERTIONS = NO; 695 | ENABLE_STRICT_OBJC_MSGSEND = YES; 696 | FRAMEWORK_VERSION = A; 697 | GCC_C_LANGUAGE_STANDARD = gnu99; 698 | GCC_NO_COMMON_BLOCKS = YES; 699 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 700 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 701 | GCC_WARN_UNDECLARED_SELECTOR = YES; 702 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 703 | GCC_WARN_UNUSED_FUNCTION = YES; 704 | GCC_WARN_UNUSED_VARIABLE = YES; 705 | INFOPLIST_FILE = Keys/Info.plist; 706 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 707 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 708 | MTL_ENABLE_DEBUG_INFO = NO; 709 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.keys-macos"; 710 | PRODUCT_NAME = Keys; 711 | SDKROOT = macosx; 712 | SKIP_INSTALL = YES; 713 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 714 | SWIFT_VERSION = 5.0; 715 | VERSIONING_SYSTEM = "apple-generic"; 716 | VERSION_INFO_PREFIX = ""; 717 | }; 718 | name = Release; 719 | }; 720 | 03B715631B7A481100A15ECF /* Debug */ = { 721 | isa = XCBuildConfiguration; 722 | buildSettings = { 723 | ALWAYS_SEARCH_USER_PATHS = NO; 724 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 725 | CLANG_CXX_LIBRARY = "libc++"; 726 | CLANG_ENABLE_MODULES = YES; 727 | CLANG_ENABLE_OBJC_ARC = YES; 728 | CLANG_WARN_BOOL_CONVERSION = YES; 729 | CLANG_WARN_CONSTANT_CONVERSION = YES; 730 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 731 | CLANG_WARN_EMPTY_BODY = YES; 732 | CLANG_WARN_ENUM_CONVERSION = YES; 733 | CLANG_WARN_INT_CONVERSION = YES; 734 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 735 | CLANG_WARN_UNREACHABLE_CODE = YES; 736 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 737 | COMBINE_HIDPI_IMAGES = YES; 738 | COPY_PHASE_STRIP = NO; 739 | DEBUG_INFORMATION_FORMAT = dwarf; 740 | ENABLE_STRICT_OBJC_MSGSEND = YES; 741 | ENABLE_TESTABILITY = YES; 742 | GCC_C_LANGUAGE_STANDARD = gnu99; 743 | GCC_DYNAMIC_NO_PIC = NO; 744 | GCC_NO_COMMON_BLOCKS = YES; 745 | GCC_OPTIMIZATION_LEVEL = 0; 746 | GCC_PREPROCESSOR_DEFINITIONS = ( 747 | "DEBUG=1", 748 | "$(inherited)", 749 | ); 750 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 751 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 752 | GCC_WARN_UNDECLARED_SELECTOR = YES; 753 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 754 | GCC_WARN_UNUSED_FUNCTION = YES; 755 | GCC_WARN_UNUSED_VARIABLE = YES; 756 | INFOPLIST_FILE = Tests/Info.plist; 757 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 758 | MACOSX_DEPLOYMENT_TARGET = 10.10; 759 | MTL_ENABLE_DEBUG_INFO = YES; 760 | ONLY_ACTIVE_ARCH = YES; 761 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.Tests-macOS"; 762 | PRODUCT_NAME = "$(TARGET_NAME)"; 763 | SDKROOT = macosx; 764 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 765 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 766 | SWIFT_VERSION = 5.0; 767 | }; 768 | name = Debug; 769 | }; 770 | 03B715641B7A481100A15ECF /* Release */ = { 771 | isa = XCBuildConfiguration; 772 | buildSettings = { 773 | ALWAYS_SEARCH_USER_PATHS = NO; 774 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 775 | CLANG_CXX_LIBRARY = "libc++"; 776 | CLANG_ENABLE_MODULES = YES; 777 | CLANG_ENABLE_OBJC_ARC = YES; 778 | CLANG_WARN_BOOL_CONVERSION = YES; 779 | CLANG_WARN_CONSTANT_CONVERSION = YES; 780 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 781 | CLANG_WARN_EMPTY_BODY = YES; 782 | CLANG_WARN_ENUM_CONVERSION = YES; 783 | CLANG_WARN_INT_CONVERSION = YES; 784 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 785 | CLANG_WARN_UNREACHABLE_CODE = YES; 786 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 787 | COMBINE_HIDPI_IMAGES = YES; 788 | COPY_PHASE_STRIP = NO; 789 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 790 | ENABLE_NS_ASSERTIONS = NO; 791 | ENABLE_STRICT_OBJC_MSGSEND = YES; 792 | GCC_C_LANGUAGE_STANDARD = gnu99; 793 | GCC_NO_COMMON_BLOCKS = YES; 794 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 795 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 796 | GCC_WARN_UNDECLARED_SELECTOR = YES; 797 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 798 | GCC_WARN_UNUSED_FUNCTION = YES; 799 | GCC_WARN_UNUSED_VARIABLE = YES; 800 | INFOPLIST_FILE = Tests/Info.plist; 801 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 802 | MACOSX_DEPLOYMENT_TARGET = 10.10; 803 | MTL_ENABLE_DEBUG_INFO = NO; 804 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.Tests-macOS"; 805 | PRODUCT_NAME = "$(TARGET_NAME)"; 806 | SDKROOT = macosx; 807 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 808 | SWIFT_VERSION = 5.0; 809 | }; 810 | name = Release; 811 | }; 812 | 03B715721B7A484500A15ECF /* Debug */ = { 813 | isa = XCBuildConfiguration; 814 | buildSettings = { 815 | ALWAYS_SEARCH_USER_PATHS = NO; 816 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 817 | CLANG_CXX_LIBRARY = "libc++"; 818 | CLANG_ENABLE_MODULES = YES; 819 | CLANG_ENABLE_OBJC_ARC = YES; 820 | CLANG_WARN_BOOL_CONVERSION = YES; 821 | CLANG_WARN_CONSTANT_CONVERSION = YES; 822 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 823 | CLANG_WARN_EMPTY_BODY = YES; 824 | CLANG_WARN_ENUM_CONVERSION = YES; 825 | CLANG_WARN_INT_CONVERSION = YES; 826 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 827 | CLANG_WARN_UNREACHABLE_CODE = YES; 828 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 829 | COPY_PHASE_STRIP = NO; 830 | DEBUG_INFORMATION_FORMAT = dwarf; 831 | ENABLE_STRICT_OBJC_MSGSEND = YES; 832 | ENABLE_TESTABILITY = YES; 833 | GCC_C_LANGUAGE_STANDARD = gnu99; 834 | GCC_DYNAMIC_NO_PIC = NO; 835 | GCC_NO_COMMON_BLOCKS = YES; 836 | GCC_OPTIMIZATION_LEVEL = 0; 837 | GCC_PREPROCESSOR_DEFINITIONS = ( 838 | "DEBUG=1", 839 | "$(inherited)", 840 | ); 841 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 842 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 843 | GCC_WARN_UNDECLARED_SELECTOR = YES; 844 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 845 | GCC_WARN_UNUSED_FUNCTION = YES; 846 | GCC_WARN_UNUSED_VARIABLE = YES; 847 | INFOPLIST_FILE = Tests/Info.plist; 848 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 849 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 850 | MTL_ENABLE_DEBUG_INFO = YES; 851 | ONLY_ACTIVE_ARCH = YES; 852 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.Tests-iOS"; 853 | PRODUCT_NAME = "$(TARGET_NAME)"; 854 | SDKROOT = iphoneos; 855 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 856 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 857 | SWIFT_VERSION = 5.0; 858 | }; 859 | name = Debug; 860 | }; 861 | 03B715731B7A484500A15ECF /* Release */ = { 862 | isa = XCBuildConfiguration; 863 | buildSettings = { 864 | ALWAYS_SEARCH_USER_PATHS = NO; 865 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 866 | CLANG_CXX_LIBRARY = "libc++"; 867 | CLANG_ENABLE_MODULES = YES; 868 | CLANG_ENABLE_OBJC_ARC = YES; 869 | CLANG_WARN_BOOL_CONVERSION = YES; 870 | CLANG_WARN_CONSTANT_CONVERSION = YES; 871 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 872 | CLANG_WARN_EMPTY_BODY = YES; 873 | CLANG_WARN_ENUM_CONVERSION = YES; 874 | CLANG_WARN_INT_CONVERSION = YES; 875 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 876 | CLANG_WARN_UNREACHABLE_CODE = YES; 877 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 878 | COPY_PHASE_STRIP = NO; 879 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 880 | ENABLE_NS_ASSERTIONS = NO; 881 | ENABLE_STRICT_OBJC_MSGSEND = YES; 882 | GCC_C_LANGUAGE_STANDARD = gnu99; 883 | GCC_NO_COMMON_BLOCKS = YES; 884 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 885 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 886 | GCC_WARN_UNDECLARED_SELECTOR = YES; 887 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 888 | GCC_WARN_UNUSED_FUNCTION = YES; 889 | GCC_WARN_UNUSED_VARIABLE = YES; 890 | INFOPLIST_FILE = Tests/Info.plist; 891 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 892 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 893 | MTL_ENABLE_DEBUG_INFO = NO; 894 | PRODUCT_BUNDLE_IDENTIFIER = "com.zhengxingzhi.Tests-iOS"; 895 | PRODUCT_NAME = "$(TARGET_NAME)"; 896 | SDKROOT = iphoneos; 897 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 898 | SWIFT_VERSION = 5.0; 899 | VALIDATE_PRODUCT = YES; 900 | }; 901 | name = Release; 902 | }; 903 | /* End XCBuildConfiguration section */ 904 | 905 | /* Begin XCConfigurationList section */ 906 | 03580A771B75245400F4AB36 /* Build configuration list for PBXProject "Keys" */ = { 907 | isa = XCConfigurationList; 908 | buildConfigurations = ( 909 | 03580A781B75245400F4AB36 /* Debug */, 910 | 03580A791B75245400F4AB36 /* Release */, 911 | ); 912 | defaultConfigurationIsVisible = 0; 913 | defaultConfigurationName = Release; 914 | }; 915 | 03580AA31B75250E00F4AB36 /* Build configuration list for PBXNativeTarget "Keys iOS" */ = { 916 | isa = XCConfigurationList; 917 | buildConfigurations = ( 918 | 03580AA41B75250E00F4AB36 /* Debug */, 919 | 03580AA51B75250E00F4AB36 /* Release */, 920 | ); 921 | defaultConfigurationIsVisible = 0; 922 | defaultConfigurationName = Release; 923 | }; 924 | 03580AB01B75253000F4AB36 /* Build configuration list for PBXNativeTarget "Keys macOS" */ = { 925 | isa = XCConfigurationList; 926 | buildConfigurations = ( 927 | 03580AB11B75253000F4AB36 /* Debug */, 928 | 03580AB21B75253000F4AB36 /* Release */, 929 | ); 930 | defaultConfigurationIsVisible = 0; 931 | defaultConfigurationName = Release; 932 | }; 933 | 03B715621B7A481100A15ECF /* Build configuration list for PBXNativeTarget "Tests-macOS" */ = { 934 | isa = XCConfigurationList; 935 | buildConfigurations = ( 936 | 03B715631B7A481100A15ECF /* Debug */, 937 | 03B715641B7A481100A15ECF /* Release */, 938 | ); 939 | defaultConfigurationIsVisible = 0; 940 | defaultConfigurationName = Release; 941 | }; 942 | 03B715711B7A484500A15ECF /* Build configuration list for PBXNativeTarget "Tests-iOS" */ = { 943 | isa = XCConfigurationList; 944 | buildConfigurations = ( 945 | 03B715721B7A484500A15ECF /* Debug */, 946 | 03B715731B7A484500A15ECF /* Release */, 947 | ); 948 | defaultConfigurationIsVisible = 0; 949 | defaultConfigurationName = Release; 950 | }; 951 | /* End XCConfigurationList section */ 952 | }; 953 | rootObject = 03580A741B75245400F4AB36 /* Project object */; 954 | } 955 | --------------------------------------------------------------------------------