/** * Construct a group session for sending messages. * * @param senderKeyName The (groupId, senderId, deviceId) tuple. In this case, 'senderId' should be the caller. * @return A SenderKeyDistributionMessage that is individually distributed to each member of the group. */ public SenderKeyDistributionMessage Create(SenderKeyName senderKeyName) { lock (GroupCipher.LOCK) { try { SenderKeyRecord senderKeyRecord = senderKeyStore.LoadSenderKey(senderKeyName); if (senderKeyRecord.IsEmpty()) { senderKeyRecord.SetSenderKeyState(KeyHelper.GenerateSenderKeyId(), 0, KeyHelper.GenerateSenderKey(), KeyHelper.GenerateSenderSigningKey()); senderKeyStore.StoreSenderKey(senderKeyName, senderKeyRecord); } SenderKeyState state = senderKeyRecord.GetSenderKeyState(); return(new SenderKeyDistributionMessage(state.GetKeyId(), state.GetSenderChainKey().GetIteration(), state.GetSenderChainKey().GetSeed(), state.GetSigningKeyPublic())); } catch (InvalidKeyIdException e) { throw new Exception(e.Message); } catch (InvalidKeyException e) { throw new Exception(e.Message); } } }
/** * Decrypt a SenderKey group message. * * @param senderKeyMessageBytes The received ciphertext. * @param callback A callback that is triggered after decryption is complete, * but before the updated session state has been committed to the session * DB. This allows some implementations to store the committed plaintext * to a DB first, in case they are concerned with a crash happening between * the time the session state is updated but before they're able to store * the plaintext to disk. * @return Plaintext * @throws LegacyMessageException * @throws InvalidMessageException * @throws DuplicateMessageException */ public byte[] Decrypt(byte[] senderKeyMessageBytes, DecryptionCallback callback) { lock (LOCK) { try { SenderKeyRecord record = senderKeyStore.LoadSenderKey(senderKeyId); if (record.IsEmpty()) { throw new NoSessionException("No Sender Key For: " + senderKeyId); } SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyMessageBytes); SenderKeyState senderKeyState = record.GetSenderKeyState(senderKeyMessage.GetKeyId()); senderKeyMessage.VerifySignature(senderKeyState.GetSigningKeyPublic()); SenderMessageKey senderKey = GetSenderKey(senderKeyState, senderKeyMessage.GetIteration()); byte[] plaintext = GetPlainText(senderKey.GetIv(), senderKey.GetCipherKey(), senderKeyMessage.GetCipherText()); callback.HandlePlaintext(plaintext); senderKeyStore.StoreSenderKey(senderKeyId, record); return(plaintext); } catch (InvalidKeyException e) { throw new InvalidMessageException(e); } catch (InvalidKeyIdException e) { throw new InvalidMessageException(e); } } }