private byte[] DeriveKey(BigInteger key, byte[] hash, char ch, int length) { byte[] result = new byte[length]; SSH2DataWriter wr = new SSH2DataWriter(); wr.WriteBigInteger(key); wr.Write(hash); wr.WriteByte((byte)ch); wr.Write(_sessionID); byte[] h1 = new SHA1CryptoServiceProvider().ComputeHash(wr.ToByteArray()); if (h1.Length >= length) { Array.Copy(h1, 0, result, 0, length); return result; } else { wr = new SSH2DataWriter(); wr.WriteBigInteger(key); wr.Write(_sessionID); wr.Write(h1); byte[] h2 = new SHA1CryptoServiceProvider().ComputeHash(wr.ToByteArray()); if (h1.Length + h2.Length >= length) { Array.Copy(h1, 0, result, 0, h1.Length); Array.Copy(h2, 0, result, h1.Length, length - h1.Length); return result; } else throw new SSHException("necessary key length is too big"); //long key is not supported } }
private byte[] WriteToDataWriter() { SSH2DataWriter wr = new SSH2DataWriter(); wr.WriteString(SSH2Util.PublicKeyAlgorithmName(_hostkey.Algorithm)); if (_hostkey.Algorithm == PublicKeyAlgorithm.RSA) { RSAPublicKey rsa = (RSAPublicKey)_hostkey; wr.WriteBigInteger(rsa.Exponent); wr.WriteBigInteger(rsa.Modulus); } else if (_hostkey.Algorithm == PublicKeyAlgorithm.DSA) { DSAPublicKey dsa = (DSAPublicKey)_hostkey; wr.WriteBigInteger(dsa.P); wr.WriteBigInteger(dsa.Q); wr.WriteBigInteger(dsa.G); wr.WriteBigInteger(dsa.Y); } else throw new SSHException("Host key algorithm is unsupported"); return wr.ToByteArray(); }
private bool ProcessKEXDHREPLY(DataFragment packet) { //Round2 receives response SSH2DataReader re = null; PacketType h; do { re = new SSH2DataReader(packet); h = re.ReadPacketType(); if (h == PacketType.SSH_MSG_KEXDH_REPLY) break; //successfully exit else if (h == PacketType.SSH_MSG_IGNORE || h == PacketType.SSH_MSG_DEBUG) { //continue packet = _connection.ReceivePacket(); } else throw new SSHException(String.Format("KeyExchange response is not KEXDH_REPLY but {0}", h)); } while (true); byte[] key_and_cert = re.ReadString(); BigInteger f = re.ReadMPInt(); byte[] signature = re.ReadString(); Debug.Assert(re.Rest == 0); //Round3 calc hash H SSH2DataWriter wr = new SSH2DataWriter(); _k = f.modPow(_x, DH_PRIME); wr = new SSH2DataWriter(); wr.WriteString(_cInfo._clientVersionString); wr.WriteString(_cInfo._serverVersionString); wr.WriteAsString(_clientKEXINITPayload); wr.WriteAsString(_serverKEXINITPayload); wr.WriteAsString(key_and_cert); wr.WriteBigInteger(_e); wr.WriteBigInteger(f); wr.WriteBigInteger(_k); _hash = new SHA1CryptoServiceProvider().ComputeHash(wr.ToByteArray()); _connection.TraceReceptionEvent(h, "verifying host key"); if (!VerifyHostKey(key_and_cert, signature, _hash)) return false; //Debug.WriteLine("hash="+DebugUtil.DumpByteArray(hash)); if (_sessionID == null) _sessionID = _hash; return true; }
private DataFragment SendKEXDHINIT(Mode mode) { //Round1 computes and sends [e] byte[] sx = new byte[16]; _param.Random.NextBytes(sx); _x = new BigInteger(sx); _e = new BigInteger(2).modPow(_x, DH_PRIME); SSH2DataWriter wr = new SSH2DataWriter(); wr.WritePacketType(PacketType.SSH_MSG_KEXDH_INIT); wr.WriteBigInteger(_e); _status = Status.WAIT_KEXDH_REPLY; TraceTransmissionNegotiation(PacketType.SSH_MSG_KEXDH_INIT, ""); if (mode == Mode.Synchronized) return SynchronizedTransmitRawPayload(wr.ToByteArray()); else { TransmitRawPayload(wr.ToByteArray()); return null; } }
// Tests signature verification using test vectors from NIST CAVP. // http://csrc.nist.gov/groups/STM/cavp/digital-signatures.html internal static void TestSignatureVerification() { using (var reader = new System.IO.StreamReader(@"186-3ecdsatestvectors\SigVer.rsp")) { EllipticCurve curve = null; byte[] msg = null; BigInteger qx = null; BigInteger qy = null; BigInteger r = null; BigInteger s = null; string result = null; int testCount = 0; while (true) { string line = reader.ReadLine(); if (line == null) { break; } var match = System.Text.RegularExpressions.Regex.Match(line, @"\[([-\w]+),(SHA-\d+)\]"); if (match.Success) { string curveName = "nist" + match.Groups[1].Value.ToLowerInvariant().Replace("-", ""); curve = FindByName(curveName); if (curve != null) { using (var hashFunc = ECDSAHashAlgorithmChooser.Choose(curve)) { var hashName = "SHA-" + hashFunc.HashSize.ToString(); if (hashName == match.Groups[2].Value) { Debug.WriteLine("Test " + curve.CurveName); } else { // hash function doesn't match curve = null; } } } msg = null; qx = qy = r = s = null; result = null; testCount = 0; continue; } if (line.StartsWith("Msg = ") && curve != null) { msg = BigIntegerConverter.ParseHex(line.Substring(6).Trim()); continue; } if (line.StartsWith("Qx = ") && curve != null) { qx = new BigInteger(BigIntegerConverter.ParseHex(line.Substring(5).Trim())); continue; } if (line.StartsWith("Qy = ") && curve != null) { qy = new BigInteger(BigIntegerConverter.ParseHex(line.Substring(5).Trim())); continue; } if (line.StartsWith("R = ") && curve != null) { r = new BigInteger(BigIntegerConverter.ParseHex(line.Substring(4).Trim())); continue; } if (line.StartsWith("S = ") && curve != null) { s = new BigInteger(BigIntegerConverter.ParseHex(line.Substring(4).Trim())); continue; } if (line.StartsWith("Result = ") && curve != null) { result = line.Substring(9, 1); if (msg != null && qx != null && qy != null && r != null && s != null) { var pk = new ECDSAPublicKey(curve, new ECPoint(qx, qy)); var buf = new SSH2DataWriter(); buf.WriteBigInteger(r); buf.WriteBigInteger(s); var sig = buf.ToByteArray(); string verRes; try { pk.Verify(sig, msg); verRes = "P"; } catch (VerifyException) { verRes = "F"; } if (verRes != result) { throw new Exception("verification result doesn't match"); } ++testCount; Debug.WriteLine("Pass #{0}", testCount); } msg = null; qx = qy = r = s = null; result = null; } } } }
/// <summary> /// Signing /// </summary> /// <param name="data">data to sign</param> /// <returns>signature blob</returns> public byte[] Sign(byte[] data) { BigInteger order = _curve.Order; byte[] hash = _publicKey.HashForSigning(data, _curve); BigInteger e = new BigInteger(hash); using (var rng = new RNGCryptoServiceProvider()) { BigInteger.ModulusRing nring = new BigInteger.ModulusRing(order); for (int tries = 0; tries < 10; ++tries) { try { ECDSAKeyPair tempKeyPair = _curve.GenerateKeyPair(rng); BigInteger r = tempKeyPair.PublicKeyPoint.X % order; if (r == 0) { continue; } BigInteger k = tempKeyPair.PrivateKey; BigInteger s = nring.Multiply(k.ModInverse(order), e + nring.Multiply(r, _privateKey)); if (s == 0) { continue; } SSH2DataWriter writer = new SSH2DataWriter(); writer.WriteBigInteger(r); writer.WriteBigInteger(s); return writer.ToByteArray(); } catch (Exception ex) { Debug.WriteLine(ex); } } } throw new SSHException(Strings.GetString("FailedSigning")); }
private DataFragment SendKEXDHINIT(Mode mode) { //Round1 computes and sends [e] byte[] sx = new byte[32]; RngManager.GetSecureRng().GetBytes(sx); _x = new BigInteger(sx); _e = new BigInteger(2).modPow(_x, GetDiffieHellmanPrime(_cInfo._kexAlgorithm)); SSH2DataWriter wr = new SSH2DataWriter(); wr.WritePacketType(PacketType.SSH_MSG_KEXDH_INIT); wr.WriteBigInteger(_e); _status = Status.WAIT_KEXDH_REPLY; TraceTransmissionNegotiation(PacketType.SSH_MSG_KEXDH_INIT, ""); if (mode == Mode.Synchronized) return SynchronizedTransmitRawPayload(wr.ToByteArray()); else { TransmitRawPayload(wr.ToByteArray()); return null; } }