CryptoKit - Encrypt with public key?

834 Views Asked by At

To give you the context, there is a developer who develops the API of the project and there is a part of the json that will be encrypted. So I have to decipher his content. He has listed all the functions that I will need on the iOs side.

So I have his javascript code and I have to redo the equivalent in swift. He uses the JS library (SJCL) : https://github.com/bitwiseshiftleft/sjcl/

I'm trying to encrypt some text with a public key, but I can't.

First, I generated the private/public keys

let keypair = P256.Signing.PrivateKey() // generation of a key pair

 let private_key = keypair.rawRepresentation.base64EncodedString()   // private key
 print(private_key)
 print("------------")

 let public_key = keypair.publicKey // public key - DATA
 print(public_key)
 print("------------")

 let publicKeyString = public_key.rawRepresentation.base64EncodedString() // public key - STRING - easy to share
 print(publicKeyString)

Now, I'm trying to encrypt a text with the public key..

Here, his javascript code :

var c256 = sjcl.ecc.curves.c256;
var publickeyBas64ToBits = sjcl.codec.base64.toBits(publickey);

console.log(c256);
console.log(publickey);
console.log(publickeyBas64ToBits);

var pub = new sjcl.ecc.elGamal.publicKey(
                    c256, 
                    publickeyBas64ToBits
                )
var ciphertext = sjcl.encrypt(pub, message)
return ciphertext

I don't understand how to do the same thing in swift with CryptoKit :/

Can you help me please ? :)

1

There are 1 best solutions below

0
On

Given two KeyPairs, lets call them Alice and Bob - Alice would like to encrypt a message M that only Bob should be able to decrypt (and Alice too):

You are given Bobs public key as either 33 or 64 or possibly 65 bytes (compressed form, X||Y form (raw) or uncompressed 04||X||Y), construct a P256.KeyAgreement.PublicKey from the bytes. This assumes that the bytes are not base64 encoded, but rather on hex format (see this for hex String to Data conversion: https://gist.github.com/nicklockwood/81b9f122f3db9e7132be7bd61d0c0cea ). If Base64 instead of hex, decode it first and ensure 33, 64, or 65 bytes. If 65 bytes, drop the first byte and use this initializer if 33 bytes use this initializer instead

Having access to Alice private key, P256.KeyAgreement.PrivateKey - if you have earlier created a signing private key (P256.Signing.PrivateKey), you can simply convert back and forth between them using the property rawRepresentation and the initializer init(rawRepresentation on both - perform the keyagreement to form a SharedSecret. By calling

let sharedSecret = aliceKeyAgreementPrivateKey.sharedSecretFromKeyAgreement(with: bobsKeyAgreementPublicKey)

Now lets create an AES.GCM.SealedBox from the message bytes

let encryptedMessage = try AES.GCM.SealedBox(combined: messageData) Where messageData is Data from either base64 decoding a base64 encoded string or Data from hex string.

Now lets create a SymmetricKey we can use to AES.GCM decrypt - “open” - the sealedBox.

let aesDecryptionKey = sharedSecret.withUnsafeBytes { SymmetricKey($0) } Or using this method instead of withUnsafeBytes or this method, but then you need to come up with a good salt. These methods are much much safer then withUnsafeBytes, but makes my explaination a bit longer and more complex, so I leave it to your system to determine salt.this have to match what the sender used to encrypt the message of course!! As in both the SharedSecret by KeyAgreement AND the derivation of the SymmetricKey for encryption/decryption has to match..

Finally we can open the SealedBox!

let decryptedData = try AES.GCM.open(sealedBox, using: aesDecryptionKey)

And if the data was some plaintext message you might wanna decode it so it becomes readable, e.g. If it was UTF8 encoded:

let decryptedMessage = String(data: decryptedData, encoding: .utf8)!