ECC Curve25519 KeyChain - ios

I'm trying to create Curve25519 keys using the KeyChain on iOS. I am aware of the existence of CryptoKit, unfortunately, that is not available for iOS 12. Is there a way to create a Curve25519 key pre CryptoKit, maybe a parameter I'm missing when generating it in the KeyChain? The code below will only generate the P-256 keys.
let attributes: [String: Any] = [
String(kSecClass): kSecClassKey,
String(kSecAttrKeyType): kSecAttrKeyTypeECSECPrimeRandom,
String(kSecAttrKeySizeInBits): 256
]
var error: Unmanaged<CFError>?
let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)
print(privateKey ?? error!.takeUnretainedValue())

Apple's old core crypto lib CommonCrypto doesn't support modern curves like curve25519 and quite frankly is a total mess, littered with insecure ciphers, they aren't even clear on the actual curve equations being used.
Additionally, although CryptoKit supports curve25519 for key exchange, it's still limited, for example, you cannot use the "Secure Enclave" to generate curve25519 keys, only P-256, which is likely backdoored (just look at the curve co-efficients), despite all financial institutions seemingly loving it.
Ultimately a curve25519 private key is just a large (2^256) number (though it is "clamped" before use), so if you just need to generate keys, you can do this with SecRandomCopyBytes.
Though, if as I suspect you want to do some X25519 KEX or EdDSA signature over 25519, then just use libsodium. It's the goto library for NaCl, there is a really great interface in Swift written by the original libsodium author, called swift-sodium, I've used it and it's great. It also supports iOS 12+.
Generating keys in libsodium for curve25519 is as simple as:
import Sodium
let sodium = Sodium()
let curve25519KeyPair = sodium.box.keyPair()
let privateKey = curve25519KeyPair!.secretKey
let publicKey = curve25519KeyPair!.publicKey
You can then manually store in KeyChain.
Shout if you need further help, and good choice using 25519.

Related

AES encryption not working properly on iOS 13.4

My iOS application creates a key using AES encryption and send it with all the APIs , and it is being decrypted at the server end, now after the update of OS 13.4 the key created from the device(not the simulator) is in incorrect and the following error is thrown by the server :
"Padding is invalid and cannot be removed."
It is working perfectly in the devices below 13.4 OS version , we are using CommonCrypto to encrypt the key at our end , following are the details :
let ivData = "passpharse".data(using:String.Encoding.utf8)!
let cryptLength = size_t(data.count + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength
let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
The surprising part is that the key is being correctly generated for some API calls although same method is used for key generation.
Users with iOS - OS less than 13.4 are not facing any issue, If anyone have came across the same situation please guide.
thanks in advance.
After much research I made it work on all the versions.
if in the above code “passphrase” is shorted than 16 bytes, it uses whatever's in-memory past the end.
It seems like improper use of the CommonCrypto APIs was the issue here. Really don’t know why this worked before, but maybe we got lucky with the memory layout but the issues above need to be remedied before this will function as expected.

RSA Key generation with SecKey Xamarin.iOS

I'm trying to generate a public (and private) key pair using the SecKey class from Xamarin.iOS.
The KeySize is defined to 1024 bit and this seems to work (if I change this value, the length of the result array is changing too).
I generate the keys with
SecKey.GenerateKeyPair(CreateRsaParams(), out publicKey, out privateKey);
byte[] key = publicKey.GetExternalRepresentation().ToArray()
(CreateRsaParams() is a function giving back a NSDictionary with the required data)
The problem is: I get a byte array (public key) with 140 Bytes - but depended on the key size it should have only 128 Byte - and I need a 128 Byte public key for data exchange with an other system
(by the way - using PCLCrypto is not an option for me since the project is not allowed to use this 3rd party component)
Does anyone know the problem and know a solution?
Okay, problem solved.
If anyone is facing the same problem, you can find the solution at
https://forums.developer.apple.com/thread/111109
The problem was not the key, but the wrongly formulated requirement.

Decrypting with AES256CBC Library doesn't return same value?

I'm trying to implement aes256 security to both Android, iOS and Web. In iOS part I'm using this library. But when I try to decrypt text with same password on this website or any other website or with googles aes.js file in html project. They don't give same result.
What am I missing? Thank you.
let str = "emre"
let password = "2ABdhQTy1GAWiwfvsKfJyeZVfrHeloQI"
let encrypted = AES256CBC.encryptString(str, password: password)
print(encrypted!)
let decrypted = AES256CBC.decryptString(encrypted!, password: "2ABdhQTy1GAWiwfvsKfJyeZVfrHeloQI")
print(decrypted!)
The AES256CBC.encryptString(..) methode you use, generates an IV and prepend the encrypted data with it. The AES256CBC.decryptString(..) methode then
obtains the IV from the encrypted data before decrypting the message.
Take a look in the encryptString methody you are using. See the IV it's creating? The IV is a random bit of data given as input to AES encryp/decrypt when running in CBC mode. The IV is often pre-prended to the encrypted data (as this library did here), but this is not standardized across different libraries.
If you wan't to use this library together with other implementations, you need to handle this part yourself.
Also, the online web page you link, don't seem to support CBC mode, so try use another one, like this.

compare two secKey (public keys) in ios Swift

I want to ssl public key pinning in swift, I read lot of examples how to do that, last think who I can't find is How to compare two public keys in SecKey object format.
Example:
let serverPublicKey = SecTrustCopyPublicKey(secTrust) /*return SecKey object from actual SecTrust*/
let clientPublicKey = getLocalPublicKeyFromDer() /*return SecKey from .der local*/
how to compare them? At now I do that and it works:
if(serverPublicKey! as AnyObject).isEqual(clientPublicKey){
/*Key is the same, pinning OK!*/
}
find it way on gitHub: https://github.com/teamcarma/IOS-AlamofireDomain/blob/master/Source/ServerTrustPolicy.swift
but is cast to AnyObject a good idea? How to work isEqual on casted SecKey? Can any explain me?
ps.
Another idea is getting base64 from SecKey - I try and it also works, but it require a KeyChain temp operations and look no profesional.
Cited from the headers:
"Most SecKeychainItem functions will work on an SecKeyRef."*
You may cast SecKeyRef to a SecKeychainItem. If this is a valid operation (that is, the key is a keychain item), you may apply function
SecKeychainItemCreatePersistentReference
and get a CFData object, filled with attributes and data. Then check with memcpyon the bytes or cast it to a NSData object and check with isEqualToData. Don't forget to release the CFData object.
Edit
On iOS, as far as I known, the only reliable approach is to copy the data (or secret) into the keychain, using a temporary key, so that you can find it again, and then extract the data. It's cumbersome, but if you just implement it in a minimalistic way, it should not take more than 30 lines of code. I have a working example.
I The usual disclaimer: Use this at your own risk, and always be careful with security stuff.
iOS10 added:
CFDataRef _Nullable SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error)
so you can now create two Data (NSData) objects, then compare those.
Have a look at this answer for just getting the NSData: Can I get the modulus or exponent from a SecKeyRef object in Swift?
You can then compare the two NSData instances using isEqualToData:
I don't have expereince in the domain, but if they are two strings (irrespectiveof their content), you would basically do a simple check:
if(string1 == string2)
{
//condition logic
}

iOS SecKeyEncrypt OAEP SHA512

From what I can tell looking through the various padding values for the SecKeyEncrypt method in Apple's security framework, it does not support OAEP padding with a SHA512 hash digest. In fact, I can't seem to determine if the SecKeyEncrypt method does any sort of hashing/masking of each block during the CBC process.
Herein lies my problem. All my other platforms (PHP, Android, .NET) use RSA with OAEP padding and a SHA512 digest.
For example: In C# we can use BouncyCastle's OaepEncoding class which accepts any Digest and performs the hash/mask operation during the block cipher encryption process. In php, the phpseclib project provides the same functionality.
And finally, my question... can this same functionality be achieved on iOS by somehow using a hybrid of "manual" hashing and using SecKeyEncrypt? Or am I missing something much more obvious here.
Cheers!
EDIT: I think I could probably hash/mask each block by porting the bouncy castle code and then pass the new byte array to SecKeyEncrypt for encrpytion, but that begs the question, does SecKeyEncrypt do that already using some other hashing algo internally?
As of iOS 10.0, the .rsaEncryptionOAEPSHA512 option has been added as a SecKeyAlgorithm.
Swift 4
let attributes: [String: Any] = [ ... ]
let pk = SecKeyCreateRandom(attributes as CFDictionary, nil)!
let pub = SecKeyCopyPublicKey(pk)!
let message = "Encrypt me".data(using: .utf8)!
var error: Unmanaged<CFError>?
let cipherText = SecKeyCreateEncryptedData(pub, .rsaEncryptionOAEPSHA512, message as CFData, &error)
It appears this is not possible native to the Security framework for iOS. I have had a ton of issues getting OAEP RSA encryption to work properly cross platform.
However, I did just hear from a third party library provider, Chillkat, that they are adding support for this. See: http://www.chilkatforum.com/questions/7778/ios-rsa-encryption-using-oaep-sha512
EDIT: I installed Chilkat's library and had it working in minutes.

Resources