public void TestAddBytes() { BlobBuilder builder = new BlobBuilder(); byte[] value = { 0, 1, 2, 3, 4, 5 }; builder.AddBytes(value); Assert.That(builder.GetBlob(), Is.EqualTo(value)); }
public void TestAddBlob() { BlobBuilder builder = new BlobBuilder(); byte[] blob = { 0, 1, 2, 3, 4, 5 }; builder.AddBlob(blob); byte[] expected = new byte[blob.Length + 4]; Array.Copy(blob.Length.ToBytes(), expected, 4); Array.Copy(blob, 0, expected, 4, blob.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); }
public void TestAddBigInt() { BlobBuilder builder = new BlobBuilder(); BigInteger value = new BigInteger("12398259028592293582039293420948023"); builder.AddBigIntBlob(value); byte[] valueBytes = value.ToByteArrayUnsigned(); //Assert.That(valueBytes[0], Is.EqualTo(0)); byte[] expected = new byte[valueBytes.Length + 4]; Array.Copy(valueBytes.Length.ToBytes(), expected, 4); Array.Copy(valueBytes, 0, expected, 4, valueBytes.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); }
public void SendMessageTest() { // TODO: Need to modify this test so that it does not use PageantAgent const string messageValue = "junk"; var builder = new BlobBuilder (); builder.AddStringBlob(messageValue); var messageBytes = builder.GetBlob(); using (var agent = new PageantAgent()) { var client = new PageantClient(); var reply = client.SendMessage(messageBytes); var replyParser = new BlobParser(reply); var replyHeader = replyParser.ReadHeader(); Assert.That(replyHeader.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); } }
/// <summary> /// Writes aBuiler data to aStream at current position of aStream /// </summary> /// <param name="aStream">Stream to write to</param> /// <param name="aBuilder">BlobBuilder to use</param> public static void WriteBlob(this Stream aStream, BlobBuilder aBuilder) { aStream.Write(aBuilder.GetBlob(), 0, aBuilder.Length); }
public override void Serialize(Stream stream, object obj) { /* check for required parameters */ if (stream == null) { throw new ArgumentNullException("stream"); } if (obj == null) { throw new ArgumentNullException("obj"); } PinnedArray <char> passphrase = null; string ciphername; if (passphrase == null || passphrase.Data.Length == 0) { ciphername = KDFNAME_NONE; } else { ciphername = KDFNAME_BCRYPT; } var builder = new BlobBuilder(); ISshKey sshKey = obj as ISshKey; if (sshKey == null) { throw new ArgumentException("Expected ISshKey", "obj"); } var publicKeyParams = sshKey.GetPublicKeyParameters() as Ed25519PublicKeyParameter; var privateKeyParams = sshKey.GetPrivateKeyParameters() as Ed25519PrivateKeyParameter; /* writing info headers */ builder.AddBytes(Encoding.ASCII.GetBytes(AUTH_MAGIC)); builder.AddStringBlob(ciphername); builder.AddStringBlob(ciphername); //kdfname builder.AddBlob(new byte[0]); // kdfoptions /* writing public key */ builder.AddInt(1); // number of keys N var publicKeyBuilder = new BlobBuilder(); publicKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); publicKeyBuilder.AddBlob(publicKeyParams.Key); builder.AddBlob(publicKeyBuilder.GetBlob()); /* writing private key */ BlobBuilder privateKeyBuilder = new BlobBuilder(); var checkint = new SecureRandom().NextInt(); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); privateKeyBuilder.AddBlob(publicKeyParams.Key); privateKeyBuilder.AddBlob(privateKeyParams.Signature); privateKeyBuilder.AddStringBlob(sshKey.Comment); if (ciphername == KDFNAME_NONE) { /* plain-text */ builder.AddBlob(privateKeyBuilder.GetBlobAsPinnedByteArray().Data); } else { byte[] keydata; using (MD5 md5 = MD5.Create()) { keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data)); } passphrase.Dispose(); } /* writing result to file */ var builderOutput = builder.GetBlobAsPinnedByteArray(); using (var writer = new StreamWriter(stream)) { writer.NewLine = "\n"; writer.WriteLine(MARK_BEGIN); var base64Data = Util.ToBase64(builderOutput.Data); var base64String = Encoding.UTF8.GetString(base64Data); var offset = 0; while (offset < base64String.Length) { const int maxLineLength = 70; if (offset + maxLineLength > base64String.Length) { writer.WriteLine(base64String.Substring(offset)); } else { writer.WriteLine(base64String.Substring(offset, maxLineLength)); } offset += maxLineLength; } writer.WriteLine(MARK_END); } }
public override void Serialize(Stream stream, object obj) { /* check for required parameters */ if (stream == null) { throw new ArgumentNullException("stream"); } if (obj == null) { throw new ArgumentNullException("obj"); } PinnedArray<char> passphrase = null; string ciphername; if (passphrase == null || passphrase.Data.Length == 0) { ciphername = KDFNAME_NONE; } else { ciphername = KDFNAME_BCRYPT; } var builder = new BlobBuilder(); ISshKey sshKey = obj as ISshKey; if (sshKey == null) { throw new ArgumentException("Expected ISshKey", "obj"); } var publicKeyParams = sshKey.GetPublicKeyParameters() as Ed25519PublicKeyParameter; var privateKeyParams = sshKey.GetPrivateKeyParameters() as Ed25519PrivateKeyParameter; /* writing info headers */ builder.AddBytes(Encoding.ASCII.GetBytes(AUTH_MAGIC)); builder.AddStringBlob(ciphername); builder.AddStringBlob(ciphername); //kdfname builder.AddBlob(new byte[0]); // kdfoptions /* writing public key */ builder.AddInt(1); // number of keys N var publicKeyBuilder = new BlobBuilder(); publicKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); publicKeyBuilder.AddBlob(publicKeyParams.Key); builder.AddBlob(publicKeyBuilder.GetBlob()); /* writing private key */ BlobBuilder privateKeyBuilder = new BlobBuilder(); var checkint = new SecureRandom().NextInt(); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); privateKeyBuilder.AddBlob(publicKeyParams.Key); privateKeyBuilder.AddBlob(privateKeyParams.Signature); privateKeyBuilder.AddStringBlob(sshKey.Comment); if (ciphername == KDFNAME_NONE) { /* plain-text */ builder.AddBlob(privateKeyBuilder.GetBlobAsPinnedByteArray().Data); } else { byte[] keydata; using (MD5 md5 = MD5.Create()) { keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data)); } passphrase.Dispose(); } /* writing result to file */ var builderOutput = builder.GetBlobAsPinnedByteArray(); using (var writer = new StreamWriter(stream)) { writer.NewLine = "\n"; writer.WriteLine(MARK_BEGIN); var base64Data = Util.ToBase64(builderOutput.Data); var base64String = Encoding.UTF8.GetString(base64Data); var offset = 0; while (offset < base64String.Length) { const int maxLineLength = 70; if (offset + maxLineLength > base64String.Length) { writer.WriteLine(base64String.Substring(offset)); } else { writer.WriteLine(base64String.Substring(offset, maxLineLength)); } offset += maxLineLength; } writer.WriteLine(MARK_END); } }
/// <summary> /// Gets OpenSsh formatted bytes from public key /// </summary> /// <param name="Algorithm">AsymmetricAlgorithm to convert.</param> /// <returns>byte array containing key information</returns> /// <exception cref="ArgumentException"> /// AsymmetricAlgorithm is not supported /// </exception> /// <remarks> /// Currently only supports RSA and DSA public keys /// </remarks> public static byte[] GetPublicKeyBlob(this ISshKey aKey) { AsymmetricKeyParameter parameters = aKey.GetPublicKeyParameters(); BlobBuilder builder = new BlobBuilder(); if (parameters is RsaKeyParameters) { RsaKeyParameters rsaPublicKeyParameters = (RsaKeyParameters)parameters; if (aKey.Version == SshVersion.SSH1) { builder.AddInt(aKey.Size); builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Exponent); builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Modulus); } else { builder.AddStringBlob(PublicKeyAlgorithm.SSH_RSA.GetIdentifierString()); builder.AddBigIntBlob(rsaPublicKeyParameters.Exponent); builder.AddBigIntBlob(rsaPublicKeyParameters.Modulus); } } else if (parameters is DsaPublicKeyParameters) { DsaPublicKeyParameters dsaParameters = (DsaPublicKeyParameters)parameters; builder.AddStringBlob(PublicKeyAlgorithm.SSH_DSS.GetIdentifierString()); builder.AddBigIntBlob(dsaParameters.Parameters.P); builder.AddBigIntBlob(dsaParameters.Parameters.Q); builder.AddBigIntBlob(dsaParameters.Parameters.G); builder.AddBigIntBlob(dsaParameters.Y); } else if (parameters is ECPublicKeyParameters) { ECPublicKeyParameters ecdsaParameters = (ECPublicKeyParameters)parameters; string algorithm; switch (ecdsaParameters.Parameters.Curve.FieldSize) { case 256: algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP256.GetIdentifierString(); break; case 384: algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP384.GetIdentifierString(); break; case 521: algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP521.GetIdentifierString(); break; default: throw new ArgumentException("Unsupported EC size: " + ecdsaParameters.Parameters.Curve.FieldSize); } builder.AddStringBlob(algorithm); algorithm = algorithm.Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX, string.Empty); builder.AddStringBlob(algorithm); builder.AddBlob(ecdsaParameters.Q.GetEncoded()); } else if (parameters is Ed25519PublicKeyParameter) { builder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); builder.AddBlob(((Ed25519PublicKeyParameter)parameters).Key); } else { throw new ArgumentException(parameters.GetType() + " is not supported"); } byte[] result = builder.GetBlob(); builder.Clear(); return result; }
private static void VerifyIntegrity(FileData fileData) { BlobBuilder builder = new BlobBuilder(); if (fileData.ppkFileVersion != Version.V1) { builder.AddStringBlob(fileData.publicKeyAlgorithm.GetIdentifierString()); builder.AddStringBlob(fileData.privateKeyAlgorithm.GetIdentifierString()); builder.AddBlob(Encoding.GetEncoding(1252).GetBytes(fileData.comment)); builder.AddBlob(fileData.publicKeyBlob); builder.AddInt(fileData.privateKeyBlob.Data.Length); } builder.AddBytes(fileData.privateKeyBlob.Data); byte[] computedHash; SHA1 sha = SHA1.Create(); if (fileData.isHMAC) { HMAC hmac = HMACSHA1.Create(); if (fileData.passphrase != null) { using (PinnedArray<byte> hashData = new PinnedArray<byte>(cMACKeySalt.Length + fileData.passphrase.Length)) { Array.Copy(Encoding.UTF8.GetBytes(cMACKeySalt), hashData.Data, cMACKeySalt.Length); IntPtr passphrasePtr = Marshal.SecureStringToGlobalAllocUnicode(fileData.passphrase); for (int i = 0; i < fileData.passphrase.Length; i++) { int unicodeChar = Marshal.ReadInt16(passphrasePtr + i * 2); byte ansiChar = Util.UnicodeToAnsi(unicodeChar); hashData.Data[cMACKeySalt.Length + i] = ansiChar; Marshal.WriteByte(passphrasePtr, i * 2, 0); } Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr); hmac.Key = sha.ComputeHash(hashData.Data); } } else { hmac.Key = sha.ComputeHash(Encoding.UTF8.GetBytes(cMACKeySalt)); } computedHash = hmac.ComputeHash(builder.GetBlob()); hmac.Clear(); } else { computedHash = sha.ComputeHash(builder.GetBlob()); } sha.Clear(); builder.Clear(); try { int macLength = computedHash.Length; bool failed = false; if (fileData.privateMAC.Length == macLength) { for (int i = 0; i < macLength; i++) { if (fileData.privateMAC[i] != computedHash[i]) { failed = true; break; } } } else { failed = true; } if (failed) { // private key data should start with 3 bytes with value 0 if it was // properly decrypted or does not require decryption if ((fileData.privateKeyBlob.Data[0] == 0) && (fileData.privateKeyBlob.Data[1] == 0) && (fileData.privateKeyBlob.Data[2] == 0)) { // so if they bytes are there, passphrase decrypted properly and // something else is wrong with the file contents throw new PpkFormatterException(PpkFormatterException.PpkErrorType.FileCorrupt); } else { // if the bytes are not zeros, we assume that the data was not // properly decrypted because the passphrase was incorrect. throw new PpkFormatterException(PpkFormatterException.PpkErrorType.BadPassphrase); } } } catch { throw; } finally { Array.Clear(computedHash, 0, computedHash.Length); } }
public void TestAnswerSSH2_AGENTC_ADD_IDENTITY() { Agent agent = new TestAgent(); /* test adding RSA key */ BlobBuilder builder = new BlobBuilder(); RsaPrivateCrtKeyParameters rsaParameters = (RsaPrivateCrtKeyParameters)rsaKey.GetPrivateKeyParameters(); builder.AddStringBlob(rsaKey.Algorithm.GetIdentifierString()); builder.AddBigIntBlob(rsaParameters.Modulus); builder.AddBigIntBlob(rsaParameters.PublicExponent); builder.AddBigIntBlob(rsaParameters.Exponent); builder.AddBigIntBlob(rsaParameters.QInv); builder.AddBigIntBlob(rsaParameters.P); builder.AddBigIntBlob(rsaParameters.Q); builder.AddStringBlob(rsaKey.Comment); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); ISshKey returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.GetPublicKeyParameters(), Is.InstanceOf<RsaKeyParameters>()); Assert.That(returnedKey.GetPrivateKeyParameters(), Is.InstanceOf<RsaKeyParameters>()); Assert.That(returnedKey.Size, Is.EqualTo(rsaKey.Size)); Assert.That(returnedKey.Comment, Is.EqualTo(rsaKey.Comment)); Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(rsaKey.GetMD5Fingerprint())); /* test adding DSA key */ agent = new TestAgent(); builder.Clear(); DsaPublicKeyParameters dsaPublicParameters = (DsaPublicKeyParameters)dsaKey.GetPublicKeyParameters(); DsaPrivateKeyParameters dsaPrivateParameters = (DsaPrivateKeyParameters)dsaKey.GetPrivateKeyParameters(); builder.AddStringBlob(dsaKey.Algorithm.GetIdentifierString()); builder.AddBigIntBlob(dsaPublicParameters.Parameters.P); builder.AddBigIntBlob(dsaPublicParameters.Parameters.Q); builder.AddBigIntBlob(dsaPublicParameters.Parameters.G); builder.AddBigIntBlob(dsaPublicParameters.Y); builder.AddBigIntBlob(dsaPrivateParameters.X); builder.AddStringBlob(dsaKey.Comment); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.GetPublicKeyParameters(), Is.InstanceOf<DsaKeyParameters>()); Assert.That(returnedKey.GetPrivateKeyParameters(), Is.InstanceOf<DsaKeyParameters>()); Assert.That(returnedKey.Size, Is.EqualTo(dsaKey.Size)); Assert.That(returnedKey.Comment, Is.EqualTo(dsaKey.Comment)); Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(dsaKey.GetMD5Fingerprint())); /* test adding ECDSA keys */ List<ISshKey> ecdsaKeysList = new List<ISshKey>(); ecdsaKeysList.Add(ecdsa256Key); ecdsaKeysList.Add(ecdsa384Key); ecdsaKeysList.Add(ecdsa521Key); foreach (ISshKey key in ecdsaKeysList) { agent = new TestAgent(); builder.Clear(); ECPublicKeyParameters ecdsaPublicParameters = (ECPublicKeyParameters)key.GetPublicKeyParameters(); ECPrivateKeyParameters ecdsaPrivateParameters = (ECPrivateKeyParameters)key.GetPrivateKeyParameters(); string ecdsaAlgorithm = key.Algorithm.GetIdentifierString(); builder.AddStringBlob(ecdsaAlgorithm); ecdsaAlgorithm = ecdsaAlgorithm.Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX, string.Empty); builder.AddStringBlob(ecdsaAlgorithm); builder.AddBlob(ecdsaPublicParameters.Q.GetEncoded()); builder.AddBigIntBlob(ecdsaPrivateParameters.D); builder.AddStringBlob(key.Comment); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.GetPublicKeyParameters(), Is.InstanceOf<ECPublicKeyParameters>()); Assert.That(returnedKey.GetPrivateKeyParameters(), Is.InstanceOf<ECPrivateKeyParameters>()); Assert.That(returnedKey.Size, Is.EqualTo(key.Size)); Assert.That(returnedKey.Comment, Is.EqualTo(key.Comment)); Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(key.GetMD5Fingerprint())); Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(0)); } /* test adding key that already is in KeyList does not create duplicate */ int startingCount = agent.GetAllKeys().Count(); Assert.That(startingCount, Is.Not.EqualTo(0)); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); Assert.That(agent.GetAllKeys().Count(), Is.EqualTo(startingCount)); /* test locked => failure */ agent = new TestAgent(); agent.Lock(new byte[0]); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); Assert.That(agent.GetAllKeys().Count, Is.EqualTo(0)); }
public void TestInsertHeader() { BlobBuilder builder = new BlobBuilder(); builder.InsertHeader(Agent.Message.SSH_AGENT_SUCCESS); byte[] expected = { 0, 0, 0, 1, (byte)Agent.Message.SSH_AGENT_SUCCESS }; Assert.That(builder.GetBlob(), Is.EqualTo(expected)); builder = new BlobBuilder(); int value1 = 12345; builder.InsertHeader(Agent.Message.SSH_AGENT_SUCCESS, value1); expected = new byte[9]; Array.Copy((5).ToBytes(), expected, 4); expected[4] = (byte)Agent.Message.SSH_AGENT_SUCCESS; Array.Copy(value1.ToBytes(), 0, expected, 5, 4); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); builder = new BlobBuilder(); byte[] value2 = { 1, 2, 3, 4, 5 }; builder.AddBytes(value2); builder.InsertHeader(Agent.Message.SSH_AGENT_SUCCESS); expected = new byte[5 + value2.Length]; int length = value2.Length + 1; Array.Copy(length.ToBytes(), expected, 4); expected[4] = (byte)Agent.Message.SSH_AGENT_SUCCESS; Array.Copy(value2, 0, expected, 5, value2.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); builder = new BlobBuilder(); builder.AddBytes(value2); builder.InsertHeader(Agent.Message.SSH_AGENT_SUCCESS, value1); expected = new byte[9 + value2.Length]; Array.Copy((5 + value2.Length).ToBytes(), expected, 4); expected[4] = (byte)Agent.Message.SSH_AGENT_SUCCESS; Array.Copy(value1.ToBytes(), 0, expected, 5, 4); Array.Copy(value2, 0, expected, 9, value2.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); }
public void RemoveAllKeys(SshVersion version) { BlobBuilder builder = new BlobBuilder(); ICollection<ISshKey> keys = null; if (KeyRemoved != null) keys = ListKeys(version); switch (version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES); break; default: throw new Exception(cUnsupportedSshVersion); } SendMessageAndCheckSuccess(builder); if (keys != null) { foreach (var key in keys) FireKeyRemoved(key); } }
public ICollection<ISshKey> ListKeys(SshVersion aVersion) { BlobBuilder builder = new BlobBuilder(); switch (aVersion) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_REQUEST_IDENTITIES); break; default: throw new Exception(cUnsupportedSshVersion); } BlobParser replyParser = SendMessage(builder); var keyCollection = new List<ISshKey>(); var header = replyParser.ReadHeader(); switch (aVersion) { case SshVersion.SSH1: if (header.Message != Agent.Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER) { throw new AgentFailureException(); } var ssh1KeyCount = replyParser.ReadInt(); for (var i = 0; i < ssh1KeyCount; i++) { var publicKeyParams = replyParser.ReadSsh1PublicKeyData(true); var comment = replyParser.ReadString(); keyCollection.Add( new SshKey(SshVersion.SSH1, publicKeyParams, null, comment)); } break; case SshVersion.SSH2: if (header.Message != Agent.Message.SSH2_AGENT_IDENTITIES_ANSWER) { throw new AgentFailureException(); } var ssh2KeyCount = replyParser.ReadInt(); for (var i = 0; i < ssh2KeyCount; i++) { var publicKeyBlob = replyParser.ReadBlob(); var publicKeyParser = new BlobParser(publicKeyBlob); var publicKeyParams = publicKeyParser.ReadSsh2PublicKeyData(); var comment = replyParser.ReadString(); keyCollection.Add( new SshKey(SshVersion.SSH2, publicKeyParams, null, comment)); } break; default: throw new Exception(cUnsupportedSshVersion); } return keyCollection; }
public void TestAnswerSSH2_AGENTC_REMOVE_IDENTITY() { Agent agent = new TestAgent(allKeys); BlobBuilder builder = new BlobBuilder(); /* test remove key returns success when key is removed */ builder.AddBlob(rsaKey.GetPublicKeyBlob()); builder.InsertHeader(Agent.Message.SSH2_AGENTC_REMOVE_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); Assert.That(agent.GetAllKeys() .SequenceEqual(allKeys.Where(key => key != rsaKey))); /* test remove key returns failure when key does not exist */ int startCount = agent.GetAllKeys().Count(); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); Assert.That(agent.GetAllKeys().Count(), Is.EqualTo(startCount)); /* test returns failure when locked */ agent.Lock(new byte[0]); startCount = agent.GetAllKeys().Count(); builder.AddBlob(dsaKey.GetPublicKeyBlob()); builder.InsertHeader(Agent.Message.SSH2_AGENTC_REMOVE_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); Assert.That(agent.GetAllKeys().Count(), Is.EqualTo(startCount)); }
public void TestAnswerSSH2_AGENTC_SIGN_REQUEST() { const string signatureData = "this is the data that gets signed"; byte[] signatureDataBytes = Encoding.UTF8.GetBytes(signatureData); BlobBuilder builder = new BlobBuilder(); Agent agent = new TestAgent(allKeys); Agent.BlobHeader header; byte[] signatureBlob; BlobParser signatureParser; string algorithm; byte[] signature; ISigner signer; bool signatureOk; BigInteger r, s; DerSequence seq; /* test signatures */ foreach (ISshKey key in allKeys.Where(key => key.Version == SshVersion.SSH2)) { builder.Clear(); builder.AddBlob(key.GetPublicKeyBlob()); builder.AddStringBlob(signatureData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); /* check that proper response type was received */ header = parser.ReadHeader(); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE)); signatureBlob = parser.ReadBlob(); signatureParser = new BlobParser(signatureBlob); algorithm = signatureParser.ReadString(); Assert.That(algorithm, Is.EqualTo(key.Algorithm.GetIdentifierString())); signature = signatureParser.ReadBlob(); if (key.Algorithm == PublicKeyAlgorithm.SSH_RSA) { Assert.That(signature.Length == key.Size / 8); } else if (key.Algorithm == PublicKeyAlgorithm.SSH_DSS) { Assert.That(signature.Length, Is.EqualTo(40)); r = new BigInteger(1, signature, 0, 20); s = new BigInteger(1, signature, 20, 20); seq = new DerSequence(new DerInteger(r), new DerInteger(s)); signature = seq.GetDerEncoded(); } else if (key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP256 || key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP384 || key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP521) { Assert.That(signature.Length, Is.AtLeast(key.Size / 4 + 8)); Assert.That(signature.Length, Is.AtMost(key.Size / 4 + 10)); BlobParser sigParser = new BlobParser(signature); r = new BigInteger(sigParser.ReadBlob()); s = new BigInteger(sigParser.ReadBlob()); seq = new DerSequence(new DerInteger(r), new DerInteger(s)); signature = seq.GetDerEncoded(); } else if (key.Algorithm == PublicKeyAlgorithm.ED25519) { Assert.That(signature.Length, Is.EqualTo(64)); } signer = key.GetSigner(); signer.Init(false, key.GetPublicKeyParameters()); signer.BlockUpdate(signatureDataBytes, 0, signatureDataBytes.Length); signatureOk = signer.VerifySignature(signature); Assert.That(signatureOk, Is.True, "invalid signature"); Assert.That(header.BlobLength, Is.EqualTo(stream.Position - 4)); } /* test DSA key old signature format */ builder.Clear(); builder.AddBlob(dsaKey.GetPublicKeyBlob()); builder.AddStringBlob(signatureData); builder.AddInt((uint)Agent.SignRequestFlags.SSH_AGENT_OLD_SIGNATURE); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE)); signatureBlob = parser.ReadBlob(); signatureParser = new BlobParser(signatureBlob); signature = signatureParser.ReadBlob(); Assert.That(signature.Length == 40); r = new BigInteger(1, signature, 0, 20); s = new BigInteger(1, signature, 20, 20); seq = new DerSequence(new DerInteger(r), new DerInteger(s)); signature = seq.GetDerEncoded(); signer = dsaKey.GetSigner(); signer.Init(false, dsaKey.GetPublicKeyParameters()); signer.BlockUpdate(signatureDataBytes, 0, signatureDataBytes.Length); signatureOk = signer.VerifySignature(signature); Assert.That(signatureOk, Is.True, "invalid signature"); Assert.That(header.BlobLength, Is.EqualTo(stream.Position - 4)); /* test key not found */ agent = new TestAgent(); builder.Clear(); builder.AddBlob(dsaKey.GetPublicKeyBlob()); builder.AddStringBlob(signatureData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header2 = parser.ReadHeader(); Assert.That(header2.BlobLength, Is.EqualTo(1)); Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); /* test confirm constraint */ agent = new TestAgent(); Agent.KeyConstraint testConstraint = new Agent.KeyConstraint(); testConstraint.Type = Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM; SshKey testKey = dsaKey.Clone(); bool confirmCallbackReturnValue = false; agent.ConfirmUserPermissionCallback = delegate(ISshKey k, Process p) { return confirmCallbackReturnValue; }; testKey.AddConstraint(testConstraint); agent.AddKey(testKey); builder.Clear(); builder.AddBlob(dsaKey.GetPublicKeyBlob()); builder.AddStringBlob(signatureData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header2 = parser.ReadHeader(); Assert.That(header2.BlobLength, Is.EqualTo(1)); Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); confirmCallbackReturnValue = true; PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header2 = parser.ReadHeader(); Assert.That(header2.BlobLength, Is.Not.EqualTo(1)); Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE)); }
public void TestAnswerSSH1_AGENTC_RSA_CHALLENGE() { Agent agent = new TestAgent(allKeys); /* test answering to RSA challenge */ BlobBuilder builder = new BlobBuilder(); RsaPrivateCrtKeyParameters rsaParameters = (RsaPrivateCrtKeyParameters)rsa1Key.GetPrivateKeyParameters(); builder.AddInt(rsa1Key.Size); builder.AddSsh1BigIntBlob(rsaParameters.PublicExponent); builder.AddSsh1BigIntBlob(rsaParameters.Modulus); byte[] decryptedChallenge = new byte[8]; byte[] sessionId = new byte[16]; Random random = new Random(); random.NextBytes(decryptedChallenge); random.NextBytes(sessionId); IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine()); engine.Init(true, rsa1Key.GetPublicKeyParameters()); byte[] encryptedChallenge = engine.ProcessBlock(decryptedChallenge, 0, decryptedChallenge.Length); BigInteger chal = new BigInteger(encryptedChallenge); builder.AddSsh1BigIntBlob(chal); builder.AddBytes(sessionId); builder.AddInt(1); builder.InsertHeader(Agent.Message.SSH1_AGENTC_RSA_CHALLENGE); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header = parser.ReadHeader(); byte[] md5Received = parser.ReadBytes(16); /* check that proper response type was received */ Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH1_AGENT_RSA_RESPONSE)); using (MD5 md5 = MD5.Create()) { byte[] md5Buffer = new byte[48]; decryptedChallenge.CopyTo(md5Buffer, 0); sessionId.CopyTo(md5Buffer, 32); byte[] md5Expected = md5.ComputeHash(md5Buffer); /* check the encrypted challenge was successfully read */ Assert.That(md5Received, Is.EqualTo(md5Expected)); } }
public void TestAnswerSSH2_AGENTC_ADD_ID_CONSTRAINED() { /* most code is shared with SSH2_AGENTC_ADD_IDENTITY, so we just * need to test the differences */ Agent.ConfirmUserPermissionDelegate confirmCallback = delegate(ISshKey k, Process p) { return true; }; Agent agent = new TestAgent(); /* test that no confirmation callback returns failure */ BlobBuilder builder = new BlobBuilder(); RsaPrivateCrtKeyParameters rsaParameters = (RsaPrivateCrtKeyParameters)rsaKey.GetPrivateKeyParameters(); builder.AddStringBlob(rsaKey.Algorithm.GetIdentifierString()); builder.AddBigIntBlob(rsaParameters.Modulus); builder.AddBigIntBlob(rsaParameters.PublicExponent); builder.AddBigIntBlob(rsaParameters.Exponent); builder.AddBigIntBlob(rsaParameters.QInv); builder.AddBigIntBlob(rsaParameters.P); builder.AddBigIntBlob(rsaParameters.Q); builder.AddStringBlob(rsaKey.Comment); //save blob so far so we don't have to repeat later. byte[] commonBlob = builder.GetBlob(); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE)); /* test adding key with confirm constraint */ agent = new TestAgent(); agent.ConfirmUserPermissionCallback = confirmCallback; PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); ISshKey returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(1)); Assert.That(returnedKey.Constraints[0].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM)); Assert.That(returnedKey.Constraints[0].Data, Is.Null); /* test adding key with lifetime constraint */ agent = new TestAgent(); builder.Clear(); builder.AddBytes(commonBlob); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME); builder.AddInt(10); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(1)); Assert.That(returnedKey.Constraints[0].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)); Assert.That(returnedKey.Constraints[0].Data.GetType(), Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME.GetDataType())); Assert.That(returnedKey.Constraints[0].Data, Is.EqualTo(10)); /* test adding key with multiple constraints */ agent = new TestAgent(); agent.ConfirmUserPermissionCallback = confirmCallback; builder.Clear(); builder.AddBytes(commonBlob); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME); builder.AddInt(10); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(2)); Assert.That(returnedKey.Constraints[0].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM)); Assert.That(returnedKey.Constraints[0].Data, Is.Null); Assert.That(returnedKey.Constraints[1].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)); Assert.That(returnedKey.Constraints[1].Data, Is.EqualTo(10)); /* test adding key with multiple constraints in different order */ agent = new TestAgent(); agent.ConfirmUserPermissionCallback = confirmCallback; builder.Clear(); builder.AddBytes(commonBlob); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME); builder.AddInt(10); builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM); builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(2)); Assert.That(returnedKey.Constraints[0].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)); Assert.That(returnedKey.Constraints[0].Data, Is.EqualTo(10)); Assert.That(returnedKey.Constraints[1].Type, Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM)); Assert.That(returnedKey.Constraints[1].Data, Is.Null); }
/// <summary> /// prepares a lock or unlock message with specified password /// </summary> private void PrepareLockMessage(bool aLock, string aPassword) { BlobBuilder builder = new BlobBuilder(); builder.AddStringBlob(aPassword); if (aLock) { builder.InsertHeader(Agent.Message.SSH_AGENTC_LOCK); } else { builder.InsertHeader(Agent.Message.SSH_AGENTC_UNLOCK); } PrepareMessage(builder); }
public void TestAddString() { BlobBuilder builder = new BlobBuilder(); string value = "test string"; builder.AddStringBlob(value); byte[] valueBytes = Encoding.UTF8.GetBytes(value); byte[] expected = new byte[valueBytes.Length + 4]; Array.Copy(valueBytes.Length.ToBytes(), expected, 4); Array.Copy(valueBytes, 0, expected, 4, valueBytes.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); }
public void TestAddInt() { BlobBuilder builder = new BlobBuilder(); UInt32 value = 12345; builder.AddInt(value); Assert.That(builder.GetBlob(), Is.EqualTo(value.ToBytes())); }
public byte[] SignRequest(ISshKey aKey, byte[] aSignData) { BlobBuilder builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); var engine = new Pkcs1Encoding(new RsaEngine()); engine.Init(true /* encrypt */, aKey.GetPublicKeyParameters()); var encryptedData = engine.ProcessBlock(aSignData, 0, aSignData.Length); var challenge = new BigInteger(encryptedData); builder.AddSsh1BigIntBlob(challenge); builder.AddBytes(SessionId); builder.AddInt(1); // response type - must be 1 builder.InsertHeader(Agent.Message.SSH1_AGENTC_RSA_CHALLENGE); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); builder.AddBlob(aSignData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); break; default: throw new Exception(cUnsupportedSshVersion); } BlobParser replyParser = SendMessage(builder); var header = replyParser.ReadHeader(); switch (aKey.Version) { case SshVersion.SSH1: if (header.Message != Agent.Message.SSH1_AGENT_RSA_RESPONSE) { throw new AgentFailureException(); } byte[] response = new byte[16]; for (int i = 0; i < 16; i++) { response[i] = replyParser.ReadByte(); } return response; case SshVersion.SSH2: if (header.Message != Agent.Message.SSH2_AGENT_SIGN_RESPONSE) { throw new AgentFailureException(); } return replyParser.ReadBlob(); default: throw new Exception(cUnsupportedSshVersion); } }
public void TestAnswerSSH1_AGENTC_ADD_RSA_IDENTITY() { Agent agent = new TestAgent(); /* test adding RSA key */ BlobBuilder builder = new BlobBuilder(); RsaPrivateCrtKeyParameters rsaParameters = (RsaPrivateCrtKeyParameters)rsa1Key.GetPrivateKeyParameters(); builder.AddInt(rsa1Key.Size); builder.AddSsh1BigIntBlob(rsaParameters.Modulus); builder.AddSsh1BigIntBlob(rsaParameters.PublicExponent); builder.AddSsh1BigIntBlob(rsaParameters.Exponent); builder.AddSsh1BigIntBlob(rsaParameters.QInv); builder.AddSsh1BigIntBlob(rsaParameters.P); builder.AddSsh1BigIntBlob(rsaParameters.Q); builder.AddStringBlob(rsa1Key.Comment); builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_IDENTITY); PrepareMessage(builder); agent.AnswerMessage(stream); RewindStream(); Agent.BlobHeader header = parser.ReadHeader(); Assert.That(header.BlobLength, Is.EqualTo(1)); Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS)); ISshKey returnedKey = agent.GetAllKeys().First(); Assert.That(returnedKey.GetPublicKeyParameters(), Is.InstanceOf<RsaKeyParameters>()); Assert.That(returnedKey.GetPrivateKeyParameters(), Is.InstanceOf<RsaKeyParameters>()); Assert.That(returnedKey.Size, Is.EqualTo(rsa1Key.Size)); Assert.That(returnedKey.Comment, Is.EqualTo(rsa1Key.Comment)); Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(rsa1Key.GetMD5Fingerprint())); }
public void Unlock(byte[] aPassphrase) { BlobBuilder builder = new BlobBuilder(); if (aPassphrase != null) { builder.AddBlob(aPassphrase); } builder.InsertHeader(Agent.Message.SSH_AGENTC_UNLOCK); SendMessageAndCheckSuccess(builder); }
BlobBuilder CreatePrivateKeyBlob(ISshKey key) { var builder = new BlobBuilder(); switch (key.Version) { case SshVersion.SSH1: var privateKeyParams = key.GetPrivateKeyParameters() as RsaPrivateCrtKeyParameters; builder.AddInt(key.Size); builder.AddSsh1BigIntBlob(privateKeyParams.Modulus); builder.AddSsh1BigIntBlob(privateKeyParams.PublicExponent); builder.AddSsh1BigIntBlob(privateKeyParams.Exponent); builder.AddSsh1BigIntBlob(privateKeyParams.QInv); builder.AddSsh1BigIntBlob(privateKeyParams.Q); builder.AddSsh1BigIntBlob(privateKeyParams.P); break; case SshVersion.SSH2: builder.AddStringBlob(key.Algorithm.GetIdentifierString()); switch (key.Algorithm) { case PublicKeyAlgorithm.SSH_DSS: var dsaPublicKeyParameters = key.GetPublicKeyParameters() as DsaPublicKeyParameters; var dsaPrivateKeyParamters = key.GetPrivateKeyParameters() as DsaPrivateKeyParameters; builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.P); builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.Q); builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.G); builder.AddBigIntBlob(dsaPublicKeyParameters.Y); builder.AddBigIntBlob(dsaPrivateKeyParamters.X); break; case PublicKeyAlgorithm.ECDSA_SHA2_NISTP256: case PublicKeyAlgorithm.ECDSA_SHA2_NISTP384: case PublicKeyAlgorithm.ECDSA_SHA2_NISTP521: var ecdsaPublicKeyParameters = key.GetPublicKeyParameters() as ECPublicKeyParameters; var ecdsaPrivateKeyParameters = key.GetPrivateKeyParameters() as ECPrivateKeyParameters; builder.AddStringBlob(key.Algorithm.GetIdentifierString() .Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX, string.Empty)); builder.AddBlob(ecdsaPublicKeyParameters.Q.GetEncoded()); builder.AddBigIntBlob(ecdsaPrivateKeyParameters.D); break; case PublicKeyAlgorithm.SSH_RSA: var rsaPrivateKeyParameters = key.GetPrivateKeyParameters() as RsaPrivateCrtKeyParameters; builder.AddBigIntBlob(rsaPrivateKeyParameters.Modulus); builder.AddBigIntBlob(rsaPrivateKeyParameters.PublicExponent); builder.AddBigIntBlob(rsaPrivateKeyParameters.Exponent); builder.AddBigIntBlob(rsaPrivateKeyParameters.QInv); builder.AddBigIntBlob(rsaPrivateKeyParameters.P); builder.AddBigIntBlob(rsaPrivateKeyParameters.Q); break; case PublicKeyAlgorithm.ED25519: var ed25519PublicKeyParameters = key.GetPublicKeyParameters() as Ed25519PublicKeyParameter; var ed25519PrivateKeyParameters = key.GetPrivateKeyParameters() as Ed25519PrivateKeyParameter; builder.AddBlob(ed25519PublicKeyParameters.Key); builder.AddBlob(ed25519PrivateKeyParameters.Signature); break; default: throw new Exception("Unsupported algorithm"); } break; default: throw new Exception(cUnsupportedSshVersion); } builder.AddStringBlob(key.Comment); return builder; }
public void TestAddSsh1BigIntBlob() { BlobBuilder builder = new BlobBuilder(); BigInteger value = new BigInteger("12398259028592293582039293420948023"); builder.AddSsh1BigIntBlob(value); byte[] valueBytes = value.ToByteArrayUnsigned(); byte[] expected = new byte[valueBytes.Length + 2]; ushort size = (ushort)(value.BitLength); expected[0] = (byte)((size >> 8) & 0xFF); expected[1] = (byte)(size & 0xFF); Array.Copy(valueBytes, 0, expected, 2, valueBytes.Length); Assert.That(builder.GetBlob(), Is.EqualTo(expected)); }
private BlobBuilder CreatePublicKeyBlob(ISshKey aKey) { var builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); break; } return builder; }
public static byte[] FormatSignature(this ISshKey key, byte[] signature) { AsymmetricKeyParameter publicKey = key.GetPublicKeyParameters(); if (publicKey is DsaPublicKeyParameters || publicKey is ECPublicKeyParameters) { Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(signature); BigInteger r = ((DerInteger)seq[0]).PositiveValue; BigInteger s = ((DerInteger)seq[1]).PositiveValue; BlobBuilder formatedSignature = new BlobBuilder(); if (publicKey is ECPublicKeyParameters) { var bytes = r.ToByteArray().ToList (); while (bytes.Count < 20) bytes.Insert(0, 0); formatedSignature.AddBlob(bytes.ToArray()); bytes = s.ToByteArray().ToList(); while (bytes.Count < 20) bytes.Insert(0, 0); formatedSignature.AddBlob(bytes.ToArray()); } else { var bytes = r.ToByteArrayUnsigned().ToList(); while (bytes.Count < 20) bytes.Insert(0, 0); formatedSignature.AddBytes(bytes.ToArray()); bytes = s.ToByteArrayUnsigned().ToList(); while (bytes.Count < 20) bytes.Insert(0, 0); formatedSignature.AddBytes(bytes.ToArray()); } return formatedSignature.GetBlob(); } else if (publicKey is RsaKeyParameters || publicKey is Ed25519PublicKeyParameter) { return signature; } throw new Exception("Unsupported algorithm"); }
private BlobParser SendMessage(BlobBuilder aBuilder) { byte[] reply; using (var message = aBuilder.GetBlobAsPinnedByteArray()) { reply = SendMessage(message.Data); } try { return new BlobParser(reply); } catch (Exception) { return null; } }
/// <summary> /// Answers the message. /// </summary> /// <param name='messageStream'>Message stream.</param> /// <param name="process">The calling process or <c>null</c> if the process /// could not be obtained.</param> /// <remarks>code based on winpgnt.c from PuTTY source code</remarks> public void AnswerMessage(Stream messageStream, Process process = null) { if (messageStream.CanTimeout) { messageStream.ReadTimeout = 5000; } var messageParser = new BlobParser(messageStream); var responseBuilder = new BlobBuilder(); BlobHeader header; try { header = messageParser.ReadHeader(); if (MessageReceived != null) { var eventArgs = new MessageReceivedEventArgs(header); MessageReceived(this, eventArgs); if (eventArgs.Fail) { throw new Exception (); } } } catch (Exception) { header = new BlobHeader(); header.Message = Message.UNKNOWN; // this will cause the switch statement below to use the default case // which returns an error to the stream. } switch (header.Message) { case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES: /* * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER. */ try { if (header.BlobLength > 1) { // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES // with a string tacked on. We need to read the string from the // stream, but it is not used for anything. messageParser.ReadString (); } var keyList = ListKeys(SshVersion.SSH1); if (FilterKeyListCallback != null) { keyList = FilterKeyListCallback(keyList); } foreach (SshKey key in keyList) { responseBuilder.AddBytes(key.GetPublicKeyBlob()); responseBuilder.AddStringBlob(key.Comment); } responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER, keyList.Count); // TODO may want to check that there is enough room in the message stream break; // succeeded } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH2_AGENTC_REQUEST_IDENTITIES: /* * Reply with SSH2_AGENT_IDENTITIES_ANSWER. */ try { var keyList = ListKeys(SshVersion.SSH2); if (FilterKeyListCallback != null) { keyList = FilterKeyListCallback(keyList); } foreach (SshKey key in keyList) { responseBuilder.AddBlob(key.GetPublicKeyBlob()); responseBuilder.AddStringBlob(key.Comment); } responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER, keyList.Count); // TODO may want to check that there is enough room in the message stream break; // succeeded } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH1_AGENTC_RSA_CHALLENGE: /* * Reply with either SSH1_AGENT_RSA_RESPONSE or * SSH_AGENT_FAILURE, depending on whether we have that key * or not. */ try { //Reading publicKey information var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true); //Searching for Key here var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1 && (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single(); //Reading challenge var encryptedChallenge = messageParser.ReadSsh1BigIntBlob(); var sessionId = messageParser.ReadBytes(16); //Checking responseType field if (messageParser.ReadInt() != 1) { goto default; //responseType !=1 is not longer supported } //Answering to the challenge var engine = new Pkcs1Encoding(new RsaEngine()); engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters()); var decryptedChallenge = engine.ProcessBlock(encryptedChallenge, 0, encryptedChallenge.Length); using (MD5 md5 = MD5.Create()) { var md5Buffer = new byte[48]; decryptedChallenge.CopyTo(md5Buffer, 0); sessionId.CopyTo(md5Buffer, 32); responseBuilder.AddBytes(md5.ComputeHash(md5Buffer)); responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE); break; } } catch (InvalidOperationException) { // this is expected if there is not a matching key } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH2_AGENTC_SIGN_REQUEST: /* * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE, * depending on whether we have that key or not. */ try { var keyBlob = messageParser.ReadBlob(); var reqData = messageParser.ReadBlob(); var flags = new SignRequestFlags(); try { // usually, there are no flags, so parser will throw flags = (SignRequestFlags)messageParser.ReadInt(); } catch { } var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH2 && key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First(); var confirmConstraints = matchingKey.Constraints .Where(constraint => constraint.Type == KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM); if (confirmConstraints.Count() > 0) { if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process)) { goto default; } } /* create signature */ var signKey = matchingKey; var signer = signKey.GetSigner(); var algName = signKey.Algorithm.GetIdentifierString(); signer.Init(true, signKey.GetPrivateKeyParameters()); signer.BlockUpdate(reqData, 0, reqData.Length); byte[] signature = signer.GenerateSignature(); signature = signKey.FormatSignature(signature); BlobBuilder signatureBuilder = new BlobBuilder(); if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE)) { signatureBuilder.AddStringBlob(algName); } signatureBuilder.AddBlob(signature); responseBuilder.AddBlob(signatureBuilder.GetBlob()); responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE); try { KeyUsed(this, new KeyUsedEventArgs(signKey, process)); } catch { } break; // succeeded } catch (InvalidOperationException) { // this is expected if there is not a matching key } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failure case Message.SSH1_AGENTC_ADD_RSA_IDENTITY: case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED: /* * Add to the list and return SSH_AGENT_SUCCESS, or * SSH_AGENT_FAILURE if the key was malformed. */ if (IsLocked) { goto default; } bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED); try { var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false); var keyPair = messageParser.ReadSsh1KeyData(publicKeyParams); SshKey key = new SshKey(SshVersion.SSH1, keyPair); key.Comment = messageParser.ReadString(); key.Source = "External client"; if (ssh1constrained) { while (messageStream.Position < header.BlobLength + 4) { KeyConstraint constraint = new KeyConstraint(); constraint.Type = (KeyConstraintType)messageParser.ReadByte(); if (constraint.Type == KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) { constraint.Data = messageParser.ReadInt(); } key.AddConstraint(constraint); } } AddKey(key); responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; } catch (CallbackNullException) { // this is expected } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH2_AGENTC_ADD_IDENTITY: case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED: /* * Add to the list and return SSH_AGENT_SUCCESS, or * SSH_AGENT_FAILURE if the key was malformed. */ if (IsLocked) { goto default; } bool constrained = (header.Message == Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); try { var publicKeyParams = messageParser.ReadSsh2PublicKeyData(); var keyPair = messageParser.ReadSsh2KeyData(publicKeyParams); SshKey key = new SshKey(SshVersion.SSH2, keyPair); key.Comment = messageParser.ReadString(); key.Source = "External client"; if (constrained) { while (messageStream.Position < header.BlobLength + 4) { KeyConstraint constraint = new KeyConstraint(); constraint.Type = (KeyConstraintType)messageParser.ReadByte(); if (constraint.Type == KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) { constraint.Data = messageParser.ReadInt(); } key.AddConstraint(constraint); } } AddKey(key); responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; // success! } catch (CallbackNullException) { // this is expected } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY: case Message.SSH2_AGENTC_REMOVE_IDENTITY: /* * Remove from the list and return SSH_AGENT_SUCCESS, or * perhaps SSH_AGENT_FAILURE if it wasn't in the list to * start with. */ if (IsLocked) { goto default; } SshVersion removeVersion; byte[] rKeyBlob; if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY) { removeVersion = SshVersion.SSH1; rKeyBlob = messageParser.ReadBytes(header.BlobLength - 1); } else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY) { removeVersion = SshVersion.SSH2; rKeyBlob = messageParser.ReadBlob(); } else { Debug.Fail("Should not get here."); goto default; } try { var matchingKey = mKeyList.Get(removeVersion, rKeyBlob); var startKeyListLength = mKeyList.Count; RemoveKey(matchingKey); // only succeed if key was removed if (mKeyList.Count == startKeyListLength - 1) { responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; //success! } } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES: case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES: /* * Remove all SSH-1 or SSH-2 keys. */ if (IsLocked) { goto default; } SshVersion removeAllVersion; if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES) { removeAllVersion = SshVersion.SSH1; } else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES) { removeAllVersion = SshVersion.SSH2; } else { Debug.Fail("Should not get here."); goto default; } try { RemoveAllKeys(removeAllVersion); responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; //success! } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; // failed case Message.SSH_AGENTC_LOCK: try { var passphrase = new PinnedArray<byte>(messageParser.ReadBlob()); try { Lock(passphrase.Data); } finally { passphrase.Clear(); } if (IsLocked) { responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; } } catch (AgentLockedException) { // This is expected } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; case Message.SSH_AGENTC_UNLOCK: try { var passphrase = new PinnedArray<byte>(messageParser.ReadBlob()); try { Unlock(passphrase.Data); } finally { passphrase.Clear(); } if (!IsLocked) { responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS); break; } } catch (AgentLockedException) { // This is expected } catch (PassphraseException) { // This is expected } catch (Exception ex) { Debug.Fail(ex.ToString()); } goto default; default: responseBuilder.Clear(); responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE); break; } /* write response to stream */ if (messageStream.CanSeek) messageStream.Position = 0; messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length); messageStream.Flush(); }
/// <summary> /// Sends message to remote agent and checks that it returned SSH_AGENT_SUCCESS /// </summary> /// <param name="aBuilder">The message to send</param> /// <exception cref="AgentFailureException"> /// Thrown if agent did not return SSH_AGENT_SUCCESS /// </exception> private void SendMessageAndCheckSuccess(BlobBuilder aBuilder) { var replyParser = SendMessage(aBuilder); var header = replyParser.ReadHeader(); if (header.Message != Agent.Message.SSH_AGENT_SUCCESS) { throw new AgentFailureException(); } }
public override void Serialize(Stream aStream, object aObject) { /* check for required parameters */ if (aStream == null) { throw new ArgumentNullException("aStream"); } if (aObject == null) { throw new ArgumentNullException("aObject"); } PasswordFinder pwFinder = null; if (GetPassphraseCallbackMethod != null) { pwFinder = new PasswordFinder(GetPassphraseCallbackMethod); } PinnedArray<char> passphrase = null; if (pwFinder != null) { passphrase = new PinnedArray<char>(0); passphrase.Data = pwFinder.GetPassword(); } byte cipherType; if (passphrase == null || passphrase.Data.Length == 0) { cipherType = SSH_CIPHER_NONE; } else { cipherType = SSH_CIPHER_3DES; } BlobBuilder builder = new BlobBuilder(); ISshKey sshKey = aObject as ISshKey; RsaKeyParameters publicKeyParams = sshKey.GetPublicKeyParameters() as RsaKeyParameters; RsaPrivateCrtKeyParameters privateKeyParams = sshKey.GetPrivateKeyParameters() as RsaPrivateCrtKeyParameters; /* writing info headers */ builder.AddBytes(Encoding.ASCII.GetBytes(FILE_HEADER_LINE + "\n")); builder.AddByte(0); //end of string builder.AddByte(cipherType); //cipher builder.AddInt(0); //reserved /* writing public key */ builder.AddInt(sshKey.Size); builder.AddSsh1BigIntBlob(publicKeyParams.Modulus); builder.AddSsh1BigIntBlob(publicKeyParams.Exponent); builder.AddStringBlob(sshKey.Comment); /* writing private key */ BlobBuilder privateKeyBuilder = new BlobBuilder(); /* adding some control values */ Random random = new Random(); byte[] resultCheck = new byte[2]; random.NextBytes(resultCheck); privateKeyBuilder.AddByte(resultCheck[0]); privateKeyBuilder.AddByte(resultCheck[1]); privateKeyBuilder.AddByte(resultCheck[0]); privateKeyBuilder.AddByte(resultCheck[1]); privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Exponent); privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.DQ); privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.P); privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Q); if (cipherType == SSH_CIPHER_NONE) { /* plain-text */ builder.AddBytes(privateKeyBuilder.GetBlobAsPinnedByteArray().Data); } else { byte[] keydata; using (MD5 md5 = MD5.Create()) { keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data)); } /* encryption */ DesSsh1Engine desEngine = new DesSsh1Engine(); desEngine.Init(true, new KeyParameter(keydata)); BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(desEngine); byte[] ouputBuffer = bufferedBlockCipher.ProcessBytes( privateKeyBuilder.GetBlobAsPinnedByteArray().Data); builder.AddBytes(ouputBuffer); passphrase.Dispose(); } /* writing result to file */ var builderOutput = builder.GetBlobAsPinnedByteArray(); aStream.Write(builderOutput.Data, 0, builderOutput.Data.Length); aStream.Close(); }
private static void VerifyIntegrity(FileData fileData) { BlobBuilder builder = new BlobBuilder(); if (fileData.ppkFileVersion != Version.V1) { builder.AddStringBlob(fileData.publicKeyAlgorithm.GetIdentifierString()); builder.AddStringBlob(fileData.privateKeyAlgorithm.GetIdentifierString()); builder.AddBlob(Encoding.GetEncoding(1252).GetBytes(fileData.comment)); builder.AddBlob(fileData.publicKeyBlob); builder.AddInt(fileData.privateKeyBlob.Data.Length); } builder.AddBytes(fileData.privateKeyBlob.Data); byte[] computedHash; SHA1 sha = SHA1.Create(); if (fileData.isHMAC) { HMAC hmac = HMACSHA1.Create(); if (fileData.passphrase != null) { using (PinnedArray <byte> hashData = new PinnedArray <byte>(cMACKeySalt.Length + fileData.passphrase.Length)) { Array.Copy(Encoding.UTF8.GetBytes(cMACKeySalt), hashData.Data, cMACKeySalt.Length); IntPtr passphrasePtr = Marshal.SecureStringToGlobalAllocUnicode(fileData.passphrase); for (int i = 0; i < fileData.passphrase.Length; i++) { int unicodeChar = Marshal.ReadInt16(passphrasePtr + i * 2); byte ansiChar = Util.UnicodeToAnsi(unicodeChar); hashData.Data[cMACKeySalt.Length + i] = ansiChar; Marshal.WriteByte(passphrasePtr, i * 2, 0); } Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr); hmac.Key = sha.ComputeHash(hashData.Data); } } else { hmac.Key = sha.ComputeHash(Encoding.UTF8.GetBytes(cMACKeySalt)); } computedHash = hmac.ComputeHash(builder.GetBlob()); hmac.Clear(); } else { computedHash = sha.ComputeHash(builder.GetBlob()); } sha.Clear(); builder.Clear(); try { int macLength = computedHash.Length; bool failed = false; if (fileData.privateMAC.Length == macLength) { for (int i = 0; i < macLength; i++) { if (fileData.privateMAC[i] != computedHash[i]) { failed = true; break; } } } else { failed = true; } if (failed) { // private key data should start with 3 bytes with value 0 if it was // properly decrypted or does not require decryption if ((fileData.privateKeyBlob.Data[0] == 0) && (fileData.privateKeyBlob.Data[1] == 0) && (fileData.privateKeyBlob.Data[2] == 0)) { // so if they bytes are there, passphrase decrypted properly and // something else is wrong with the file contents throw new PpkFormatterException(PpkFormatterException.PpkErrorType.FileCorrupt); } else { // if the bytes are not zeros, we assume that the data was not // properly decrypted because the passphrase was incorrect. throw new PpkFormatterException(PpkFormatterException.PpkErrorType.BadPassphrase); } } } catch { throw; } finally { Array.Clear(computedHash, 0, computedHash.Length); } }