How to resolve a 'Bad packet length' error in SSH.NET? - c#

I'm trying to upload files via SFTP, using SSH.NET. SFTPClient.Connect() throws an SshConnectionException with the message, "Bad packet length 1302334341." This is my code:
static void Main()
{
try
{
SftpClient sftp = new SftpClient(server, 22, userID, password);
sftp.Connect();
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
I saw in another discussion that this probably has to do with encryption. I'm using AES, and I have a host key. I don't understand how to enter the encryption, though. Based on that discussion, I was playing with this:
ConnectionInfo connectionInfo = new PasswordConnectionInfo(server, 22, userID, password);
connectionInfo.Encryptions.Clear();
connectionInfo.Encryptions.Add("aes","ssh-rsa 2048 11:22:34:d4:56:d6:78:90:01:22:6b:46:34:54:55:8a")
I know that's not the right set of arguments to pass to Encryptions.Add(), but I'm a little lost with using this library; can you help me figure out how to set the encryption properly (assuming that's the problem)?

Solved, in this discussion. I needed to remove encryptions using
foreach (var d in connectionInfo.Encryptions.Where(p => p.Key != "aes128-cbc").ToList())
{
connectionInfo.Encryptions.Remove(d.Key);
}
substituting in whichever encryption I intend to use

Related

Unable to get Presigned Object URL Using AWS SDK for .NET

I am currently working with S3 and need to extract an S3 resource which has a timeout for streaming, so that the client cannot use the URL after a specific amount of time.
I have already used some code provided in the documentation for "Presigned Object URL Using AWS SDK for .NET".
The code will provide a temporary URL which can be used to download an S3 resource by anyone...but within a specific time limit.
I have also used the Amazon S3 Explorer for Visual Studio, but it doesn't support URL generation for resources embedded with AWSKMS key.
Also tried deleting the KMS Key for the S3 folder, but that is throwing an error.
If there is a possible link for deleting KMS keys can you also include it in your answers.
//Code Start
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using System;
namespace URLDownload
{
public class Class1
{
private const string bucketName = "some-value";
private const string objectKey = "some-value";
// Specify your bucket region (an example region is shown).
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USEast1;
private static IAmazonS3 s3Client;
public static void Main()
{
s3Client = new AmazonS3Client(bucketRegion);
string urlString = GeneratePreSignedURL();
Console.WriteLine(urlString);
Console.Read();
}
static string GeneratePreSignedURL()
{
string urlString = "";
try
{
//ServerSideEncryptionMethod ssem = new ServerSideEncryptionMethod("AWSKMS");
GetPreSignedUrlRequest request1 = new GetPreSignedUrlRequest
{
BucketName = bucketName,
Key = objectKey,
Expires = DateTime.Now.AddMinutes(5),
Verb = 0,
ServerSideEncryptionKeyManagementServiceKeyId = "some-value",
ServerSideEncryptionMethod = ServerSideEncryptionMethod.AWSKMS
};
urlString = s3Client.GetPreSignedURL(request1);
}
catch (AmazonS3Exception e)
{
Console.WriteLine("Error encountered on server. Message:'{0}' when writing an object", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
}
return urlString;
}
}
}
SignatureDoesNotMatch
The request signature we calculated does not match the signature you provided. Check your key and signing method.
AKIA347A6YXQ3XM4JQ7A
This is the error that I am getting when I am trying to access the generated URL and that is probably because the AWSKMS authentication is having some issue.
I see it's been a couple of years, but did have an answer for this one? One thing that your code snippet seems to be missing is V4 signature flag set to true:
AWSConfigsS3.UseSignatureVersion4 = true;
Sources:
https://aws.amazon.com/blogs/developer/generating-amazon-s3-pre-signed-urls-with-sse-part-1/
https://aws.amazon.com/blogs/developer/generating-amazon-s3-pre-signed-urls-with-sse-kms-part-2/
You also need to make sure you're providing x-amz-server-side-encryption and x-amz-server-side-encryption-aws-kms-key-id headers on your upload request

Generate the license key from the unique machine key in C# win forms Setup

I have developed an C# win forms application in Visual Studio 2010 and to provide security to it I am generating a machine dependent key by using systems cpuId, biosId, diskId. It looks like
Now in Setup I am just getting one key input area like below.
and I want to show the machine key which is created for the specific system, above the serial key input area.
My need is that the end user or buyer of the Software call me and give me the machine key and then I will calculate a key using that key and send back to client or buyer.
This is my first setup project so I am totally unaware of this thing. I will really appreciate your humble response.
I like to break your question into two parts
Creating a UI with required fields or controls where user can provide the license key
There are two way to get the user input during the installation,
Creating a windows form with required controls to get the input(You can not open windows form as a modal pop up during the installation)
Creating a .wid file to get the user input(This would be the recommended approach)
Validating the license Key and aborting the installation when invalid key is used
Once you have got the user input during the installation you have to validate it, You can use Installer Class for this.
Install() method example
public override void Install(System.Collections.IDictionary stateSaver)
{
//Invoke the base class method
base.Install(stateSaver);
if (!keyEnteredByUser.Equals(generatedKey))
{
//This would abort the installation
throw new Exception("Invalid Key");
}
}
I think better you should take look in this Article.
In that he have taken the same way to generating the unique key as per the system. And the way to generate the unique key is follows.
public static string GetSystemInfo(string SoftwareName)
{
if (UseProcessorID == true)
SoftwareName += RunQuery("Processor", "ProcessorId");
if (UseBaseBoardProduct == true)
SoftwareName += RunQuery("BaseBoard", "Product");
if (UseBaseBoardManufacturer == true)
SoftwareName += RunQuery("BaseBoard", "Manufacturer");
// See more in source code
SoftwareName = RemoveUseLess(SoftwareName);
if (SoftwareName.Length < 25)
return GetSystemInfo(SoftwareName);
return SoftwareName.Substring(0, 25).ToUpper();
}
private static string RunQuery(string TableName, string MethodName)
{
ManagementObjectSearcher MOS =
new ManagementObjectSearcher("Select * from Win32_" + TableName);
foreach (ManagementObject MO in MOS.Get())
{
try
{
return MO[MethodName].ToString();
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
return "";
}
And following method which describes how to generate the password code which matches the unique key ,
static public string MakePassword(string st, string Identifier)
{
if (Identifier.Length != 3)
throw new ArgumentException("Identifier must be 3 character length");
int[] num = new int[3];
num[0] = Convert.ToInt32(Identifier[0].ToString(), 10);
num[1] = Convert.ToInt32(Identifier[1].ToString(), 10);
num[2] = Convert.ToInt32(Identifier[2].ToString(), 10);
st = Boring(st);
st = InverseByBase(st, num[0]);
st = InverseByBase(st, num[1]);
st = InverseByBase(st, num[2]);
StringBuilder SB = new StringBuilder();
foreach (char ch in st)
{
SB.Append(ChangeChar(ch, num));
}
return SB.ToString();
}
So when the user enters the correct password it will be stored in the user system and the next run it wont ask for the password.
public static void WriteFile(string FilePath, string Data)
{
FileStream fout = new FileStream(FilePath, FileMode.OpenOrCreate,
FileAccess.Write);
TripleDES tdes = new TripleDESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(fout, tdes.CreateEncryptor(key, iv),
CryptoStreamMode.Write);
byte[] d = Encoding.ASCII.GetBytes(Data);
cs.Write(d, 0, d.Length);
cs.WriteByte(0);
cs.Close();
fout.Close();
}
So as you asked when the unique key generated , the user as to call you and read his code after based on the code you can generate the password as by above method .
But my point of view is different, this method is not good to collaborate with user. Its waste of time that user needs to call you for password. Better try some other method where user just need to click the link which makes project as full from trail. Anyway the above method will solve your question, I guess.
I suggest using an approach of symmetric or asymmetric encryption - that is direction you must look in to provide machine-based secret key generation. Look for its model in .NET.
Of course, if you want your application to be much more secured, you'll have to provide an activation server for it with client keyhashes database.

Auth fail error when using SharpSSH

I am trying to connect to a Solaris/Unix server using a C# class to read system information/configuration, memory usage etc.
My requirement is to run the commands on the server from a C# application (as we do with a PuTTY client) and store the response in a string variable for later processing.
After some research, I found out that SharpSSH library can be used to do the same.
When I try to run my code, the following line gives me an Auth Fail exception.
I am confident that the credentials (server name, user name and password) are correct since I am able to log-in from the PuTTY client with the same credentials.
SshStream ssh = new SshStream(servername, username, password);
What am I doing wrong?
The following is the stack trace if it helps!
at Tamir.SharpSsh.jsch.Session.connect(Int32 connectTimeout)
at Tamir.SharpSsh.jsch.Session.connect()
at Tamir.SharpSsh.SshStream..ctor(String host, String username, String password)
After some research, I found a VB code which pointed me to the right direction. It seems that adding an additional event handler for the KeyboardInteractiveAuthenticationMethod helped to solve this. Hope this helps someone else.
void HandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)
{
foreach (AuthenticationPrompt prompt in e.Prompts)
{
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
{
prompt.Response = password;
}
}
}
private bool connectToServer()
{
try
{
KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(username);
PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(username, password);
kauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(HandleKeyEvent);
ConnectionInfo connectionInfo = new ConnectionInfo(serverName, port, username, pauth, kauth);
sshClient = new SshClient(connectionInfo);
sshClient.Connect();
return true;
}
catch (Exception ex)
{
if (null != sshClient && sshClient.IsConnected)
{
sshClient.Disconnect();
}
throw ex;
}
}

SslStream.AuthenticateAsServer exception - The server mode SSL must use a certificate with the associated private key

I am developing a proxy server application similar to CCProxy. Its working fine for HTTP but not HTTPS. Its throwing exception when AuthenticateAsServer() method is called on SslStream object.
I also don't know whether I have supplied proper certificate, I don't know how to create a certificate. I just provided the certificate which came with the code that I downloaded online.
Here is the code:
private static void DoHttpProcessing(TcpClient client)
{
Stream clientStream = client.GetStream();
Stream outStream = clientStream;
SslStream sslStream = null;
StreamReader clientStreamReader = new StreamReader(clientStream);
CacheEntry cacheEntry = null;
MemoryStream cacheStream = null;
if (Server.DumpHeaders || Server.DumpPostData || Server.DumpResponseData)
{
Monitor.TryEnter(_outputLockObj, TimeSpan.FromMilliseconds(-1.0));
}
try
{
//read the first line HTTP command
String httpCmd = clientStreamReader.ReadLine();
if (String.IsNullOrEmpty(httpCmd))
{
clientStreamReader.Close();
clientStream.Close();
return;
}
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0];
String remoteUri = splitBuffer[1];
Version version = new Version(1, 0);
HttpWebRequest webReq;
HttpWebResponse response = null;
if (splitBuffer[0].ToUpper() == "CONNECT")
{
remoteUri = "https://" + splitBuffer[1];
while (!String.IsNullOrEmpty(clientStreamReader.ReadLine())) ;
StreamWriter connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine("HTTP/1.0 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("Proxy-agent: matt-dot-net");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
sslStream = new SslStream(clientStream, false);
try
{
// HERE I RECEIVE EXCEPTION
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
sslStream.Close();
clientStreamReader.Close();
connectStreamWriter.Close();
clientStream.Close();
return;
}//further code goes here...
Also, instead of sslStream.AuthenticateAsServer, if I use ssStream.AuthenticateAsClient method I get AuthenticationException with message "A call to SSPI failed, see inner exception." and InnerException gives message as "The message received was unexpected or badly formatted"
When I am using sslstream.AuthenticateAsServer() method, I need to create certificate for each new HTTPS host and pass it with this method. If I provide the self signed certificate, the request succeeds. But problem is, for how many new HTTPS requests will I keep creating certificates manually and assign it to AuthenticateAsServer()?
For the serverside certificate, most certificates correspond to a FQDN (so server1.localhost.local), although there can be wildcard certs (*.localhost.local). When you use AuthenticateAsClient method, that could be one of two things, 1) The Certificate doesnt have the Extended Key Usage for Client Authentication or 2) you didnt pass the right password for it to read the cert/private key. To get past both these hurdles rather quickly i would suggest creating an OpenSSL CA and then generating a CA and Server Cert. There is tons of documentation on how to do this and should take 30 minutes tops for someone who has never created one before....(Also i would suggest exporting the cert into pkcs12 extension for the CA to be chained in with the Server Cert).

Is there a way to digitally sign a document on Medium Trust hosting?

The hosting server just wont execute:
SignedXml.ComputeSignature();
I thought fromXML and toXML methods required full trust. But this came as a surprise. Now it is impossible to digitally sign any document.
On searching the net I found this:
Using RSA Public Key Encryption in a Shared Web Hosting Environment
Anyone used this before or any other way out?
I was eventually able to develop the online activation system using Bounty Castle security API's.
There is not a direct method available, but the base API can be used to generate a digital signature.
I know this post is old but maybe someone will find it useful:
The solution works with ASP .NET 3.5 in medium trust:
private XmlDocument GetSignedDoc(XmlDocument doc)
{
X509Certificate2 certificate = null;
try
{
certificate = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + licenceFile, licenceFilePass, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
if (certificate == null)
throw new Exception("The certificate i
s null!!!");
}
catch (Exception ex)
{
exception += "X509Certificate2 fail! Did not get certificate " + AppDomain.CurrentDomain.BaseDirectory + licenceFile;
exception += FormatException(ex);
goto SetError;
}
RSACryptoServiceProvider myRSASigner = null;
try
{
myRSASigner = (RSACryptoServiceProvider)certificate.PrivateKey;
if (myRSASigner == null)
{
throw new Exception("No valid cert was found");
}
doc = SignXmlFile(doc, myRSASigner);
catch (Exception ex)
{
exception += "SignXmlFile failed";
exception += FormatException(ex);
goto SetError;
}
}
private static XmlDocument SignXmlFile(XmlDocument doc, RSACryptoServiceProvider myRSA)
{
byte[] sign_this = Encoding.UTF8.GetBytes(doc.InnerXml);
byte[] signature = myRSA.SignData(sign_this, new SHA1CryptoServiceProvider());
string base64_string = Convert.ToBase64String(signature);
XmlElement Signature = doc.CreateElement("Signature");
Signature.AppendChild(doc.CreateTextNode(base64_string));
doc.DocumentElement.AppendChild(doc.ImportNode(Signature, true));
return doc;
}
The authors of the article are basically reinventing the wheel by getting different pieces together in order to get some working code. While their approach should work and you could invent some similar approach yourself (take some code here and there and try to make it work), they confirm (in the history) that there were bugs that were fixed and I assume there can be more bugs there.
JFYI: we offer XML security components which work in limited environments because we have all code written ourselves and included in our assemblies.

Categories