react-native-security-suite 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -2
- package/README.md +40 -3
- package/android/build.gradle +85 -43
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +1 -3
- package/android/src/main/AndroidManifestDeprecated.xml +3 -0
- package/android/src/main/java/com/securitysuite/SecuritySuiteModule.java +202 -0
- package/android/src/main/java/com/securitysuite/SecuritySuitePackage.java +28 -0
- package/android/src/main/java/com/securitysuite/StorageEncryption.java +52 -0
- package/ios/DataHashingMethods.swift +196 -0
- package/ios/SecuritySuite-Bridging-Header.h +1 -0
- package/ios/SecuritySuite.mm +26 -0
- package/ios/SecuritySuite.swift +129 -0
- package/ios/SecuritySuite.xcodeproj/project.pbxproj +13 -17
- package/ios/SecuritySuite.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
- package/ios/SecuritySuite.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/SecuritySuite.xcodeproj/project.xcworkspace/xcuserdata/mohammadnavabi.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/SecuritySuite.xcodeproj/xcuserdata/mohammadnavabi.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/ios/StorageEncryption.swift +81 -0
- package/lib/commonjs/helpers.js +16 -0
- package/lib/commonjs/helpers.js.map +1 -0
- package/lib/commonjs/index.js +158 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/helpers.js +9 -0
- package/lib/module/helpers.js.map +1 -0
- package/lib/module/index.js +147 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/helpers.d.ts +2 -0
- package/lib/typescript/helpers.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +20 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/package.json +54 -33
- package/react-native-security-suite.podspec +18 -2
- package/src/helpers.ts +8 -0
- package/src/index.tsx +203 -3
- package/android/src/main/java/com/reactnativesecuritysuite/SecuritySuiteModule.java +0 -38
- package/android/src/main/java/com/reactnativesecuritysuite/SecuritySuitePackage.java +0 -28
- package/ios/SecuritySuite.m +0 -12
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Data+HashingMethods.swift
|
|
3
|
+
//
|
|
4
|
+
// Created by Amir Sepehrom on 5/31/21.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
import Foundation
|
|
8
|
+
import Security
|
|
9
|
+
import CommonCrypto
|
|
10
|
+
|
|
11
|
+
extension SecKey {
|
|
12
|
+
|
|
13
|
+
fileprivate subscript(attribute attr: CFString) -> Any? {
|
|
14
|
+
let attributes = SecKeyCopyAttributes(self) as? [CFString: Any]
|
|
15
|
+
return attributes?[attr]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Returns key length.
|
|
19
|
+
public var keySize: Int {
|
|
20
|
+
// swiftlint: disable force_cast
|
|
21
|
+
return self[attribute: kSecAttrKeySizeInBits] as! Int
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Returns encryption method of key.
|
|
25
|
+
public var type: KeyType {
|
|
26
|
+
// swiftlint: disable force_cast
|
|
27
|
+
let type = self[attribute: kSecAttrType] as! CFString
|
|
28
|
+
return KeyType(rawValue: type)!
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Public ASN1 header appropriate for current key.
|
|
32
|
+
fileprivate func asn1Header() throws -> Data {
|
|
33
|
+
return try type.asn1Header(keySize: keySize)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Exporable key data with ASN1 header.
|
|
37
|
+
public func bytes() throws -> Data {
|
|
38
|
+
return try asn1Header() + rawBytes()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Raw bytes for key that generated by Security framework.
|
|
42
|
+
public func rawBytes() throws -> Data {
|
|
43
|
+
var error: Unmanaged<CFError>?
|
|
44
|
+
|
|
45
|
+
guard let keyData = SecKeyCopyExternalRepresentation(self, &error) as Data? else {
|
|
46
|
+
throw error?.takeRetainedValue() ?? CryptographyError.invalidKey
|
|
47
|
+
}
|
|
48
|
+
return keyData
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Encryption method
|
|
52
|
+
public enum KeyType: RawRepresentable {
|
|
53
|
+
/// Eliptic curve
|
|
54
|
+
case ec
|
|
55
|
+
/// RSA
|
|
56
|
+
case rsa
|
|
57
|
+
|
|
58
|
+
/// Initilize from kSecAttrKeyType string constant.
|
|
59
|
+
public init?(rawValue: CFString) {
|
|
60
|
+
switch rawValue {
|
|
61
|
+
case kSecAttrKeyTypeEC, kSecAttrKeyTypeECSECPrimeRandom:
|
|
62
|
+
self = .ec
|
|
63
|
+
case kSecAttrKeyTypeRSA:
|
|
64
|
+
self = .rsa
|
|
65
|
+
default:
|
|
66
|
+
return nil
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// kSecAttrKeyType counterpart of option.
|
|
71
|
+
public var rawValue: CFString {
|
|
72
|
+
switch self {
|
|
73
|
+
case .ec:
|
|
74
|
+
return kSecAttrKeyTypeECSECPrimeRandom
|
|
75
|
+
case .rsa:
|
|
76
|
+
return kSecAttrKeyTypeRSA
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// ASN1 headers for encrypting public keys.
|
|
81
|
+
public struct ASN1 {
|
|
82
|
+
public static let rsa2048 = Data(base64Encoded: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A")!
|
|
83
|
+
public static let rsa4096 = Data(base64Encoded: "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A")!
|
|
84
|
+
public static let ec256 = Data(base64Encoded: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA=")!
|
|
85
|
+
public static let ec384 = Data(base64Encoded: "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgA=")!
|
|
86
|
+
public static let ec521 = Data(base64Encoded: "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAA==")!
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func asn1Header(keySize: Int) throws -> Data {
|
|
90
|
+
switch (self, keySize) {
|
|
91
|
+
case (.ec, 256):
|
|
92
|
+
return ASN1.ec256
|
|
93
|
+
case (.ec, 384):
|
|
94
|
+
return ASN1.ec384
|
|
95
|
+
case (.ec, 521):
|
|
96
|
+
return ASN1.ec521
|
|
97
|
+
case (.rsa, 2048):
|
|
98
|
+
return ASN1.rsa2048
|
|
99
|
+
case (.rsa, 4096):
|
|
100
|
+
return ASN1.rsa4096
|
|
101
|
+
default:
|
|
102
|
+
throw CryptographyError.unsupported
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public enum CryptographyError: Error {
|
|
109
|
+
/// Key data is not valid or not conform to expected type and length.
|
|
110
|
+
case invalidKey
|
|
111
|
+
/// Encryption failed.
|
|
112
|
+
case failedEncryption
|
|
113
|
+
/// Decryption failed.
|
|
114
|
+
case failedDecryption
|
|
115
|
+
/// Data that passed to encrypt/decrypt is empty.
|
|
116
|
+
case emptyData
|
|
117
|
+
/// Encrypted data is not valid or encrypted with another key type.
|
|
118
|
+
case invalidData
|
|
119
|
+
/// Encryption/Decryption method is not supported.
|
|
120
|
+
case unsupported
|
|
121
|
+
|
|
122
|
+
// Enclave
|
|
123
|
+
/// Private key is not exist on the device enclave.
|
|
124
|
+
case keyNotFound
|
|
125
|
+
/// Operation with private key which saved in enclave is not posssible.
|
|
126
|
+
case notAllowed
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public enum Digest: String {
|
|
130
|
+
case md5 = "MD5"
|
|
131
|
+
case sha1 = "SHA1"
|
|
132
|
+
case sha256 = "SHA256"
|
|
133
|
+
case sha384 = "SHA384"
|
|
134
|
+
case sha512 = "SHA512"
|
|
135
|
+
|
|
136
|
+
public var length: Int {
|
|
137
|
+
switch self {
|
|
138
|
+
case .md5:
|
|
139
|
+
return Int(CC_MD5_DIGEST_LENGTH)
|
|
140
|
+
case .sha1:
|
|
141
|
+
return Int(CC_SHA1_DIGEST_LENGTH)
|
|
142
|
+
case .sha256:
|
|
143
|
+
return Int(CC_SHA256_DIGEST_LENGTH)
|
|
144
|
+
case .sha384:
|
|
145
|
+
return Int(CC_SHA384_DIGEST_LENGTH)
|
|
146
|
+
case .sha512:
|
|
147
|
+
return Int(CC_SHA512_DIGEST_LENGTH)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public var hmacAlgorithm: CCHmacAlgorithm {
|
|
152
|
+
switch self {
|
|
153
|
+
case .md5:
|
|
154
|
+
return CCHmacAlgorithm(kCCHmacAlgMD5)
|
|
155
|
+
case .sha1:
|
|
156
|
+
return CCHmacAlgorithm(kCCHmacAlgSHA1)
|
|
157
|
+
case .sha256:
|
|
158
|
+
return CCHmacAlgorithm(kCCHmacAlgSHA256)
|
|
159
|
+
case .sha384:
|
|
160
|
+
return CCHmacAlgorithm(kCCHmacAlgSHA384)
|
|
161
|
+
case .sha512:
|
|
162
|
+
return CCHmacAlgorithm(kCCHmacAlgSHA512)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
extension Data {
|
|
168
|
+
/**
|
|
169
|
+
Calculates hash digest of data.
|
|
170
|
+
|
|
171
|
+
- Parameter digest: digest type. Currently only SHA is supported.
|
|
172
|
+
- Returns: A data object with length equal to digest length.
|
|
173
|
+
*/
|
|
174
|
+
public func hash(digest: Digest) -> Data {
|
|
175
|
+
guard !isEmpty else { return Data() }
|
|
176
|
+
var result = [UInt8](repeating: 0, count: digest.length)
|
|
177
|
+
self.withUnsafeBytes { (buf: UnsafeRawBufferPointer) -> Void in
|
|
178
|
+
let ptr = buf.baseAddress!
|
|
179
|
+
let dataLen = CC_LONG(buf.count)
|
|
180
|
+
switch digest {
|
|
181
|
+
case .md5:
|
|
182
|
+
CC_MD5(ptr, dataLen, &result)
|
|
183
|
+
case .sha1:
|
|
184
|
+
CC_SHA1(ptr, dataLen, &result)
|
|
185
|
+
case .sha256:
|
|
186
|
+
CC_SHA256(ptr, dataLen, &result)
|
|
187
|
+
case .sha384:
|
|
188
|
+
CC_SHA384(ptr, dataLen, &result)
|
|
189
|
+
case .sha512:
|
|
190
|
+
CC_SHA512(ptr, dataLen, &result)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return Data(result)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_MODULE(SecuritySuite, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(getPublicKey:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
6
|
+
|
|
7
|
+
RCT_EXTERN_METHOD(getSharedKey:(NSString)serverPK withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
8
|
+
|
|
9
|
+
RCT_EXTERN_METHOD(encrypt:(NSString)input withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
10
|
+
|
|
11
|
+
RCT_EXTERN_METHOD(decrypt:(NSString)input withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
12
|
+
|
|
13
|
+
RCT_EXTERN_METHOD(getDeviceId:(RCTResponseSenderBlock)callback)
|
|
14
|
+
|
|
15
|
+
RCT_EXTERN_METHOD(storageEncrypt:(NSString)input withSecretKey:(NSString*)secretKey withHardEncryption:(BOOL)hardEncryption withCallback:(RCTResponseSenderBlock)callback)
|
|
16
|
+
|
|
17
|
+
RCT_EXTERN_METHOD(storageDecrypt:(NSString)input withSecretKey:(NSString*)secretKey withHardEncryption:(BOOL)hardEncryption withCallback:(RCTResponseSenderBlock)callback)
|
|
18
|
+
|
|
19
|
+
RCT_EXTERN_METHOD(deviceHasSecurityRisk:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
20
|
+
|
|
21
|
+
+ (BOOL)requiresMainQueueSetup
|
|
22
|
+
{
|
|
23
|
+
return NO;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@end
|
package/ios/SecuritySuite.swift
CHANGED
|
@@ -1,7 +1,128 @@
|
|
|
1
1
|
import IOSSecuritySuite
|
|
2
|
+
import Foundation
|
|
3
|
+
import CryptoKit
|
|
4
|
+
import SwiftUI
|
|
2
5
|
|
|
6
|
+
@available(iOS 13.0, *)
|
|
3
7
|
@objc(SecuritySuite)
|
|
4
8
|
class SecuritySuite: NSObject {
|
|
9
|
+
var privateKey: String!,
|
|
10
|
+
publicKey: String!,
|
|
11
|
+
sharedKey: String!,
|
|
12
|
+
keyData: Data!
|
|
13
|
+
|
|
14
|
+
@objc(getPublicKey:withRejecter:)
|
|
15
|
+
func getPublicKey(resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
16
|
+
do {
|
|
17
|
+
privateKey = P256.KeyAgreement.PrivateKey().rawRepresentation.base64EncodedString()
|
|
18
|
+
keyData = Data(base64Encoded: privateKey as! String)!
|
|
19
|
+
publicKey = try? (ASN1.ec256 + [0x04] + P256.KeyAgreement.PrivateKey(rawRepresentation: keyData).publicKey.rawRepresentation).base64EncodedString()
|
|
20
|
+
|
|
21
|
+
resolve(publicKey)
|
|
22
|
+
} catch {
|
|
23
|
+
reject("error", "GET_PUBLIC_KEY_ERROR", nil)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@objc(getSharedKey:withResolver:withRejecter:)
|
|
28
|
+
func getSharedKey(serverPK: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
29
|
+
do {
|
|
30
|
+
print("privateKey", privateKey)
|
|
31
|
+
guard let serverPublicKeyData = Data(base64Encoded: serverPK as String),
|
|
32
|
+
let privateKeyData = Data(base64Encoded: privateKey as String) else { return }
|
|
33
|
+
|
|
34
|
+
sharedKey = try? P256.KeyAgreement.PrivateKey(rawRepresentation: privateKeyData).sharedSecretFromKeyAgreement(with: .init(rawRepresentation: serverPublicKeyData.dropFirst(ASN1.ec256.count + 1)))
|
|
35
|
+
.withUnsafeBytes({ Data(buffer: $0.bindMemory(to: UInt8.self)) })
|
|
36
|
+
.base64EncodedString()
|
|
37
|
+
|
|
38
|
+
resolve(sharedKey)
|
|
39
|
+
} catch {
|
|
40
|
+
reject("error", "GET_SHARED_KEY_ERROR", nil)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@objc(encrypt:withResolver:withRejecter:)
|
|
45
|
+
func encrypt(input: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
46
|
+
do {
|
|
47
|
+
guard let keyData = Data(base64Encoded: sharedKey) else {
|
|
48
|
+
reject("error", "DECRYPT_SHARED_KEY_ERROR", nil)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
let data = Data((input as String).utf8)
|
|
52
|
+
if keyData == nil {
|
|
53
|
+
reject("error", "keyData is null", nil)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
let key = SymmetricKey(data: keyData)
|
|
57
|
+
let output = try? AES.GCM.seal(data, using: key).combined?.base64EncodedString()
|
|
58
|
+
resolve(output)
|
|
59
|
+
} catch {
|
|
60
|
+
reject("error", "ENCRYPT_ERROR", nil)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@objc(decrypt:withResolver:withRejecter:)
|
|
65
|
+
func decrypt(input: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
66
|
+
do {
|
|
67
|
+
guard let keyData = Data(base64Encoded: sharedKey) else {
|
|
68
|
+
reject("error", "DECRYPT_SHARED_KEY_ERROR", nil)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
guard let data = Data(base64Encoded: "\(input)") else {
|
|
72
|
+
reject("error", "INPUT_ERROR", nil)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
let key = SymmetricKey(data: keyData)
|
|
76
|
+
let output = ( try? AES.GCM.open(.init(combined: data), using: key)).map({String(decoding: $0, as: UTF8.self)})
|
|
77
|
+
|
|
78
|
+
resolve(output)
|
|
79
|
+
} catch {
|
|
80
|
+
reject("error", "DECRYPT_ERROR", nil)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@objc(storageEncrypt:withSecretKey:withHardEncryption:withCallback:)
|
|
85
|
+
func storageEncrypt(input: NSString, secretKey: NSString, hardEncryption: Bool, callback: RCTResponseSenderBlock) -> Void {
|
|
86
|
+
do {
|
|
87
|
+
var encryptionKey = getDeviceId();
|
|
88
|
+
if secretKey != nil {
|
|
89
|
+
encryptionKey = secretKey as String;
|
|
90
|
+
}
|
|
91
|
+
let storageEncryption: StorageEncryption = StorageEncryption()
|
|
92
|
+
let encrypted = try? storageEncryption.encrypt(plain: "\(input)", encryptionKey: encryptionKey, hardEncryption: hardEncryption)
|
|
93
|
+
callback([encrypted, NSNull()])
|
|
94
|
+
} catch {
|
|
95
|
+
callback([NSNull(), "SOFT_DECRYPT_ERROR"])
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@objc(storageDecrypt:withSecretKey:withHardEncryption:withCallback:)
|
|
100
|
+
func storageDecrypt(input: NSString, secretKey: NSString, hardEncryption: Bool, callback: RCTResponseSenderBlock) -> Void {
|
|
101
|
+
do {
|
|
102
|
+
var encryptionKey = getDeviceId()
|
|
103
|
+
if secretKey != nil {
|
|
104
|
+
encryptionKey = secretKey as String;
|
|
105
|
+
}
|
|
106
|
+
let storageEncryption: StorageEncryption = StorageEncryption()
|
|
107
|
+
let decrypted = try? storageEncryption.decrypt(decoded: "\(input)", encryptionKey: encryptionKey, hardEncryption: hardEncryption)
|
|
108
|
+
callback([decrypted, NSNull()])
|
|
109
|
+
} catch {
|
|
110
|
+
callback([NSNull(), "SOFT_DECRYPT_ERROR"])
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@objc(getDeviceId:)
|
|
115
|
+
func getDeviceId(callback: RCTResponseSenderBlock) -> Void {
|
|
116
|
+
do {
|
|
117
|
+
callback([getDeviceId(), NSNull()]);
|
|
118
|
+
} catch {
|
|
119
|
+
callback([NSNull(), "GET_DEVICE_ID_ERROR"]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
func getDeviceId() -> String {
|
|
124
|
+
return UIDevice.current.identifierForVendor!.uuidString.replacingOccurrences(of: "-", with: "", options: [], range: nil)
|
|
125
|
+
}
|
|
5
126
|
|
|
6
127
|
@objc(deviceHasSecurityRisk:withRejecter:)
|
|
7
128
|
func deviceHasSecurityRisk(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
|
|
@@ -13,3 +134,11 @@ class SecuritySuite: NSObject {
|
|
|
13
134
|
}
|
|
14
135
|
}
|
|
15
136
|
}
|
|
137
|
+
|
|
138
|
+
struct ASN1 {
|
|
139
|
+
static let rsa2048 = Data(base64Encoded: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A")!
|
|
140
|
+
static let rsa4096 = Data(base64Encoded: "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A")!
|
|
141
|
+
static let ec256 = Data(base64Encoded: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA=")!
|
|
142
|
+
static let ec384 = Data(base64Encoded: "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgA=")!
|
|
143
|
+
static let ec521 = Data(base64Encoded: "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQ=")!
|
|
144
|
+
}
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
objects = {
|
|
8
8
|
|
|
9
9
|
/* Begin PBXBuildFile section */
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
F4FF95D7245B92E800C19C63 /*
|
|
13
|
-
|
|
10
|
+
48C650222A751374001FA3B0 /* StorageEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48C650202A751374001FA3B0 /* StorageEncryption.swift */; };
|
|
11
|
+
48C650232A751374001FA3B0 /* DataHashingMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48C650212A751374001FA3B0 /* DataHashingMethods.swift */; };
|
|
12
|
+
F4FF95D7245B92E800C19C63 /* SecuritySuite.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* SecuritySuite.swift */; };
|
|
14
13
|
/* End PBXBuildFile section */
|
|
15
14
|
|
|
16
15
|
/* Begin PBXCopyFilesBuildPhase section */
|
|
@@ -27,11 +26,11 @@
|
|
|
27
26
|
|
|
28
27
|
/* Begin PBXFileReference section */
|
|
29
28
|
134814201AA4EA6300B7C361 /* libSecuritySuite.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecuritySuite.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
48C650202A751374001FA3B0 /* StorageEncryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageEncryption.swift; sourceTree = "<group>"; };
|
|
30
|
+
48C650212A751374001FA3B0 /* DataHashingMethods.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataHashingMethods.swift; sourceTree = "<group>"; };
|
|
31
|
+
B3E7B5891CC2AC0600A0062D /* SecuritySuite.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecuritySuite.mm; sourceTree = "<group>"; };
|
|
32
32
|
F4FF95D5245B92E700C19C63 /* SecuritySuite-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SecuritySuite-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
33
33
|
F4FF95D6245B92E800C19C63 /* SecuritySuite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecuritySuite.swift; sourceTree = "<group>"; };
|
|
34
|
-
|
|
35
34
|
/* End PBXFileReference section */
|
|
36
35
|
|
|
37
36
|
/* Begin PBXFrameworksBuildPhase section */
|
|
@@ -56,11 +55,11 @@
|
|
|
56
55
|
58B511D21A9E6C8500147676 = {
|
|
57
56
|
isa = PBXGroup;
|
|
58
57
|
children = (
|
|
59
|
-
|
|
60
58
|
F4FF95D6245B92E800C19C63 /* SecuritySuite.swift */,
|
|
61
|
-
B3E7B5891CC2AC0600A0062D /* SecuritySuite.
|
|
59
|
+
B3E7B5891CC2AC0600A0062D /* SecuritySuite.mm */,
|
|
62
60
|
F4FF95D5245B92E700C19C63 /* SecuritySuite-Bridging-Header.h */,
|
|
63
|
-
|
|
61
|
+
48C650212A751374001FA3B0 /* DataHashingMethods.swift */,
|
|
62
|
+
48C650202A751374001FA3B0 /* StorageEncryption.swift */,
|
|
64
63
|
134814211AA4EA7D00B7C361 /* Products */,
|
|
65
64
|
);
|
|
66
65
|
sourceTree = "<group>";
|
|
@@ -122,10 +121,9 @@
|
|
|
122
121
|
isa = PBXSourcesBuildPhase;
|
|
123
122
|
buildActionMask = 2147483647;
|
|
124
123
|
files = (
|
|
125
|
-
|
|
124
|
+
48C650232A751374001FA3B0 /* DataHashingMethods.swift in Sources */,
|
|
125
|
+
48C650222A751374001FA3B0 /* StorageEncryption.swift in Sources */,
|
|
126
126
|
F4FF95D7245B92E800C19C63 /* SecuritySuite.swift in Sources */,
|
|
127
|
-
B3E7B58A1CC2AC0600A0062D /* SecuritySuite.m in Sources */,
|
|
128
|
-
|
|
129
127
|
);
|
|
130
128
|
runOnlyForDeploymentPostprocessing = 0;
|
|
131
129
|
};
|
|
@@ -160,6 +158,7 @@
|
|
|
160
158
|
COPY_PHASE_STRIP = NO;
|
|
161
159
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
162
160
|
ENABLE_TESTABILITY = YES;
|
|
161
|
+
"EXCLUDED_ARCHS[sdk=*]" = arm64;
|
|
163
162
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
164
163
|
GCC_DYNAMIC_NO_PIC = NO;
|
|
165
164
|
GCC_NO_COMMON_BLOCKS = YES;
|
|
@@ -210,6 +209,7 @@
|
|
|
210
209
|
COPY_PHASE_STRIP = YES;
|
|
211
210
|
ENABLE_NS_ASSERTIONS = NO;
|
|
212
211
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
212
|
+
"EXCLUDED_ARCHS[sdk=*]" = arm64;
|
|
213
213
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
214
214
|
GCC_NO_COMMON_BLOCKS = YES;
|
|
215
215
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
@@ -238,11 +238,9 @@
|
|
|
238
238
|
OTHER_LDFLAGS = "-ObjC";
|
|
239
239
|
PRODUCT_NAME = SecuritySuite;
|
|
240
240
|
SKIP_INSTALL = YES;
|
|
241
|
-
|
|
242
241
|
SWIFT_OBJC_BRIDGING_HEADER = "SecuritySuite-Bridging-Header.h";
|
|
243
242
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
244
243
|
SWIFT_VERSION = 5.0;
|
|
245
|
-
|
|
246
244
|
};
|
|
247
245
|
name = Debug;
|
|
248
246
|
};
|
|
@@ -259,10 +257,8 @@
|
|
|
259
257
|
OTHER_LDFLAGS = "-ObjC";
|
|
260
258
|
PRODUCT_NAME = SecuritySuite;
|
|
261
259
|
SKIP_INSTALL = YES;
|
|
262
|
-
|
|
263
260
|
SWIFT_OBJC_BRIDGING_HEADER = "SecuritySuite-Bridging-Header.h";
|
|
264
261
|
SWIFT_VERSION = 5.0;
|
|
265
|
-
|
|
266
262
|
};
|
|
267
263
|
name = Release;
|
|
268
264
|
};
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>SchemeUserState</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>SecuritySuite.xcscheme_^#shared#^_</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>orderHint</key>
|
|
10
|
+
<integer>0</integer>
|
|
11
|
+
</dict>
|
|
12
|
+
</dict>
|
|
13
|
+
</dict>
|
|
14
|
+
</plist>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SoftEncryption.swift
|
|
3
|
+
// EncryptionSecurity
|
|
4
|
+
//
|
|
5
|
+
// Created by Mohammad on 5/9/1401 AP.
|
|
6
|
+
// Copyright © 1401 AP Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import CryptoKit
|
|
11
|
+
|
|
12
|
+
@available(iOS 13.0, *)
|
|
13
|
+
class StorageEncryption {
|
|
14
|
+
let nonce = try! AES.GCM.Nonce(data: Data(base64Encoded: "bj1nixTVoYpSvpdA")!)
|
|
15
|
+
|
|
16
|
+
func encrypt(plain: String, encryptionKey: String, hardEncryption: Bool) throws -> String {
|
|
17
|
+
do {
|
|
18
|
+
guard let encryptionKeyData = Data(base64Encoded: encryptionKey) else {
|
|
19
|
+
return "Could not decode encryptionKey text: \(encryptionKey)"
|
|
20
|
+
}
|
|
21
|
+
guard let plainData = plain.data(using: .utf8) else {
|
|
22
|
+
return "Could not decode plain text: \(plain)"
|
|
23
|
+
}
|
|
24
|
+
let symmetricKey = SymmetricKey(data: encryptionKeyData)
|
|
25
|
+
var encrypted = try AES.GCM.seal(plainData, using: symmetricKey, nonce: nonce, authenticating: ASN1.ec256)
|
|
26
|
+
if (hardEncryption) {
|
|
27
|
+
encrypted = try AES.GCM.seal(plainData, using: symmetricKey)
|
|
28
|
+
}
|
|
29
|
+
return encrypted.combined!.base64EncodedString()
|
|
30
|
+
} catch let error {
|
|
31
|
+
return "Error encrypting message: \(error.localizedDescription)"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func decrypt(decoded: String, encryptionKey: String, hardEncryption: Bool) throws -> String {
|
|
36
|
+
do {
|
|
37
|
+
guard let encryptionKeyData = Data(base64Encoded: encryptionKey) else {
|
|
38
|
+
return "Could not decode encryption key: \(encryptionKey)"
|
|
39
|
+
}
|
|
40
|
+
guard let decodedData = Data(base64Encoded: decoded) else {
|
|
41
|
+
return "Could not decode decoded text: \(decoded)"
|
|
42
|
+
}
|
|
43
|
+
let symmetricKey = SymmetricKey(data: encryptionKeyData)
|
|
44
|
+
if (hardEncryption) {
|
|
45
|
+
let sealedBoxToOpen = try AES.GCM.SealedBox(combined: decodedData)
|
|
46
|
+
let decrypted = try AES.GCM.open(sealedBoxToOpen, using: symmetricKey)
|
|
47
|
+
return String(data: decrypted, encoding: .utf8)!
|
|
48
|
+
} else {
|
|
49
|
+
let sealedBoxRestored = try AES.GCM.SealedBox(combined: decodedData)
|
|
50
|
+
let decrypted = try AES.GCM.open(sealedBoxRestored, using: symmetricKey, authenticating: ASN1.ec256)
|
|
51
|
+
return String(data: decrypted, encoding: .utf8)!
|
|
52
|
+
}
|
|
53
|
+
} catch let error {
|
|
54
|
+
return "Error decrypting message: \(error.localizedDescription)"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public extension Data {
|
|
60
|
+
init?(hexString: String) {
|
|
61
|
+
let len = hexString.count / 2
|
|
62
|
+
var data = Data(capacity: len)
|
|
63
|
+
var i = hexString.startIndex
|
|
64
|
+
for _ in 0..<len {
|
|
65
|
+
let j = hexString.index(i, offsetBy: 2)
|
|
66
|
+
let bytes = hexString[i..<j]
|
|
67
|
+
if var num = UInt8(bytes, radix: 16) {
|
|
68
|
+
data.append(&num, count: 1)
|
|
69
|
+
} else {
|
|
70
|
+
return nil
|
|
71
|
+
}
|
|
72
|
+
i = j
|
|
73
|
+
}
|
|
74
|
+
self = data
|
|
75
|
+
}
|
|
76
|
+
/// Hexadecimal string representation of `Data` object.
|
|
77
|
+
var hexadecimal: String {
|
|
78
|
+
return map { String(format: "%02x", $0) }
|
|
79
|
+
.joined()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isJsonString = void 0;
|
|
7
|
+
const isJsonString = value => {
|
|
8
|
+
try {
|
|
9
|
+
JSON.parse(value);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
exports.isJsonString = isJsonString;
|
|
16
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["isJsonString","value","JSON","parse","e","exports"],"sourceRoot":"../../src","sources":["helpers.ts"],"mappings":";;;;;;AAAO,MAAMA,YAAY,GAAIC,KAAa,IAAc;EACtD,IAAI;IACFC,IAAI,CAACC,KAAK,CAACF,KAAK,CAAC;EACnB,CAAC,CAAC,OAAOG,CAAC,EAAE;IACV,OAAO,KAAK;EACd;EACA,OAAO,IAAI;AACb,CAAC;AAACC,OAAA,CAAAL,YAAA,GAAAA,YAAA"}
|