public PreKeyWhisperMessage(UInt32 messageVersion, UInt32 registrationId, Maybe<UInt32> preKeyId, UInt32 signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey, WhisperMessage message) { MessageVersion = messageVersion; RegistrationId = registrationId; PreKeyId = preKeyId; SignedPreKeyId = signedPreKeyId; BaseKey = baseKey; IdentityKey = identityKey; Message = message; var preKeyMessage = new WhisperProtos.PreKeyWhisperMessage { signedPreKeyId = SignedPreKeyId, baseKey = BaseKey.Serialize(), identityKey = IdentityKey.Serialize(), message = Message.Serialize(), registrationId = registrationId }; preKeyId.Do(pKid => preKeyMessage.preKeyId = pKid); byte[] versionBytes = { ByteUtil.IntsToByteHighAndLow(MessageVersion, CURRENT_VERSION) }; byte[] messageBytes; using(var stream = new MemoryStream()) { Serializer.Serialize(stream, preKeyMessage); messageBytes = stream.ToArray(); } _serialized = ByteUtil.Combine(versionBytes, messageBytes); }
public PreKeyWhisperMessage(byte[] serialized) { try { MessageVersion = (UInt32)ByteUtil.HighBitsToUInt(serialized[0]); if(MessageVersion > CiphertextMessage.CURRENT_VERSION) { throw new InvalidVersionException("Unknown version: " + MessageVersion); } WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage; using(var stream = new MemoryStream(serialized)) { preKeyWhisperMessage = Serializer.Deserialize<WhisperProtos.PreKeyWhisperMessage>(stream); } if((MessageVersion == 2 && !preKeyWhisperMessage.preKeyId.HasValue) || (MessageVersion == 3 && !preKeyWhisperMessage.signedPreKeyId.HasValue) || preKeyWhisperMessage.baseKey == null || preKeyWhisperMessage.identityKey == null || preKeyWhisperMessage.message == null) { throw new InvalidMessageException("Incomplete message."); } _serialized = serialized; RegistrationId = preKeyWhisperMessage.registrationId.Value; PreKeyId = preKeyWhisperMessage.preKeyId.Value.ToMaybe(); SignedPreKeyId = preKeyWhisperMessage.signedPreKeyId.Value; //() ? preKeyWhisperMessage.getSignedPreKeyId() : -1; BaseKey = Curve.DecodePoint(preKeyWhisperMessage.baseKey, 0); IdentityKey = new IdentityKey(Curve.DecodePoint(preKeyWhisperMessage.identityKey, 0)); Message = new WhisperMessage(preKeyWhisperMessage.message); } catch(InvalidKeyException e) { throw new InvalidMessageException(e); } catch(LegacyMessageException e) { throw new InvalidMessageException(e); } }
public byte[] Decrypt(WhisperMessage ciphertext, IDecryptionCallback 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; } }
public byte[] Decrypt(WhisperMessage ciphertext) { return Decrypt(ciphertext, new NullDecryptionCallback()); }
private byte[] Decrypt(SessionState sessionState, WhisperMessage ciphertextMessage) { if(!sessionState.HasSenderChain()) { throw new InvalidMessageException("Uninitialized session!"); } if(ciphertextMessage.MessageVersion != sessionState.GetSessionVersion()) { throw new InvalidMessageException(string.Format("Message version {0}, but session version {1}", ciphertextMessage.MessageVersion, sessionState.GetSessionVersion())); } UInt32 messageVersion = ciphertextMessage.MessageVersion; ECPublicKey theirEphemeral = ciphertextMessage.SenderRatchetKey; UInt32 counter = ciphertextMessage.Counter; ChainKey chainKey = GetOrCreateChainKey(sessionState, theirEphemeral); MessageKeys messageKeys = GetOrCreateMessageKeys(sessionState, theirEphemeral, chainKey, counter); ciphertextMessage.VerifyMac(messageVersion, sessionState.GetRemoteIdentityKey(), sessionState.GetLocalIdentityKey(), messageKeys.MacKey); byte[] plaintext = GetPlaintext(messageVersion, messageKeys, ciphertextMessage.Body); sessionState.ClearUnacknowledgedPreKeyMessage(); return plaintext; }
private byte[] Decrypt(SessionRecord sessionRecord, WhisperMessage ciphertext) { lock(SESSION_LOCK) { var previousStates = new List<SessionState>(sessionRecord.PreviousStates); var exceptions = new List<Exception>(); try { var sessionState = new SessionState(sessionRecord.SessionState); byte[] plaintext = Decrypt(sessionState, ciphertext); sessionRecord.SetState(sessionState); return plaintext; } catch(InvalidMessageException e) { exceptions.Add(e); } // TODO: Check~ foreach(var state in previousStates) { try { var promotedState = new SessionState(state); byte[] plainText = Decrypt(promotedState, ciphertext); sessionRecord.PreviousStates.Remove(state); return plainText; } catch(InvalidMessageException e) { exceptions.Add(e); } } throw new InvalidMessageException("No valid sessions.", exceptions); } }
/// <summary> /// Encrypt a message. /// </summary> /// <param name="paddedMessage">The plaintext message bytes, optionally padded to a constant multiple.</param> public CiphertextMessage Encrypt(byte[] paddedMessage) { lock(SESSION_LOCK) { SessionRecord sessionRecord = _sessionStore.LoadSession(_remoteAddress); SessionState sessionState = sessionRecord.SessionState; ChainKey chainKey = sessionState.GetSenderChainKey(); MessageKeys messageKeys = chainKey.GetMessageKeys(); ECPublicKey senderEphemeral = sessionState.SenderRatchetKey; UInt32 previousCounter = sessionState.PreviousCounter; UInt32 sessionVersion = sessionState.GetSessionVersion(); byte[] ciphertextBody = GetCiphertext(sessionVersion, messageKeys, paddedMessage); CiphertextMessage ciphertextMessage = new WhisperMessage(sessionVersion, messageKeys.MacKey, senderEphemeral, chainKey.Index, previousCounter, ciphertextBody, sessionState.GetLocalIdentityKey(), sessionState.GetRemoteIdentityKey()); if(sessionState.HasUnacknowledgedPreKeyMessage()) { SessionState.UnacknowledgedPreKeyMessageItems items = sessionState.GetUnacknowledgedPreKeyMessageItems(); UInt32 localRegistrationId = sessionState.LocalRegistrationId; ciphertextMessage = new PreKeyWhisperMessage(sessionVersion, localRegistrationId, items.PreKeyId, items.SignedPreKeyId, items.BaseKey, sessionState.GetLocalIdentityKey(), (WhisperMessage)ciphertextMessage); } sessionState.SetSenderChainKey (chainKey.GetNextChainKey ()); _sessionStore.StoreSession(_remoteAddress, sessionRecord); return ciphertextMessage; } }