Skip to content

Commit

Permalink
Fix build on Linux.
Browse files Browse the repository at this point in the history
- Fix mono compiler errors.
- Add unmanaged implementation of argon2 hash.
- Restore legacy .csproj files.
- Add developer scripts and notes.
  • Loading branch information
dlech committed May 9, 2022
1 parent 6ebbb64 commit 98a4a3b
Show file tree
Hide file tree
Showing 35 changed files with 675 additions and 310 deletions.
34 changes: 28 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
name: Test

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
on: [push, pull_request]

jobs:

build:
windows:
runs-on: windows-2022

steps:
Expand All @@ -35,3 +31,29 @@ jobs:
with:
version: 'v0.1.15'
directory: ./coverage

linux:
runs-on: ubuntu-22.04

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Install nuget
run: |
sudo curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/v4.9.4/nuget.exe
echo -e '#!/bin/sh\nexec mono /usr/local/bin/nuget.exe "$@"' | sudo tee /usr/local/bin/nuget
sudo chmod +x /usr/local/bin/nuget
- name: Install depedencies
run: |
sudo apt-add-repository ppa:dlech/keepass2-plugins-beta
sudo apt-get update
sudo apt-get install --no-install-recommends mono-devel libbccrypto-cil libgtk2.0-cil-dev libglade2.0-cil-dev libargon2-dev
./scripts/install-nunit.sh
- name: Build
run: xbuild

- name: Test
run: ./scripts/run-tests-mono.sh
29 changes: 29 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,32 @@ install dependencies.
cd SshAgentLib
./scripts/shell.ps1
nuget restore

## Linux

The info above applies to Windows only. For Linux, only the most recent Ubuntu
LTS is officially supported.

### Dependencies

Nuget is only needed to install NUnit to for building and running the unit tests.
You will need a more recent `nuget` than what is available in the Ubuntu archives.

Then run the following commands:

sudo add-apt-repository ppa:dlech/keepass2-plugins-beta
sudo apt update
sudo apt install mono-devel libbccrypto-cil libgtk2.0-cil-dev libglade2.0-cil-dev libargon2-dev
./scripts/install-nunit.sh

To build the entire project:

xbuild

To build and run unit tests:

./scripts/run-tests-mono.sh

Note: additional arguments for `run-tests-mono.sh` will be passed to `nunit-console.exe`.
This can be used with `--explore` to list test names and with `--test=NAMES`
or `--where=EXPRESSION` to run individual tests.
14 changes: 0 additions & 14 deletions SshAgentLib.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLibTests", "SshAgentLibTests\SshAgentLibTests.csproj", "{4C052A55-5F53-4756-AC2C-103EE602E60F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLib.Ui.Common", "Ui\Common\SshAgentLib.Ui.Common.csproj", "{BB935336-BEB1-4AE2-9929-CF7E6BBA53EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLib.Ui.WinForms", "Ui\WinForms\SshAgentLib.Ui.WinForms.csproj", "{3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLib.Ui.GTK", "Ui\Gtk\SshAgentLib.Ui.GTK.csproj", "{D9797E08-73FA-4F41-AB34-789F1BB68F07}"
Expand All @@ -32,10 +30,6 @@ Global
{4C052A55-5F53-4756-AC2C-103EE602E60F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C052A55-5F53-4756-AC2C-103EE602E60F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C052A55-5F53-4756-AC2C-103EE602E60F}.Release|Any CPU.Build.0 = Release|Any CPU
{BB935336-BEB1-4AE2-9929-CF7E6BBA53EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB935336-BEB1-4AE2-9929-CF7E6BBA53EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB935336-BEB1-4AE2-9929-CF7E6BBA53EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB935336-BEB1-4AE2-9929-CF7E6BBA53EE}.Release|Any CPU.Build.0 = Release|Any CPU
{3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -44,14 +38,6 @@ Global
{D9797E08-73FA-4F41-AB34-789F1BB68F07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9797E08-73FA-4F41-AB34-789F1BB68F07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9797E08-73FA-4F41-AB34-789F1BB68F07}.Release|Any CPU.Build.0 = Release|Any CPU
{71DDF18D-2CA7-46E3-866C-6CC7294E0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71DDF18D-2CA7-46E3-866C-6CC7294E0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71DDF18D-2CA7-46E3-866C-6CC7294E0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71DDF18D-2CA7-46E3-866C-6CC7294E0B69}.Release|Any CPU.Build.0 = Release|Any CPU
{703E9787-06B8-45EB-881B-6251F0AB845E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{703E9787-06B8-45EB-881B-6251F0AB845E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{703E9787-06B8-45EB-881B-6251F0AB845E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{703E9787-06B8-45EB-881B-6251F0AB845E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
9 changes: 6 additions & 3 deletions SshAgentLib/Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,22 @@ public void AddKey(ISshKey key)
// can't add key with confirm constraint if we don't have
// confirm callback
throw new InvalidOperationException(
"cannot add key with confirm constraint when there is no confirm callback");
"cannot add key with confirm constraint when there is no confirm callback"
);
}

if (constraint.Type == KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
{
var lifetime = (uint)constraint.Data * 1000;
var timer = new Timer(lifetime);

void onTimerElapsed(object s, ElapsedEventArgs e)
var onTimerElapsed = default(ElapsedEventHandler);

onTimerElapsed = (s, e) =>
{
timer.Elapsed -= onTimerElapsed;
RemoveKey(key);
}
};

timer.Elapsed += onTimerElapsed;
timer.Start();
Expand Down
4 changes: 2 additions & 2 deletions SshAgentLib/AgentClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ public byte[] SignRequest(ISshKey aKey, byte[] aSignData)

public void Lock(byte[] passphrase)
{
if (passphrase is null)
if (passphrase == null)
{
throw new ArgumentNullException(nameof(passphrase));
}
Expand All @@ -314,7 +314,7 @@ public void Lock(byte[] passphrase)

public void Unlock(byte[] passphrase)
{
if (passphrase is null)
if (passphrase == null)
{
throw new ArgumentNullException(nameof(passphrase));
}
Expand Down
206 changes: 206 additions & 0 deletions SshAgentLib/Crypto/Argon2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 David Lechner <[email protected]>

using System.Security.Cryptography;

using System;
using System.Runtime.InteropServices;

namespace SshAgentLib.Crypto
{
internal static class Argon2
{
public static class KeyDerivation
{
public const string Argon2id = "Argon2id";
public const string Argon2d = "Argon2d";
public const string Argon2i = "Argon2i";
}

public class Parameters
{
internal string Algorithm;
internal int Memory;
internal int Passes;
internal int Parallelism;
internal byte[] Salt;
}

public static DeriveBytes CreateHasher(Parameters parameters, byte[] passphrase)
{
if (parameters == null)
{
throw new ArgumentNullException(nameof(parameters));
}

if (passphrase == null)
{
throw new ArgumentNullException(nameof(passphrase));
}

try
{
// try unmanged hasher first for best performance
return new UnmanagedHasher(parameters, passphrase);
}
catch (DllNotFoundException)
{
// and fall back to managed implementation if unmanaged libargon2 is not found
return CreateManagedHasher(parameters, passphrase);
}
}

private class UnmanagedHasher : DeriveBytes
{
private readonly HashRaw hashRaw;
private readonly Parameters parameters;
private readonly byte[] password;

public UnmanagedHasher(Parameters parameters, byte[] password)
{
// Just using this to throw DllNotFoundException early.
argon2_type2string(0, 0);

switch (parameters.Algorithm)
{
case KeyDerivation.Argon2id:
hashRaw = argon2id_hash_raw;
break;
case KeyDerivation.Argon2d:
hashRaw = argon2d_hash_raw;
break;
case KeyDerivation.Argon2i:
hashRaw = argon2i_hash_raw;
break;
default:
throw new NotSupportedException("unsupported algorithm");
}

this.parameters = parameters;
this.password = password;
}

private delegate int HashRaw(
uint t_cost,
uint m_cost,
uint parallelism,
byte[] pwd,
UIntPtr pwdlen,
byte[] salt,
UIntPtr saltlen,
byte[] hash,
UIntPtr hashlen
);

[DllImport("argon2")]
private static extern IntPtr argon2_type2string(uint type, int uppercase);

[DllImport("argon2")]
private static extern int argon2i_hash_raw(
uint t_cost,
uint m_cost,
uint parallelism,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pwd,
UIntPtr pwdlen,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 6)] byte[] salt,
UIntPtr saltlen,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 8)] byte[] hash,
UIntPtr hashlen
);

[DllImport("argon2")]
private static extern int argon2d_hash_raw(
uint t_cost,
uint m_cost,
uint parallelism,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pwd,
UIntPtr pwdlen,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 6)] byte[] salt,
UIntPtr saltlen,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 8)] byte[] hash,
UIntPtr hashlen
);

[DllImport("argon2")]
private static extern int argon2id_hash_raw(
uint t_cost,
uint m_cost,
uint parallelism,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pwd,
UIntPtr pwdlen,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 6)] byte[] salt,
UIntPtr saltlen,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 8)] byte[] hash,
UIntPtr hashlen
);

[DllImport("argon2")]
private static extern IntPtr argon2_error_message(int error_code);

public override byte[] GetBytes(int cb)
{
var hash = new byte[cb];

var err = hashRaw(
(uint)parameters.Passes,
(uint)parameters.Memory,
(uint)parameters.Parallelism,
password,
(UIntPtr)password.Length,
parameters.Salt,
(UIntPtr)parameters.Salt.Length,
hash,
(UIntPtr)hash.Length
);

if (err != 0)
{
var msg = Marshal.PtrToStringAnsi(argon2_error_message(err));
throw new CryptographicException(msg);
}

return hash;
}

public override void Reset()
{
throw new NotImplementedException();
}
}

#if __MonoCS__
// no debian packaged Argon2 implementation is available
private static DeriveBytes CreateManagedHasher(Parameters parameters, byte[] passphrase)
{
throw new NotImplementedException("managed argon2 not implement, install libargon2");
}
#else
private static DeriveBytes CreateManagedHasher(Parameters parameters, byte[] passphrase)
{
Konscious.Security.Cryptography.Argon2 argon2;

switch (parameters.Algorithm)
{
case KeyDerivation.Argon2id:
argon2 = new Konscious.Security.Cryptography.Argon2id(passphrase);
break;
case KeyDerivation.Argon2d:
argon2 = new Konscious.Security.Cryptography.Argon2d(passphrase);
break;
case KeyDerivation.Argon2i:
argon2 = new Konscious.Security.Cryptography.Argon2i(passphrase);
break;
default:
throw new NotSupportedException("unsupported algorithm");
}

argon2.MemorySize = parameters.Memory;
argon2.Iterations = parameters.Passes;
argon2.DegreeOfParallelism = parameters.Parallelism;
argon2.Salt = parameters.Salt;

return argon2;
}
#endif
}
}
4 changes: 2 additions & 2 deletions SshAgentLib/CygwinSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ void AcceptConnections()
stream.Flush();
stream.Read(buffer, 0, 12);
var pid = BitConverter.ToInt32(buffer, 0);
var gid = BitConverter.ToInt32(buffer, 4);
var uid = BitConverter.ToInt32(buffer, 8);
// var gid = BitConverter.ToInt32(buffer, 4);
// var uid = BitConverter.ToInt32(buffer, 8);
// FIXME: This should be a cygwin pid, not a windows pid
// seems to work fine though
pid = Process.GetCurrentProcess().Id;
Expand Down
4 changes: 2 additions & 2 deletions SshAgentLib/IAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ public static ICollection<ISshKey> GetAllKeys(this IAgent agent)
/// <exception cref="ArgumentNullException"></exception>
public static bool Contains(this IAgent agent, SshPublicKey key)
{
if (agent is null)
if (agent == null)
{
throw new ArgumentNullException(nameof(agent));
}

if (key is null)
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
Expand Down
Loading

0 comments on commit 98a4a3b

Please sign in to comment.