I am building an E2EE chat app where there is one asymmetric key pair per group. Each user also has one asymmetric key pair. All messages in a group chat are encrypted with the group public key and decrypted with the group private key.
When Alice is added to the group, Bob (one of the group admins) encrypts the group's private key for Alice with her public key. For want of a better term, let's call this encrypted form of the group private key the "encrypted group private key". The encrypted group private key can only be decrypted using Alice's private key. It is therefore safe to store on my server. Bob creates this encrypted group private key locally and then sends it up for storage on my server.
// on Bob's device
encryptedGroupPrivateKey = encrypt(data: groupPrivateKey, publicKey: alicePublicKey)
My server in this case is just a plain key-value store of encrypted private keys on the cloud. Later, Alice can download the encrypted group private key and decrypt it to reveal the raw group private key and use that to read messages of the group.
When Bob sends up the encrypted group private key to my server, how can I verify that what Bob has sent me does indeed contain the group private key and not some garbage? Otherwise, my server would dutifully store the garbage for Alice but when Alice comes to decrypt the encrypted group private key she finds out the contents are not the group private key and is not able to read the messages of the group.
My first thought is to hash the group private key when the group is created and store the hashed version on my server and somehow later compare this hash with that of the encrypted group private key. How might this work?
I'm looking to have a verify function on my server which is able to
// on my cloud server
verify(encryptedGroupPrivateKey, groupPrivateKeyHash) // returns true
verify("anything else", groupPrivateKeyHash) // returns false
Putting it all together and more generally this is the set of functions I'm looking for:
messageHash = hash(message)
cipherText = encrypt(message, publicKey)
verify(cipherText, messageHash) # returns true
verify("anything else", messageHash) # returns false