How to get SecIdentity after SecCertificateCreateWithData and SecItemAdd? - ios

I was given a .cer file which needs to be used to connect with the server properly. At first SecCertificateCreateWithData crashed, so after research, I ended up converting .cer file to der format (openssl x509 -in cert.cer -outform der -out certder.der), and then iOS seemed to accept it.
I need to get SecIdentity object, however, there seems to be a problem:
let cerPath = Bundle.main.path(forResource: "certder", ofType: "der")
let data: NSData = try! Data(contentsOf: URL(fileURLWithPath: cerPath!)) as! NSData
let cert: SecCertificate = SecCertificateCreateWithData(nil, data)!
let params : [String: Any] = [
kSecClass as String : kSecClassCertificate,
kSecValueRef as String : cert,
kSecAttrLabel as String: "label1",
]
SecItemDelete(params as CFDictionary)
let status = SecItemAdd(params as CFDictionary, nil)
print("status1: \(status)")
let query: [String: Any] = [
kSecClass as String : kSecClassIdentity,
kSecReturnRef as String: true,
kSecAttrLabel as String: "label1"
]
var secIdentity: SecIdentity?
var extractedData: AnyObject?
let status2 = SecItemCopyMatching(query as NSDictionary, &extractedData)
print("status2: \(status2)")
if (status2 == errSecSuccess) {
print("success")
secIdentity = extractedData as! SecIdentity?
}
Log:
status1: 0
status2: -25300. Error -25300 is errSecItemNotFound
Here is how info of that given certificate looks like:
openssl x509 -in cert.cer -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1465898828 (0x575fd74c)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=LT, L=NamePurposelyHidden, O=NamePurposelyHidden, OU=NamePurposelyHidden, CN=NamePurposelyHidden
Validity
Not Before: Aug 9 08:21:03 2014 GMT
Not After : Jul 27 08:21:03 2064 GMT
Subject: C=LT, L=NamePurposelyHidden, O=NamePurposelyHidden, OU=NamePurposelyHidden, CN=NamePurposelyHidden
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b6:26:54:85:05:15:bd:2f:af:39:c0:91:41:05:
d2:35:74:bf:d2:e5:35:2d:3d:21:60:15:6b:d9:f6:
66:2b:02:29:c9:94:8b:3c:36:af:f8:5a:05:0f:21:
25:7d:90:5b:ab:70:f5:85:e8:ce:8a:60:2b:a4:61:
36:a8:b9:16:f6:79:7b:e1:1f:37:83:5b:fd:18:db:
70:7a:dd:79:3b:74:0d:4b:4f:4d:49:8c:79:0b:8c:
c1:2e:7c:4c:62:ae:b3:e4:b5:cf:4b:20:2c:98:20:
4a:4c:dd:49:67:99:7f:c1:dd:39:4d:be:8c:b7:6a:
b8:e6:c3:e3:a8:03:21:ec:a3:c8:e4:46:d7:e6:d4:
83:4a:5a:d7:a1:35:6f:54:72:96:b2:52:54:37:d4:
b4:62:f8:07:eb:27:d5:f0:42:0f:5a:3a:b8:ae:78:
38:73:e4:b5:7c:d1:6b:e4:61:6e:fd:df:c8:03:a4:
8d:fe:d3:92:98:df:30:fb:e1:03:45:cb:dd:6a:ca:
50:25:b2:a6:4b:4a:64:e0:79:a6:ef:35:53:df:d9:
48:16:f8:39:08:94:9b:8e:f0:74:01:ae:76:46:9c:
9c:a3:ec:70:45:24:44:96:3d:b4:06:51:2e:1e:dd:
4d:72:09:0d:9d:f1:11:08:9d:24:4b:5c:3e:79:0b:
b9:c7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
AE:95:DF:CD:E0:D9:BB:D1:8E:CD:15:86:98:9B:04:35:D7:E6:96:44
Signature Algorithm: sha256WithRSAEncryption
61:d3:98:46:a9:53:db:fc:a9:3b:db:40:40:63:55:7c:66:74:
35:82:83:c8:19:4a:89:ae:bd:1b:5c:26:8e:20:f9:5b:db:aa:
0c:4c:99:4e:28:3b:51:00:33:96:5f:22:40:c1:c1:c8:ed:70:
d7:f7:3e:aa:ec:f9:0e:bb:ec:f8:17:12:c1:49:f6:02:0d:73:
57:39:48:5d:ad:8f:e5:e9:3b:b1:f8:1d:d4:7e:cf:58:d5:78:
73:9c:56:3b:bb:3a:25:36:c8:3b:b8:ba:90:97:6e:28:51:5d:
63:23:3e:90:7d:87:61:13:03:c5:27:1b:51:55:c0:17:76:18:
1a:74:6d:f9:2c:c8:f1:7a:89:64:41:fc:3b:7b:82:4f:e3:e8:
5d:02:40:3a:d5:81:f3:38:de:aa:79:53:1a:d2:a3:60:59:94:
8c:bd:62:bb:6d:70:da:0d:22:3e:9d:e0:fa:5d:20:87:ce:16:
f0:53:f4:b7:1d:c7:b3:59:64:ba:8a:73:75:bc:7f:61:cb:14:
d4:9f:34:3f:bd:b1:06:0c:62:f6:1f:b4:d2:15:38:61:bd:2c:
44:94:1c:e1:88:f4:d2:fc:42:d7:6d:ed:d6:4e:a2:b7:67:20:
01:7a:87:39:3b:4c:2b:3c:ef:3c:15:54:1d:cc:00:30:9c:cc:
e2:4f:71:98

Related

iOS CryptoSwift AES Encryption to Python Decryption works - but not the inverse

I am using CryptoSwift 1.4.1, iOS 15.2, PyCryptodome 3.12.0, and XCode 13.2.1 to encrypt small string messages that I send to a Raspberry Pi Linux Device over BLE. It works when iOS encrypts the message and sends it to the Raspberry Pi. The Pi can successfully decrypt it. Now I want to do the inverse, encrypt a message on the Pi and have the iOS App read and decrypt it. This, however is not working and the decrypted value is the not the message I encrypted on the Pi.
Working iOS encryption:
func aesEncrypt(stringToEncrypt: String, key: Array<UInt8>, iv: Array<UInt8>) throws -> String {
let data = stringToEncrypt.data(using: String.Encoding.utf8)
let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding).encrypt((data?.bytes)!)
return encrypted.toHexString()
}
let ivString = "4198816658388141"
let keyString = "9004786896524916"
let key = [UInt8](keyString.utf8)
let iv = [UInt8](ivString.utf8)
let encryptedSsid = try! aesEncrypt(stringToEncrypt: ssid!, key: key, iv: iv)
Working Raspberry Pi decryption in Python:
KEY = b'9004786896524916'
IV = b'4198816658388141'
MODE = AES.MODE_CFB
def decrypt(key, iv, encrypted_text):
logger.info(f"Encrypted: {encrypted_text}")
aes = AES.new(key, MODE, iv, segment_size=128)
encrypted_text_bytes = binascii.a2b_hex(encrypted_text)
decrypted_text = aes.decrypt(encrypted_text_bytes).decode("utf-8")
logger.info(f"Decrypted: {decrypted_text}")
return decrypted_text
I tried to encrypt a message on the Pi with the following code:
KEY = b'9004786896524916'
IV = b'4198816658388141'
MODE = AES.MODE_CFB
def encrypt(key, decrypted_text):
# Create cipher object and encrypt the data
logger.info(f"Decrypted: {decrypted_text}")
cipher = AES.new(key, MODE, segment_size=128) # Create a AES cipher object with the key using the mode CBC
#encrypted_text = cipher.encrypt(pad(decrypted_text, AES.block_size)) # Pad the input data and then encrypt
encrypted_text = cipher.encrypt(decrypted_text) # Pad the input data and then encrypt
logger.info(f"Encrypted: {encrypted_text}")
return encrypted_text
...
encrypt(KEY, returnString('utf-8'))
However, the iOS App fails to decrypt it properly with this method:
func aesDecrypt(stringToDecrypt: String, key: Array<UInt8>, iv: Array<UInt8>) throws -> String {
let data = stringToDecrypt.data(using: String.Encoding.utf8)
let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding).decrypt((data?.bytes)!)
return decrypted.toHexString()
}
let ivString = "4198816658388141"
let keyString = "9004786896524916"
let key = [UInt8](keyString.utf8)
let iv = [UInt8](ivString.utf8)
var message = try! aesDecrypt(stringToDecrypt: charString, key: key, iv: iv)
How can I get decryption to work properly in the iOS App when a message is encrypted on the Pi?
In the encrypt() method the IV is not considered. As in aesEncrypt(), the IV must be passed and used when creating the AES object.
Furthermore there are bugs in the encoding: The plaintext must be UTF8 encoded and the ciphertext must be hex encoded:
from Crypto.Cipher import AES
import binascii
def encrypt(key, iv, plaintext):
cipher = AES.new(key, MODE, iv, segment_size=128)
plaintext_bytes = plaintext.encode("utf-8")
ciphertext = cipher.encrypt(plaintext_bytes)
ciphertext_hex = binascii.b2a_hex(ciphertext)
return ciphertext_hex
This function is the counterpart to decrypt(), i.e. encrypt() can be used to generate a ciphertext which can be decrypted with decrypt() (or aesDecrypt()).
In the iOS code there are two bugs, both concerning the encoding: The ciphertext must not be UTF8 encoded, but hex decoded. And the decrypted data must not be hex encoded, but UTF-8 decoded.
A possible fix is:
func aesDecrypt(stringToDecrypt: String, key: Array<UInt8>, iv: Array<UInt8>) throws -> String {
let data = Array<UInt8>(hex: stringToDecrypt)
let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding).decrypt(data)
return String(bytes: decrypted, encoding: .utf8)!
}
This function is the counterpart to aesEncrypt(), i.e. aesDecrypt() can be used to decrypt a ciphertext generated with aesEncrypt() (or encrypt()).
Regarding security: A static IV is insecure. Instead, the IV should be randomly generated for each encryption. Since the (non-secret IV) is needed for decryption, it is passed along with the ciphertext (typically concatenated).

Retrieve issuer name from certificate by SecCertificate

I have a certificate file. SecCertificate object is created correctly.
let data = try? Data(contentsOf: fileUrl!)
let certificate = SecCertificateCreateWithData(nil, data! as CFData)
▿ Optional<SecCertificateRef>
- some : <cert(0x7fec5d608250) s: www.google.com i: Avast trusted CA>
// I can get Subject name by
SecCertificateCopySubjectSummary(certificate!)! as String
// I tried printing SecCertificateCopyNormalizedIssuerSequence
var data1 = SecCertificateCopyNormalizedIssuerSequence(certificate!)! as Data
print(String(data: data1, encoding: .utf8))
Optional("0h1\u{0B}0\t\u{06}\u{03}U\u{04}\u{06}\u{13}\u{02}CZ1\u{0F}0\r\u{06}\u{03}U\u{04}\u{08}\u{0C}\u{06}Prague1\u{0E}0\u{0C}\u{06}\u{03}U\u{04}\n\u{0C}\u{05}AVAST1\u{1D}0\u{1B}\u{06}\u{03}U\u{04}\u{0B}\u{0C}\u{14}Software Development1\u{19}0\u{17}\u{06}\u{03}U\u{04}\u{03}\u{0C}\u{10}Avast trusted CA")
But I need to get issuers name info like common name or organisation(like i from SecCertificateRef in above example) using SecCertificate.h
Thanks.

Convert private base64 encoded key to SecKey

I did generate private key using OpenSSL like this:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 563 -nodes -subj "//C=LT\ST=Vilnius\L=Vilnius\O=Briedis\OU=Org\CN=www.example.com"
The key.pem file contains privte key in base64 format. Removed BEGIN and END marks. As well new lines. After applying these changes private key looks like this:
let privteKeyString = “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“
Conversion from base64 to SecKey:
let privateKeyData = Data(privteKeyString.utf8)
var error: Unmanaged<CFError>?
let secKey = SecKeyCreateWithData(privateKeyData as! NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits: 4096,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, &error)
After execution getting an -50 error.
What is the way to convert private base64 key to SecKey?
Usually all RSAPrivateKey is not a vanilla RSAPrivateKey, but rather a PrivateKeyInfo (see Section 5 of RFC 5208). IOS do not support PrivateKeyInfo key structure. In this case a converted to RSAPrivateKey is needed. Steps to create iOS SecKey from PrivateKeyInfo:
Using OpenSSL convert private key.pem to DER format.
openssl rsa -in key.pem -outform der -out key.der
Drag and drop key.der file to the Xcode project.
Load and print out private key as vanilla RSAPrivateKey:
let keyUrl = Bundle.main.url(forResource: "key", withExtension: "der")
let keyDerData = try? Data(contentsOf: keyUrl!)
print(keyDerData?.base64EncodedString())
Convert vanilla RSAPrivateKey raw data to SecKey.
var error: Unmanaged<CFError>?
let secKey = SecKeyCreateWithData(keyDerData as! NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits: 4096,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, &error)

Secure Enclave keys exists even after app uninstallation

I have generated Keys inside the Secure enclave using the following Code Snippet,
func generateKeyPair(accessControl: SecAccessControl) throws -> (`public`: SecureEnclaveKeyReference, `private`: SecureEnclaveKeyReference) {
let privateKeyParams: [String: Any] = [
kSecAttrLabel as String: privateLabel,
kSecAttrIsPermanent as String: true,
kSecAttrAccessControl as String: accessControl,
]
let params: [String: Any] =
[
kSecAttrKeyType as String: attrKeyTypeEllipticCurve,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: privateKeyParams
]
var publicKey, privateKey: SecKey?
let status = SecKeyGeneratePair(params as CFDictionary, &publicKey, &privateKey)
guard status == errSecSuccess else {
throw SecureEnclaveHelperError(message: "Could not generate keypair", osStatus: status)
}
return (public: SecureEnclaveKeyReference(publicKey!), private: SecureEnclaveKeyReference(privateKey!))
}
Post un-installation of the application the keys still exists, is there a way to remove the keys from secure enclave ?
Thank you in advance :)
There is no trigger to perform code when the app is deleted from the device. Access to the keychain is dependant on the provisioning profile that is used to sign the application. Therefore no other applications would be able to access this information in the keychain.
https://stackoverflow.com/a/5711090/7350472
If you want to delete key from Secure Enclave you can call:
SecItemDelete(query as CFDictionary)
https://developer.apple.com/documentation/security/1395547-secitemdelete

Generating key pair in iOS using SecKeyGeneratePair failed with errSecInteractionNotAllowed

In my app I am using SecKeyGeneratePair to generate RSA key pair. After releasing the app, I started to notice occasional errSecInteractionNotAllowed errors (currently very rare) when using this function, so far only on iOS 10 devices. It is unclear to me why the key pair generation failed, or what I should do to fix that. Also, I could not find any documentation as to why key pair generation should fail with this error.
This is the code I used to generate the key pair:
guard let access = SecAccessControlCreateWithFlags(nil,
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
[],
nil) else {throw Error(description: "Failed to create access control")}
let privateAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): keyTag + self.privateKeyExtension,
String(kSecAttrAccessControl): access] as [String : Any]
let publicAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): keyTag + self.publicKeyExtension] as [String : Any]
let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): self.rsaKeySize,
String(kSecPublicKeyAttrs): publicAttributes,
String(kSecPrivateKeyAttrs): privateAttributes] as [String : Any]
var pubKey, privKey: SecKey?
let status = SecKeyGeneratePair(pairAttributes as CFDictionary, &pubKey, &privKey)
After this code, I am checking the status, and if it is not errSecSuccess, I am logging an error with the status returned from the function. This is where I noticed the errSecInteractionNotAllowed error.
So, why does key pair generation or what I could do in order to fix it?
Thanks,
Omer
Two suggestions:
Try to add an other protection class like kSecAttrAccessibleAlways to your call of SecAccessControlCreateWithFlags and test if the behavior still occurs.
Further define a flag for your use case instead of passing an empty array. E.g. userPresence.
Additionally I stumbled across this SO post, maybe you can find some inspiration there.
After discussing this with Apple Developer Support, here is the solution:
let privateAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): keyTag + self.privateKeyExtension,
String(kSecAttrAccessible): kSecAttrAccessibleAlways] as [String : Any]
let publicAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): keyTag + self.publicKeyExtension,
String(kSecAttrAccessible): kSecAttrAccessibleAlways] as [String : Any]
let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): self.rsaKeySize,
String(kSecPublicKeyAttrs): publicAttributes,
String(kSecPrivateKeyAttrs): privateAttributes] as [String : Any]
var pubKey, privKey: SecKey?
let status = SecKeyGeneratePair(pairAttributes as CFDictionary, &pubKey, &privKey)
The important part is the kSecAttrAccessible, choose the value that matches your needs from this list. Notice that some of the values will limit the access to the key in KeyVault.

Resources