Ejemplo n.º 1
0
        /**
         * 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);
                }
            }
        }
        /// <summary>
        /// Decrypt a SenderKey group message.
        /// </summary>
        /// <param name="senderKeyMessageBytes">The received ciphertext.</param>
        /// <param name="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.</param>
        /// <returns>Plaintext</returns>
        /// <exception cref="LegacyMessageException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        /// <exception cref="DuplicateMessageException"></exception>
        /// <exception cref="NoSessionException"></exception>
        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 (Exception e) when(e is InvalidKeyException || e is InvalidKeyIdException)
                {
                    throw new InvalidMessageException(e);
                }
            }
        }