public VerificationMessage Deserialize(Omnix.Serialization.RocketPack.RocketPackReader r, int rank) { if (rank > 256) { throw new System.FormatException(); } // Read property count uint propertyCount = r.GetUInt32(); ProfileMessage p_profileMessage = ProfileMessage.Empty; OmniAgreementPublicKey p_agreementPublicKey = OmniAgreementPublicKey.Empty; for (; propertyCount > 0; propertyCount--) { uint id = r.GetUInt32(); switch (id) { case 0: // ProfileMessage { p_profileMessage = ProfileMessage.Formatter.Deserialize(r, rank + 1); break; } case 1: // AgreementPublicKey { p_agreementPublicKey = OmniAgreementPublicKey.Formatter.Deserialize(r, rank + 1); break; } } } return(new VerificationMessage(p_profileMessage, p_agreementPublicKey)); }
private IEnumerable <(ReadOnlyMemory <byte>, string)> GetHashesV1(V1.Internal.ProfileMessage profileMessage, OmniAgreementPublicKey agreementPublicKey, V1.Internal.HashAlgorithm hashAlgorithm) { var results = new Dictionary <ReadOnlyMemory <byte>, string>(); byte[] verificationMessageHash; { var verificationMessage = new V1.Internal.VerificationMessage(profileMessage, agreementPublicKey); if (hashAlgorithm == V1.Internal.HashAlgorithm.Sha2_256) { var hub = new Hub(); verificationMessage.Export(hub.Writer, _bufferPool); verificationMessageHash = Sha2_256.ComputeHash(hub.Reader.GetSequence()); } else { throw new NotSupportedException(nameof(hashAlgorithm)); } } foreach (var password in _passwords) { if (hashAlgorithm.HasFlag(V1.Internal.HashAlgorithm.Sha2_256)) { results.Add(Hmac_Sha2_256.ComputeHash(verificationMessageHash, Sha2_256.ComputeHash(password)), password); } } return(results.Select(item => (item.Key, item.Value))); }
public VerificationMessage(ProfileMessage profileMessage, OmniAgreementPublicKey agreementPublicKey) { if (profileMessage is null) { throw new System.ArgumentNullException("profileMessage"); } if (agreementPublicKey is null) { throw new System.ArgumentNullException("agreementPublicKey"); } this.ProfileMessage = profileMessage; this.AgreementPublicKey = agreementPublicKey; { var __h = new System.HashCode(); if (this.ProfileMessage != default) { __h.Add(this.ProfileMessage.GetHashCode()); } if (this.AgreementPublicKey != default) { __h.Add(this.AgreementPublicKey.GetHashCode()); } __hashCode = __h.ToHashCode(); } }
private async ValueTask HandshakeV1(IConnection connection, CancellationToken token) { V1.Internal.ProfileMessage myProfileMessage; V1.Internal.ProfileMessage?otherProfileMessage = null; { { var sessionId = new byte[32]; _random.GetBytes(sessionId); myProfileMessage = new V1.Internal.ProfileMessage( sessionId, (_passwords.Count == 0) ? V1.Internal.AuthenticationType.None : V1.Internal.AuthenticationType.Password, new[] { V1.Internal.KeyExchangeAlgorithm.EcDh_P521_Sha2_256 }, new[] { V1.Internal.KeyDerivationAlgorithm.Pbkdf2 }, new[] { V1.Internal.CryptoAlgorithm.Aes_256 }, new[] { V1.Internal.HashAlgorithm.Sha2_256 }); } var enqueueTask = connection.EnqueueAsync((bufferWriter) => myProfileMessage.Export(bufferWriter, _bufferPool), token); var dequeueTask = connection.DequeueAsync((sequence) => otherProfileMessage = V1.Internal.ProfileMessage.Import(sequence, _bufferPool), token); await ValueTaskHelper.WhenAll(enqueueTask, dequeueTask); if (otherProfileMessage is null) { throw new NullReferenceException(); } if (myProfileMessage.AuthenticationType != otherProfileMessage.AuthenticationType) { throw new OmniSecureConnectionException("AuthenticationType does not match."); } } var keyExchangeAlgorithm = GetOverlapMaxEnum(myProfileMessage.KeyExchangeAlgorithms, otherProfileMessage.KeyExchangeAlgorithms); var keyDerivationAlgorithm = GetOverlapMaxEnum(myProfileMessage.KeyDerivationAlgorithms, otherProfileMessage.KeyDerivationAlgorithms); var cryptoAlgorithm = GetOverlapMaxEnum(myProfileMessage.CryptoAlgorithms, otherProfileMessage.CryptoAlgorithms); var hashAlgorithm = GetOverlapMaxEnum(myProfileMessage.HashAlgorithms, otherProfileMessage.HashAlgorithms); if (!EnumHelper.IsValid(keyExchangeAlgorithm)) { throw new OmniSecureConnectionException("key exchange algorithm does not match."); } if (!EnumHelper.IsValid(keyDerivationAlgorithm)) { throw new OmniSecureConnectionException("key derivation algorithm does not match."); } if (!EnumHelper.IsValid(cryptoAlgorithm)) { throw new OmniSecureConnectionException("Crypto algorithm does not match."); } if (!EnumHelper.IsValid(hashAlgorithm)) { throw new OmniSecureConnectionException("Hash algorithm does not match."); } ReadOnlyMemory <byte> secret = null; if (keyExchangeAlgorithm.HasFlag(V1.Internal.KeyExchangeAlgorithm.EcDh_P521_Sha2_256)) { var myAgreement = OmniAgreement.Create(OmniAgreementAlgorithmType.EcDh_P521_Sha2_256); OmniAgreementPrivateKey myAgreementPrivateKey; OmniAgreementPublicKey? otherAgreementPublicKey = null; { { myAgreementPrivateKey = myAgreement.GetOmniAgreementPrivateKey(); var enqueueTask = connection.EnqueueAsync((bufferWriter) => myAgreement.GetOmniAgreementPublicKey().Export(bufferWriter, _bufferPool), token); var dequeueTask = connection.DequeueAsync((sequence) => otherAgreementPublicKey = OmniAgreementPublicKey.Import(sequence, _bufferPool), token); await ValueTaskHelper.WhenAll(enqueueTask, dequeueTask); if (otherAgreementPublicKey is null) { throw new NullReferenceException(); } if ((DateTime.UtcNow - otherAgreementPublicKey.CreationTime.ToDateTime()).TotalMinutes > 30) { throw new OmniSecureConnectionException("Agreement public key has Expired."); } } if (_passwords.Count > 0) { V1.Internal.AuthenticationMessage myAuthenticationMessage; V1.Internal.AuthenticationMessage?otherAuthenticationMessage = null; { { var myHashAndPasswordList = this.GetHashesV1(myProfileMessage, myAgreement.GetOmniAgreementPublicKey(), hashAlgorithm).ToList(); RandomProvider.GetThreadRandom().Shuffle(myHashAndPasswordList); myAuthenticationMessage = new V1.Internal.AuthenticationMessage(myHashAndPasswordList.Select(n => n.Item1).ToArray()); } var enqueueTask = connection.EnqueueAsync((bufferWriter) => myAuthenticationMessage.Export(bufferWriter, _bufferPool), token); var dequeueTask = connection.DequeueAsync((sequence) => otherAuthenticationMessage = V1.Internal.AuthenticationMessage.Import(sequence, _bufferPool), token); await ValueTaskHelper.WhenAll(enqueueTask, dequeueTask); if (otherAuthenticationMessage is null) { throw new NullReferenceException(); } var matchedPasswords = new List <string>(); { var equalityComparer = new GenericEqualityComparer <ReadOnlyMemory <byte> >((x, y) => BytesOperations.SequenceEqual(x.Span, y.Span), (x) => Fnv1_32.ComputeHash(x.Span)); var receiveHashes = new HashSet <ReadOnlyMemory <byte> >(otherAuthenticationMessage.Hashes, equalityComparer); foreach (var(hash, password) in this.GetHashesV1(otherProfileMessage, otherAgreementPublicKey, hashAlgorithm)) { if (receiveHashes.Contains(hash)) { matchedPasswords.Add(password); } } } if (matchedPasswords.Count == 0) { throw new OmniSecureConnectionException("Password does not match."); } _matchedPasswords = matchedPasswords.ToArray(); } } } if (hashAlgorithm.HasFlag(V1.Internal.HashAlgorithm.Sha2_256)) { secret = OmniAgreement.GetSecret(otherAgreementPublicKey, myAgreementPrivateKey); } } byte[] myCryptoKey; byte[] otherCryptoKey; byte[] myHmacKey; byte[] otherHmacKey; if (keyDerivationAlgorithm.HasFlag(V1.Internal.KeyDerivationAlgorithm.Pbkdf2)) { byte[] xorSessionId = new byte[Math.Max(myProfileMessage.SessionId.Length, otherProfileMessage.SessionId.Length)]; BytesOperations.Xor(myProfileMessage.SessionId.Span, otherProfileMessage.SessionId.Span, xorSessionId); int cryptoKeyLength = 0; int hmacKeyLength = 0; if (cryptoAlgorithm.HasFlag(V1.Internal.CryptoAlgorithm.Aes_256)) { cryptoKeyLength = 32; } if (hashAlgorithm.HasFlag(V1.Internal.HashAlgorithm.Sha2_256)) { hmacKeyLength = 32; } myCryptoKey = new byte[cryptoKeyLength]; otherCryptoKey = new byte[cryptoKeyLength]; myHmacKey = new byte[hmacKeyLength]; otherHmacKey = new byte[hmacKeyLength]; var kdfResult = new byte[(cryptoKeyLength + hmacKeyLength) * 2]; if (hashAlgorithm.HasFlag(V1.Internal.HashAlgorithm.Sha2_256)) { Pbkdf2_Sha2_256.TryComputeHash(secret.Span, xorSessionId, 1024, kdfResult); } else { throw new NotSupportedException(nameof(keyDerivationAlgorithm)); } using (var stream = new MemoryStream(kdfResult)) { if (_type == OmniSecureConnectionType.Connect) { stream.Read(myCryptoKey, 0, myCryptoKey.Length); stream.Read(otherCryptoKey, 0, otherCryptoKey.Length); stream.Read(myHmacKey, 0, myHmacKey.Length); stream.Read(otherHmacKey, 0, otherHmacKey.Length); } else if (_type == OmniSecureConnectionType.Accept) { stream.Read(otherCryptoKey, 0, otherCryptoKey.Length); stream.Read(myCryptoKey, 0, myCryptoKey.Length); stream.Read(otherHmacKey, 0, otherHmacKey.Length); stream.Read(myHmacKey, 0, myHmacKey.Length); } } } else { throw new NotSupportedException(nameof(keyDerivationAlgorithm)); } _infoV1 = new InfoV1(cryptoAlgorithm, hashAlgorithm, myCryptoKey, otherCryptoKey, myHmacKey, otherHmacKey); }