Skip to content

Commit bec13b0

Browse files
authored
Merge pull request #215 from ohaiibuzzle/fix/createkey
fix: Private/Public Key Generation
2 parents fe1bbfe + 59959fa commit bec13b0

2 files changed

Lines changed: 131 additions & 0 deletions

File tree

PlayTools/MysticRunes/PlayedApple.swift

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,95 @@ public class PlayKeychain: NSObject {
198198

199199
return errSecItemNotFound
200200
}
201+
202+
@objc static public func keyCreateRandomKey(_ parameters: NSDictionary,
203+
error: UnsafeMutablePointer<Unmanaged<CFError>?>?)
204+
-> Unmanaged<SecKey>? {
205+
// Check if kSecAttrIsPermanent is set to 1 in kSecPrivateKeyAttrs.
206+
// If it is, set it to 0 before fowarding the call to SecKeyCreateRandomKey,
207+
// and then add the key to the keychain db with the original attributes (with kSecAttrIsPermanent set to 1)
208+
var privateKeyAttrs = parameters[kSecPrivateKeyAttrs as String] as? [String: Any] ?? [:]
209+
let isPermanent = privateKeyAttrs[kSecAttrIsPermanent as String] as? Bool ?? false
210+
if isPermanent {
211+
privateKeyAttrs[kSecAttrIsPermanent as String] = false
212+
}
213+
var parametersCopy = parameters as! [String: Any] // swiftlint:disable:this force_cast
214+
parametersCopy[kSecPrivateKeyAttrs as String] = privateKeyAttrs
215+
var error: Unmanaged<CFError>?
216+
guard let key = SecKeyCreateRandomKey(parametersCopy as CFDictionary, &error) else {
217+
debugLogger("Failed to create random key: \(error!.takeRetainedValue())")
218+
return nil
219+
}
220+
if isPermanent {
221+
// Add the key to the keychain db with the original attributes
222+
var keychainDict = [String: Any]()
223+
keychainDict[kSecClass as String] = kSecClassKey
224+
keychainDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
225+
keychainDict[kSecAttrKeyClass as String] = parameters[kSecAttrKeyClass as String]
226+
keychainDict["type"] = parameters[kSecAttrKeyType as String]
227+
keychainDict["kcls"] = parameters[kSecAttrKeyClass as String]
228+
keychainDict["v_Data"] = SecKeyCopyExternalRepresentation(key, nil) as? Data
229+
keychainDict["r_Attributes"] = 1
230+
guard playChainDB.insert(keychainDict as NSDictionary) != nil else {
231+
debugLogger("Failed to write keychain file")
232+
return nil
233+
}
234+
}
235+
return Unmanaged.passRetained(key)
236+
}
237+
238+
@objc static public func keyGeneratePair(_ parameters: NSDictionary,
239+
publicKey: UnsafeMutablePointer<Unmanaged<SecKey>?>?,
240+
privateKey: UnsafeMutablePointer<Unmanaged<SecKey>?>?) -> OSStatus {
241+
// Same as above but we need to disable kSecAttrIsPermanent for both the public and private key.
242+
var privateKeyAttrs = parameters[kSecPrivateKeyAttrs as String] as? [String: Any] ?? [:]
243+
let isPrivatePermanent = privateKeyAttrs[kSecAttrIsPermanent as String] as? Bool ?? false
244+
if isPrivatePermanent {
245+
privateKeyAttrs[kSecAttrIsPermanent as String] = false
246+
}
247+
var publicKeyAttrs = parameters[kSecPublicKeyAttrs as String] as? [String: Any] ?? [:]
248+
let isPublicPermanent = (publicKeyAttrs[kSecAttrIsPermanent as String] as? Bool) ?? false
249+
if isPublicPermanent {
250+
publicKeyAttrs[kSecAttrIsPermanent as String] = false
251+
}
252+
var parametersCopy = parameters as! [String: Any] // swiftlint:disable:this force_cast
253+
parametersCopy[kSecPrivateKeyAttrs as String] = privateKeyAttrs
254+
parametersCopy[kSecPublicKeyAttrs as String] = publicKeyAttrs
255+
var newPublicKey: SecKey?
256+
var newPrivateKey: SecKey?
257+
guard SecKeyGeneratePair(parametersCopy as CFDictionary, &newPublicKey, &newPrivateKey) != 0 else {
258+
debugLogger("Failed to generate key pair.")
259+
return errSecMissingEntitlement
260+
}
261+
if isPrivatePermanent {
262+
// Add the keys to the keychain db with the original attributes
263+
let publicKeyRef = newPublicKey
264+
let privateKeyRef = newPrivateKey
265+
var publicKeyDict = [String: Any]()
266+
publicKeyDict[kSecClass as String] = kSecClassKey
267+
publicKeyDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
268+
publicKeyDict[kSecAttrKeyClass as String] = kSecAttrKeyClassPublic
269+
publicKeyDict["type"] = parameters[kSecAttrKeyType as String]
270+
publicKeyDict["kcls"] = kSecAttrKeyClassPublic
271+
publicKeyDict["v_Data"] = SecKeyCopyExternalRepresentation(publicKeyRef!, nil) as? Data
272+
publicKeyDict["r_Attributes"] = 1
273+
guard playChainDB.insert(publicKeyDict as NSDictionary) != nil else {
274+
debugLogger("Failed to write public key to keychain db")
275+
return errSecMissingEntitlement
276+
}
277+
var privateKeyDict = [String: Any]()
278+
privateKeyDict[kSecClass as String] = kSecClassKey
279+
privateKeyDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
280+
privateKeyDict[kSecAttrKeyClass as String] = kSecAttrKeyClassPrivate
281+
privateKeyDict["type"] = parameters[kSecAttrKeyType as String]
282+
privateKeyDict["kcls"] = kSecAttrKeyClassPrivate
283+
privateKeyDict["v_Data"] = SecKeyCopyExternalRepresentation(privateKeyRef!, nil) as? Data
284+
privateKeyDict["r_Attributes"] = 1
285+
guard playChainDB.insert(privateKeyDict as NSDictionary) != nil else {
286+
debugLogger("Failed to write private key to keychain db")
287+
return errSecMissingEntitlement
288+
}
289+
}
290+
return errSecSuccess
291+
}
201292
}

PlayTools/PlayLoader.m

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#import <PlayTools/PlayTools-Swift.h>
1212
#import <sys/utsname.h>
1313
#import "NSObject+Swizzle.h"
14+
#import <dlfcn.h>
15+
16+
@import MachO;
1417

1518
// Get device model from playcover .plist
1619
// With a null terminator
@@ -170,10 +173,46 @@ static OSStatus pt_SecItemDelete(CFDictionaryRef query) {
170173
return retval;
171174
}
172175

176+
static SecKeyRef pt_SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) {
177+
SecKeyRef result;
178+
if ([[PlaySettings shared] playChain]) {
179+
result = [PlayKeychain keyCreateRandomKey:(__bridge NSDictionary * _Nonnull)(parameters) error:error];
180+
} else {
181+
result = SecKeyCreateRandomKey(parameters, (void *)error);
182+
}
183+
184+
if ([[PlaySettings shared] playChainDebugging]) {
185+
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyCreateRandomKey: %@", parameters]];
186+
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyCreateRandomKey result: %@", result]];
187+
}
188+
189+
return result;
190+
}
191+
192+
// Deprecated, but some apps might still use it.
193+
static OSStatus pt_SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
194+
OSStatus retval;
195+
if ([[PlaySettings shared] playChain]) {
196+
retval = [PlayKeychain keyGeneratePair:(__bridge NSDictionary * _Nonnull)(parameters) publicKey:(void *)publicKey privateKey:(void *)privateKey];
197+
} else {
198+
retval = SecKeyGeneratePair(parameters, (void *)publicKey, (void *)privateKey);
199+
}
200+
201+
if ([[PlaySettings shared] playChainDebugging]) {
202+
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair: %@", parameters]];
203+
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair public key result: %@", publicKey != NULL ? *publicKey : nil]];
204+
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair private key result: %@", privateKey != NULL ? *privateKey : nil]];
205+
}
206+
207+
return retval;
208+
}
209+
173210
DYLD_INTERPOSE(pt_SecItemCopyMatching, SecItemCopyMatching)
174211
DYLD_INTERPOSE(pt_SecItemAdd, SecItemAdd)
175212
DYLD_INTERPOSE(pt_SecItemUpdate, SecItemUpdate)
176213
DYLD_INTERPOSE(pt_SecItemDelete, SecItemDelete)
214+
DYLD_INTERPOSE(pt_SecKeyCreateRandomKey, SecKeyCreateRandomKey)
215+
DYLD_INTERPOSE(pt_SecKeyGeneratePair, SecKeyGeneratePair)
177216

178217
static uint8_t ue_status = 0;
179218

@@ -276,6 +315,7 @@ static int pt_usleep(useconds_t time) {
276315
return usleep(time);
277316
}
278317

318+
279319
DYLD_INTERPOSE(pt_open, open)
280320
DYLD_INTERPOSE(pt_stat, stat)
281321
DYLD_INTERPOSE(pt_access, access)

0 commit comments

Comments
 (0)