public PreKeyWhisperMessage(uint messageVersion, uint registrationId, May<uint> preKeyId, uint signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey, WhisperMessage message) { this.version = messageVersion; this.registrationId = registrationId; this.preKeyId = preKeyId; this.signedPreKeyId = signedPreKeyId; this.baseKey = baseKey; this.identityKey = identityKey; this.message = message; WhisperProtos.PreKeyWhisperMessage.Builder builder = WhisperProtos.PreKeyWhisperMessage.CreateBuilder() .SetSignedPreKeyId(signedPreKeyId) .SetBaseKey(ByteString.CopyFrom(baseKey.serialize())) .SetIdentityKey(ByteString.CopyFrom(identityKey.serialize())) .SetMessage(ByteString.CopyFrom(message.serialize())) .SetRegistrationId(registrationId); if (preKeyId.HasValue) // .isPresent() { builder.SetPreKeyId(preKeyId.ForceGetValue()); // get() } byte[] versionBytes = { ByteUtil.intsToByteHighAndLow((int)this.version, (int)CURRENT_VERSION) }; byte[] messageBytes = builder.Build().ToByteArray(); this.serialized = ByteUtil.combine(versionBytes, messageBytes); }
public PreKeyWhisperMessage(uint messageVersion, uint registrationId, May <uint> preKeyId, uint signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey, WhisperMessage message) { this.version = messageVersion; this.registrationId = registrationId; this.preKeyId = preKeyId; this.signedPreKeyId = signedPreKeyId; this.baseKey = baseKey; this.identityKey = identityKey; this.message = message; WhisperProtos.PreKeyWhisperMessage.Builder builder = WhisperProtos.PreKeyWhisperMessage.CreateBuilder() .SetSignedPreKeyId(signedPreKeyId) .SetBaseKey(ByteString.CopyFrom(baseKey.serialize())) .SetIdentityKey(ByteString.CopyFrom(identityKey.serialize())) .SetMessage(ByteString.CopyFrom(message.serialize())) .SetRegistrationId(registrationId); if (preKeyId.HasValue) // .isPresent() { builder.SetPreKeyId(preKeyId.ForceGetValue()); // get() } byte[] versionBytes = { ByteUtil.intsToByteHighAndLow((int)this.version, (int)CURRENT_VERSION) }; byte[] messageBytes = builder.Build().ToByteArray(); this.serialized = ByteUtil.combine(versionBytes, messageBytes); }
public PreKeyWhisperMessage(byte[] serialized) { try { this.version = (uint)ByteUtil.highBitsToInt(serialized[0]); if (this.version > CiphertextMessage.CURRENT_VERSION) { throw new InvalidVersionException("Unknown version: " + this.version); } WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage = WhisperProtos.PreKeyWhisperMessage.ParseFrom(ByteString.CopyFrom(serialized, 1, serialized.Length - 1)); if ((version == 2 && !preKeyWhisperMessage.HasPreKeyId) || (version == 3 && !preKeyWhisperMessage.HasSignedPreKeyId) || !preKeyWhisperMessage.HasBaseKey || !preKeyWhisperMessage.HasIdentityKey || !preKeyWhisperMessage.HasMessage) { throw new InvalidMessageException("Incomplete message."); } this.serialized = serialized; this.registrationId = preKeyWhisperMessage.RegistrationId; this.preKeyId = preKeyWhisperMessage.HasPreKeyId ? new May<uint>(preKeyWhisperMessage.PreKeyId) : May<uint>.NoValue; this.signedPreKeyId = preKeyWhisperMessage.HasSignedPreKeyId ? preKeyWhisperMessage.SignedPreKeyId : uint.MaxValue; // -1 this.baseKey = Curve.decodePoint(preKeyWhisperMessage.BaseKey.ToByteArray(), 0); this.identityKey = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.IdentityKey.ToByteArray(), 0)); this.message = new WhisperMessage(preKeyWhisperMessage.Message.ToByteArray()); } catch (Exception e) { //(InvalidProtocolBufferException | InvalidKeyException | LegacyMessage throw new InvalidMessageException(e.Message); } }
public PreKeyWhisperMessage(byte[] serialized) { try { this.version = (uint)ByteUtil.highBitsToInt(serialized[0]); if (this.version > CiphertextMessage.CURRENT_VERSION) { throw new InvalidVersionException("Unknown version: " + this.version); } WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage = WhisperProtos.PreKeyWhisperMessage.ParseFrom(ByteString.CopyFrom(serialized, 1, serialized.Length - 1)); if ((version == 2 && !preKeyWhisperMessage.HasPreKeyId) || (version == 3 && !preKeyWhisperMessage.HasSignedPreKeyId) || !preKeyWhisperMessage.HasBaseKey || !preKeyWhisperMessage.HasIdentityKey || !preKeyWhisperMessage.HasMessage) { throw new InvalidMessageException("Incomplete message."); } this.serialized = serialized; this.registrationId = preKeyWhisperMessage.RegistrationId; this.preKeyId = preKeyWhisperMessage.HasPreKeyId ? new May <uint>(preKeyWhisperMessage.PreKeyId) : May <uint> .NoValue; this.signedPreKeyId = preKeyWhisperMessage.HasSignedPreKeyId ? preKeyWhisperMessage.SignedPreKeyId : uint.MaxValue; // -1 this.baseKey = Curve.decodePoint(preKeyWhisperMessage.BaseKey.ToByteArray(), 0); this.identityKey = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.IdentityKey.ToByteArray(), 0)); this.message = new WhisperMessage(preKeyWhisperMessage.Message.ToByteArray()); } catch (Exception e) { //(InvalidProtocolBufferException | InvalidKeyException | LegacyMessage throw new InvalidMessageException(e.Message); } }
/** * Encrypt a message. * * @param paddedMessage The plaintext message bytes, optionally padded to a constant multiple. * @return A ciphertext message encrypted to the recipient+device tuple. */ public CiphertextMessage encrypt(byte[] paddedMessage) { lock (SESSION_LOCK) { SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress); SessionState sessionState = sessionRecord.getSessionState(); ChainKey chainKey = sessionState.getSenderChainKey(); MessageKeys messageKeys = chainKey.getMessageKeys(); ECPublicKey senderEphemeral = sessionState.getSenderRatchetKey(); uint previousCounter = sessionState.getPreviousCounter(); uint sessionVersion = sessionState.getSessionVersion(); byte[] ciphertextBody = getCiphertext(sessionVersion, messageKeys, paddedMessage); CiphertextMessage ciphertextMessage = new WhisperMessage(sessionVersion, messageKeys.getMacKey(), senderEphemeral, chainKey.getIndex(), previousCounter, ciphertextBody, sessionState.getLocalIdentityKey(), sessionState.getRemoteIdentityKey()); if (sessionState.hasUnacknowledgedPreKeyMessage()) { SessionState.UnacknowledgedPreKeyMessageItems items = sessionState.getUnacknowledgedPreKeyMessageItems(); uint localRegistrationId = sessionState.GetLocalRegistrationId(); ciphertextMessage = new PreKeyWhisperMessage(sessionVersion, localRegistrationId, items.getPreKeyId(), items.getSignedPreKeyId(), items.getBaseKey(), sessionState.getLocalIdentityKey(), (WhisperMessage)ciphertextMessage); } sessionState.setSenderChainKey(chainKey.getNextChainKey()); sessionStore.StoreSession(remoteAddress, sessionRecord); return ciphertextMessage; } }
private byte[] decrypt(SessionState sessionState, WhisperMessage ciphertextMessage) { if (!sessionState.hasSenderChain()) { throw new InvalidMessageException("Uninitialized session!"); } if (ciphertextMessage.getMessageVersion() != sessionState.getSessionVersion()) { throw new InvalidMessageException($"Message version {ciphertextMessage.getMessageVersion()}, but session version {sessionState.getSessionVersion()}"); } uint messageVersion = ciphertextMessage.getMessageVersion(); ECPublicKey theirEphemeral = ciphertextMessage.getSenderRatchetKey(); uint counter = ciphertextMessage.getCounter(); ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral); MessageKeys messageKeys = getOrCreateMessageKeys(sessionState, theirEphemeral, chainKey, counter); /* ciphertextMessage.verifyMac(messageVersion, sessionState.getRemoteIdentityKey(), sessionState.getLocalIdentityKey(), messageKeys.getMacKey());*/ byte[] plaintext = getPlaintext(messageVersion, messageKeys, ciphertextMessage.getBody()); sessionState.clearUnacknowledgedPreKeyMessage(); return plaintext; }
private byte[] decrypt(SessionRecord sessionRecord, WhisperMessage ciphertext) { lock (SESSION_LOCK) { IEnumerator<SessionState> previousStates = sessionRecord.getPreviousSessionStates().GetEnumerator(); //iterator LinkedList<Exception> exceptions = new LinkedList<Exception>(); try { SessionState sessionState = new SessionState(sessionRecord.getSessionState()); byte[] plaintext = decrypt(sessionState, ciphertext); sessionRecord.setState(sessionState); return plaintext; } catch (InvalidMessageException e) { exceptions.AddLast(e); // add (java default behavioir addlast) } while (previousStates.MoveNext()) //hasNext(); { try { SessionState promotedState = new SessionState(previousStates.Current); //.next() byte[] plaintext = decrypt(promotedState, ciphertext); sessionRecord.getPreviousSessionStates().Remove(previousStates.Current); // previousStates.remove() sessionRecord.promoteState(promotedState); return plaintext; } catch (InvalidMessageException e) { exceptions.AddLast(e); } } throw new InvalidMessageException("No valid sessions.", exceptions); } }
/** * Decrypt a message. * * @param ciphertext The {@link WhisperMessage} to decrypt. * @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 The plaintext. * @throws InvalidMessageException if the input is not valid ciphertext. * @throws DuplicateMessageException if the input is a message that has already been received. * @throws LegacyMessageException if the input is a message formatted by a protocol version that * is no longer supported. * @throws NoSessionException if there is no established session for this contact. */ public byte[] decrypt(WhisperMessage ciphertext, DecryptionCallback callback) { lock (SESSION_LOCK) { if (!sessionStore.ContainsSession(remoteAddress)) { throw new NoSessionException($"No session for: {remoteAddress}"); } SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress); byte[] plaintext = decrypt(sessionRecord, ciphertext); callback.handlePlaintext(plaintext); sessionStore.StoreSession(remoteAddress, sessionRecord); return plaintext; } }
/** * Decrypt a message. * * @param ciphertext The {@link WhisperMessage} to decrypt. * * @return The plaintext. * @throws InvalidMessageException if the input is not valid ciphertext. * @throws DuplicateMessageException if the input is a message that has already been received. * @throws LegacyMessageException if the input is a message formatted by a protocol version that * is no longer supported. * @throws NoSessionException if there is no established session for this contact. */ public byte[] decrypt(WhisperMessage ciphertext) { return decrypt(ciphertext, new NullDecryptionCallback()); }