├── .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 | [](https://github.com/remaerd/Keys)
2 | [](https://github.com/remaerd/Keys/releases)
3 | [](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 |
--------------------------------------------------------------------------------