private byte[] CalculateExchangeHash(SequencePool sequencePool, SshConnectionInfo connectionInfo, Packet clientKexInitMsg, Packet serverKexInitMsg, ReadOnlySequence <byte> public_host_key, ECPoint q_c, ECPoint q_s, BigInteger sharedSecret) { /* * string V_C, client's identification string (CR and LF excluded) * string V_S, server's identification string (CR and LF excluded) * string I_C, payload of the client's SSH_MSG_KEXINIT * string I_S, payload of the server's SSH_MSG_KEXINIT * string K_S, server's public host key * string Q_C, client's ephemeral public key octet string * string Q_S, server's ephemeral public key octet string * mpint K, shared secret */ using Sequence sequence = sequencePool.RentSequence(); var writer = new SequenceWriter(sequence); writer.WriteString(connectionInfo.ClientIdentificationString !); writer.WriteString(connectionInfo.ServerIdentificationString !); writer.WriteString(clientKexInitMsg.Payload); writer.WriteString(serverKexInitMsg.Payload); writer.WriteString(public_host_key); writer.WriteString(q_c); writer.WriteString(q_s); writer.WriteMPInt(sharedSecret); using IncrementalHash hash = IncrementalHash.CreateHash(_hashAlgorithmName); foreach (var segment in sequence.AsReadOnlySequence()) { hash.AppendData(segment.Span); } return(hash.GetHashAndReset()); }
private byte[] Hash(SequencePool sequencePool, BigInteger sharedSecret, byte[] exchangeHash, byte c, byte[] sessionId, int hashLength) { // https://tools.ietf.org/html/rfc4253#section-7.2 byte[] hashRv = new byte[hashLength]; int hashOffset = 0; // TODO: handle 'If the key length needed is longer than the output of the HASH' // HASH(K || H || c || session_id) using Sequence sequence = sequencePool.RentSequence(); var writer = new SequenceWriter(sequence); writer.WriteMPInt(sharedSecret); writer.Write(exchangeHash); writer.WriteByte(c); writer.Write(sessionId); using IncrementalHash hash = IncrementalHash.CreateHash(_hashAlgorithmName); foreach (var segment in sequence.AsReadOnlySequence()) { hash.AppendData(segment.Span); } byte[] K1 = hash.GetHashAndReset(); Append(hashRv, K1, ref hashOffset); while (hashOffset != hashRv.Length) { // TODO: handle 'If the key length needed is longer than the output of the HASH' // K3 = HASH(K || H || K1 || K2) throw new NotSupportedException(); } return(hashRv);
public void Transform(Span <byte> prefix, ReadOnlySequence <byte> data, Span <byte> suffix, Sequence output) { var writer = new SequenceWriter(output); writer.Write(prefix); writer.Write(data); writer.Write(suffix); }
public override void AppendPublicKey(ref SequenceWriter writer) { RSAParameters parameters = _rsa.ExportParameters(includePrivateParameters: false); using var innerData = writer.SequencePool.RentSequence(); var innerWriter = new SequenceWriter(innerData); innerWriter.WriteString(AlgorithmNames.SshRsa); innerWriter.WriteMPInt(parameters.Exponent); innerWriter.WriteMPInt(parameters.Modulus); writer.WriteString(innerData.AsReadOnlySequence()); }
private static Packet CreatePublicKeyRequestMessage(SequencePool sequencePool, string userName, byte[] sessionId, PrivateKey privateKey) { /* * byte SSH_MSG_USERAUTH_REQUEST * string user name * string service name * string "publickey" * boolean TRUE * string public key algorithm name * string public key to be used for authentication * string signature */ using var packet = sequencePool.RentPacket(); var writer = packet.GetWriter(); writer.WriteByte(MessageNumber.SSH_MSG_USERAUTH_REQUEST); writer.WriteString(userName); writer.WriteString("ssh-connection"); writer.WriteString("publickey"); writer.WriteBoolean(true); writer.WriteString(privateKey.Format); privateKey.AppendPublicKey(ref writer); { /* * string session identifier * byte SSH_MSG_USERAUTH_REQUEST * string user name * string service name * string "publickey" * boolean TRUE * string public key algorithm name * string public key to be used for authentication */ using var signatureData = sequencePool.RentSequence(); var signatureWriter = new SequenceWriter(signatureData); signatureWriter.WriteString(sessionId); signatureWriter.WriteByte(MessageNumber.SSH_MSG_USERAUTH_REQUEST); signatureWriter.WriteString(userName); signatureWriter.WriteString("ssh-connection"); signatureWriter.WriteString("publickey"); signatureWriter.WriteBoolean(true); signatureWriter.WriteString(privateKey.Format); privateKey.AppendPublicKey(ref signatureWriter); privateKey.AppendSignature(ref writer, signatureData.AsReadOnlySequence()); } return(packet.Move()); }
public override void AppendSignature(ref SequenceWriter writer, ReadOnlySequence <byte> data) { using var innerData = writer.SequencePool.RentSequence(); var innerWriter = new SequenceWriter(innerData); innerWriter.WriteString(AlgorithmNames.SshRsa); int signatureLength = _rsa.KeySize / 8; byte[] signature = new byte[signatureLength]; if (!_rsa.TrySignData(data.ToArray(), signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1, out int bytesWritten) || bytesWritten != signatureLength) { throw new InvalidOperationException("Unable to sign data."); } innerWriter.WriteString(signature); writer.WriteString(innerData.AsReadOnlySequence()); }
public abstract void AppendSignature(ref SequenceWriter writer, ReadOnlySequence <byte> data);
public abstract void AppendPublicKey(ref SequenceWriter writer);