Im trying to use the SecKeyCopyKeyExchangeResult function to obtain the shared secret from my local private key and received public key of server.
Shared key is generated successfully and I able to decrypt incomming message with AES encryption
Not so long time ago server devs decided to add KDF to key generation flow.
I started investigate how I can do it on iOS side and find out that there is a special param static let sharedInfo: SecKeyKeyExchangeParameter
To say that documentation is poor its to say nothing...
Only what I did found is this description in header
#constant kSecKeyKeyExchangeParameterSharedInfo Contains CFDataRef
with additional shared info
for KDF (key derivation function).
If somebody have worked with this please help. Server use this params to generate KDF on scala
private def concatWithKdf(secretKey: SecretKey) = {
val bytes = new Array[Byte](SECRET_KEY_LENGTH)
val digest = new SHA256Digest();
val kdf1BytesGenerator = new KDF1BytesGenerator(digest)
kdf1BytesGenerator.init(new KDFParameters(secretKey.getEncoded, null))
kdf1BytesGenerator.generateBytes(bytes, 0, bytes.length)
new SecretKeySpec(bytes, secretKey.getAlgorithm)
}
Code on iOS side
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandard,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
You are totally right my friend, the documentation around the Security Framework is abysmal.
Indeed CryptoKit is Apple's attempt to modernise things here in a libsodium style providing simple interfaces to carefully selected primitives, such as elliptic curve Diffie-Hellman over safe curves.
So I sympathise, and suggest generally just use libsodium when you need crypto on iOS/macOS.
Anyway, to hopefully answer your question, I found a mention in the SecKit lib that matches what you seem to use in Scala, after the Diffie-Hellman process you are running the key material through SHA256 on the server side, so iOS needs to match this HBKDF.
#constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256
Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys
and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows
kSecKeyKeyExchangeParameterSharedInfo parameters to be used.
so I think you just need to change this:
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandard,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
to this:
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
I haven't tested the above as I'm on a Linux machine atm, but hopefully it helps, it should add SHA256 based KDF onto the ECDH process. But yeah, what a mess of an API. I just can't work with it.
Related
Update
Misleading question:
From the discussion below as well as this question formulated thereafter ...
Why do PKCS#1 PublicKeys from 'Java17 KeyFactory' and Swift (iOS) differ?
... it became clear that the assumption leading to this question ...
'iOS: Creating PublicKey in PKCS-Format instead of ASN.1-Format'
... was fundamentally wrong.
Fixing the assumptions
Hence the assumptions should have been:
Swift (iOS) produces PKCS#1-formatted keys
Java 17 produces keys which look alike but are slightly different using SubjectPublicKeyInfo (or SPKI)
For the sake of documentation, the question remains untouched (below)
Objective
Creating a PublicKey in PKCS-format:
Generated on an iOS-device (Swift)
General approach
iOS generates PublicKeys which are represented in ASN.1-Format
https://www.rfc-editor.org/rfc/rfc3447#appendix-A
Sample: Generating a KeyPair (ASN.1-Format)
SampleCode to extract the PublicKey in ASN.1-Format from the KeyPair (Swift):
// Keypair attributes
let tag = "my_personal_keystore_keypair_alias".data(using: .utf8)!
let attributes: [String: Any] =
[kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: "4096",
kSecPrivateKeyAttrs as String:
[kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag]
]
var error: Unmanaged<CFError>?
// Generate PrivateKey / Keypair
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
// Extract PublicKey
guard let publicKey = SecKeyCopyPublicKey(privateKey),
let publicKeyOptional = SecKeyCopyExternalRepresentation(publicKey, nil) else {
return "PublicKey could not be accessed."
}
let publicKeyData = publicKeyOptional as Data
let base64PublicKey = publicKeyData.base64EncodedString()
print("PublicKey, base64: ", base64PublicKey)
Problem
I am missing an option to retrieve the PublicKey in PKCS-Format.
Apple Developer Documentation
There seems to be some kind of a SecItemExport, but it lacks explanation to me.
https://developer.apple.com/documentation/security/1394828-secitemexport
Stackoverflow
The question is not new in its intent, still the best answer is linked to a dead resource and hence of no use.
Exporting public key in pkcs#1 format on iOS?
Additional condition
External libraries for key generation are not allowed.
The intent is that it is not possible to trust sources to handle PrivateKeys properly. Therefore only sources from Apple are trusted.
Nevertheless, using a library to convert the PublicKey (only) from ASN.1 into PKCS-format would be feasible.
Anyways
Thanks for reading & sharing - any help is appreciated :)
Appendix for experimentation
Adding public keys which are produced by the given code.
I serve multiple to prevent 'lucky shots' .. ;-)
First:
MIICCgKCAgEAl0HYn9IdRmexAR9dSh3SxmFazWF0RV2TKmtRxGySvCA+aHZ/Dp+8tC0YDWpQzP+tZdlDWNOBj/D7i1z4b+UZk8F9ZEoi+w61kYQz+KjMkRuYrPBFi4A/gsS2qGeFJ4OvLQzGObZ0C+5/E+wunUWyQCVjgjTHKH8yqfVXeWYFKmaSSZblSZJAObE8Ao5J38DMINF1oWG+GdZt8RTLf35ULLEa8zKvFXrfBkDjiQH90WKPwDxWwvFInqZhjpsFxLytiKW+iBLqa4+0P7uwXVodFXa38RW9dk9mEsLvj6764BKtPAaWym9XZfEZNBu0jwlfO07k0augynGps6bsSIyYglDImlTRagdA/e+1AMBlSxEFVO4NpCjEpMT7rNX/LYPeEaJ8fTC3axOM1yEntcwUfSSCDulVPGlWlFbPxt29y1RrGtMmwfbTlbOQf2okMf0mGx9Ytd9HWadIdWh4FqDVWA8MF82PP1YsOW5TA0hkprK1qJwfkaLRKnmpfL5a7gWn4HWzpdDqrezhbc/zTCeHbX5c61mgWsAIWnB3fyXsJHpR62+QtBEznwhDxafVCQyUmsDqbncBxilEnFIn08G+6ox2PQC8GhNdpFVGsSoqpDfctsm51/tUYLpyeIBdzw/3nMLL1J5jL3yWr7ZKgnzNwjpC8l6c6gpsF3NRodeVhp8CAwEAAQ==
Second:
MIICCgKCAgEAlSbN7rlX6EMCDGuxQm9G6qqXIWshDvI5VaN4QPNCFcFzPjI/FyaHqi43+mxTyKGycT6TNqvanSu67yoIA80tSlFH2LndWv6sPQeHKxNwwFKU98Y/uL3M6hKIVXDwa6kZGM58dfY9qMWEOPXB4AwZtVaxJ4ePHFAR0kEOAHLCPpQxFkNlkg9FlCwlBzZbhHkI5uhCmlGEiLpLaJNJzjn7yo33m65189J6tIh3vopZ2ahFHb/vo6SVSbtS7Y0YlinJwH3MCGLm5+pKBpE64t5lgEhDPYSF7pKpLhEVqC5ETaya3mYTkXPSCiY/9Mo5zddniUGrxAJaY940jY3QNYeFmWPEEdhhIW2tUbuiM3IlHAqk4Du5p/2o1QcSVZdBsHStSGdcWqs00Z+ooxXwrOpMOUnZeb8Jt5dGDyHwjOmPf0N8dDQwz+5pgOoTkxd/z5cTK9tMv/nC+Mbbt8LRsct16M3LYrRAYnA8unX1ZD3eXTJPOSB/fM9Hmf1ObxQro9tatC5RaJjS0Xg5aepUsey62BW9lj4kHCkRPD4w1OmjDWGUCOSEhwy0KwqFyRBppYUMndEbJb3GKEjpekcQYwjERPtH/vEVxaN5gGYaCORancUaNH+d03zAmi0G830QXQvyohyKUkGw5qljEBH5R5Wqu7YLTlUes0rQEx8DpLVclaMCAwEAAQ==
Third:
MIICCgKCAgEA1ZqMyEHgyW/uFK0+BRbByiu2ZMG/HsasoC27h4FEjvSxQQTtMgAZpoFNAjLstDWcN6PtT4137LVW3L0nsYvth+MG91mkpiByqoCNc6RigQDODNkmPlOk0ICIBII06CYx/FhzyVnm+idbi+TCZ4k9SFYkqN4iuve3QSDp8AJjIoKQEdJGcwiSE85eMXoNLmqCJ0ACxEYLHUI8n/rm2Zo3pJNRYL/WIsJvjzZAFHJ0I8ZwGzB7pNbTr6IGiXFxy8mZ51/yaQCe2/sPQLIVlYwD+lBCpDNoX3S86JLCEWOHmvntcPoPyvKnyaaE4i8yU1XUtCC1oSK4yodJPSrCzixIjG72P/puoUkTHWsLzPQ3yVVJYztvp+ETVwUj+wm8VD5GzbnPrwkO5MctmRhIEPZ1s63Tv4we1PtjlsFvsFPTYm1nuoSgsscfdjcb1/YFF/JcnVreuQcuHNrxecSxa47XzuETb5CfvoB+pVj7hZjOkEABWWcpaMTciIDk9CYUNByM33YFCt8tIPB/uuC3Kt8EpdfkypHh7CcNgHv6O6YXeUuNrb7XjE5DdtcbRMVHHWo8bNzLOHYgd7HMY346Ie6Ko8SFGMNV4Npk+c2CGzZgpBvo3+PfjGfXQjBVcdt9asQvF1fc922Zx2Oyy7Uc+xmTHkpKZqZB2LU++N+aHOa/370CAwEAAQ==
The fastest way to check the keys is to use a website like this ( https://www.javainuse.com/rsagenerator ).
Use the "RSA Encryption"-SubSection, paste one of the Keys including some sample payload to be encrypted.
We expect the keys to be formatted as PKCS#1.
Therefore for 'Cipher Type' RSA/ECB/PKCS1Padding or RSA/None/PKCS1Padding is chosen.
Both lead to ' unknown key type passed to RSA' although the "RSA Generate Keys"-Subsection above produces 'alike'-RSA keys.
Hence the iOS-Key has a different Format, which is ASN.1
Still, PKCS#1 is searched for .. :)
I'm try to generate key pairs with CryptoKit, but seems like the key pairs is not compatible with other platform like https://8gwifi.org/ecsignverify.jsp
import CryptoKit
...
let privateKey = P256.Signing.PrivateKey()
let publicKey = privateKey.publicKey
//using this send this string to other platform
let publicKeyPem = publicKey.pemRepresentation
//keeping this one on my keychain
let privateKeyPem = privateKey.pemRepresentation
but this keypairs can't be verified in other platform, like when I sign some data with private key and can't be verified by someoneelse(but it works well on iOS platform, is there something I missed?)
You are using two different Curves. The link you specified shows that you are trying to initiate a secp256k1 key, but that is not the same as CryptoKit P256 - which is the Curve secp256r1, notice last two chara k1 != r1. Even if private key instantiation succeeds, the public keys will differ, so signature validation (verification) will always fail.
Can you use secp256r1? It is present in the list on the site you linked to, above sect571r1.
Do you have to use secp256k1? If so you can use
https://github.com/Sajjon/K1
Want to use secp256k1 in CryptoKit in the future? Help me upvote my proposal to get it added to swift-crypto (open source variant of CryptoKit)!
How to prove that certain data is calculated(or generated) inside Enclave(Intel SGX)?
I tried to generate asymmetric key pair inside enclave(private key might be invisible to outside), and
then expose public key with evidence(i guess quote or remote attestation related things).
I got how remote attestation goes but, i cannot come up with applying remote attestation to verifying enclave-generated data.
Is this possible scenario with Intel SGX?
You can prove the origin of the public key by placing it in the report_data field of a Quote generated during report attestation.
_quote_t.report_data can be used to attest arbitrary data:
The 64 byte data buffer is free form data and you can supply any information in that buffer that you would like to have identified as being in the possession and protection envelope of the enclave when the report/quote was generated. You can thus use this buffer to convey whatever information you would like to a verifying party. (Source)
The report_data field can be found by tracking the following structures:
sgx_key_exchange.h
typedef struct _ra_msg3_t {
sgx_mac_t mac
sgx_ec256_public_t g_a;
sgx_ps_sec_prop_desc_t ps_sec_prop;
uint8_t quote[]; // <- Here!
} sgx_ra_msg3_t;
sgx_quote.h
typedef struct _quote_t
{
uint16_t version;
uint16_t sign_type;
sgx_epid_group_id_t epid_group_id;
sgx_isv_svn_t qe_svn;
sgx_isv_svn_t pce_svn;
uint32_t xeid;
sgx_basename_t basename;
sgx_report_body_t report_body; // <- Here!
uint32_t signature_len;
uint8_t signature[];
} sgx_quote_t;
The Quote is part of the Msg3 (client-to-server) of remote attestation protocol. You can review the details of Msg3 creation in this official Code Sample and in the intel/sgx-ra-sample RA example.
In the latter, you can find out how the report is generated using sgx_create_report:
sgx_status_t get_report(sgx_report_t *report, sgx_target_info_t *target_info)
{
#ifdef SGX_HW_SIM
return sgx_create_report(NULL, NULL, report);
#else
return sgx_create_report(target_info, NULL, report);
#endif
}
In both cases, second argument sgx_report_data_t *report_data is NULL and can be replaced by pointer to arbitrary input. This is where you want to put your public key or any other data.
I am making an app which behaves like cloud storage. I need to upload a file with Alamofire. When I am uploading the related file, I need to append a string which holds path like: "folderName/fileName" (which shows the path on my cloud storage app) to my file data in bytes. I can achieve this by using below code in Java:
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
params.put("parameterName", new DataPart("folderName/fileName", fileInBytes));
return params;
}
But I don't know how to do this in Swift. I need to create a new Data with a string and a data, before uploading it with Alamofire. How can I achieve that? Any response will be appreciated.
Thanks everyone who answered me, I've found a solution. I created a structure called DataPart with a string and data, and put that parameter to my Alamofire request with parameter name.
"What is the equivalent of a Java HashMap<String,Integer> in Swift" this entry helped me a lot in case you are wondering.
If I understand correctly, you want to convert your path (of type String) to swift's Data structure, then upload it to your server alongside a joined file's data.
so here's how you can do it-
let path = "folderName/fileName"
let pathEncodedData = path.data(using: .utf8)!
let fileData: Data = #YourFile'sData
let params = ["path": pathEncodedData, "fileData": fileData]
I have to write a program to establish a secure communication with a USB device. I have to use the private key generated from it which is stored in PKCS#1 format. As I have used Crypto++ in order part of my program, I would like to utilize it for this purpose as well.
However, I cannot find a way to import RSA private key from memory. It accepts private key in PKCS#8 format only. Could some pro show me a sample code on how to do it? Many thanks!
PKCS#1 format is ASN.1 encoded. For RSAPublicKey and RSAPrivateKey, its as easy as:
RSA::PublicKey publicKey(...);
ByteQueue queue;
publicKey.Save(queue);
// The public key is now in the ByteQueue in PKCS #1 format
// ------------
// Load a PKCS #1 private key
byte key[] = {...}
ArraySource arr(key, sizeof(key));
RSA::PrivateKey privateKey;
privateKey.Load(arr);
// The private key is now ready to use
Saving and loading keys is discussed in more detail at the Crypto++ wiki under Keys and Formats.