Skip to content

Commit

Permalink
Merge pull request #106 from joemphilips/fix_macaroon_build
Browse files Browse the repository at this point in the history
Fix BouncyCastle test failure for macaroon.
  • Loading branch information
joemphilips authored Jun 9, 2020
2 parents 2d9903f + 416fb3f commit 87489bf
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 261 deletions.
3 changes: 2 additions & 1 deletion src/DotNetLightning.Core/DotNetLightning.Core.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<ProjectReference Condition="'$(BouncyCastle)'!='true'" Include="..\NSec\Experimental\NSec.Experimental.csproj" PrivateAssets="all" />
<ProjectReference Include="..\ResultUtils\ResultUtils.fsproj" PrivateAssets="all" />
<ProjectReference Include="..\InternalBech32Encoder\InternalBech32Encoder.csproj" PrivateAssets="all" />
<ProjectReference Include="..\Macaroons\Macaroons.csproj" PrivateAssets="all" />
<ProjectReference Include="..\Macaroons\Macaroons.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
Expand Down Expand Up @@ -75,6 +75,7 @@
<Compile Include="Payment\PaymentEvents.fs" />
<Compile Include="Payment\Amount.fs" />
<Compile Include="Payment\PaymentRequest.fs" />
<Compile Include="Payment\LSAT\CryptoAlgorithm.fs" />
<Compile Include="Payment\LSAT\Constants.fs" />
<Compile Include="Payment\LSAT\CaveatsExtensions.fs" />
<Compile Include="Payment\LSAT\MacaroonIdentifier.fs" />
Expand Down
77 changes: 77 additions & 0 deletions src/DotNetLightning.Core/Payment/LSAT/CryptoAlgorithm.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
namespace DotNetLightning.Payment.LSAT

open Macaroons
open System
open System.Security.Cryptography
open NBitcoin

#if BouncyCastle
type BouncyCastleCryptoAlgorithm() =
inherit CryptoAlgorithm()
override this.Encrypt(key, plaintext) =
raise <| NotSupportedException("Encryption/Decryption for third party caveats are not supported yet for pure C# build.")

override this.Decrypt(key, cipherText) =
raise <| NotSupportedException("Encryption/Decryption for third party caveats are not supported yet for pure C# build.")

module CryptoAlgorithm =
/// Run this function if function if you want to use third party caveat feature. Otherwise it is not necessary.
/// If you try to add/verify 3rd party caveats without doing this, it will throw Exception.
[<CompiledName("InitMacaroon")>]
let initMacaroon() =
Macaroon.Crypto <- (BouncyCastleCryptoAlgorithm() :> CryptoAlgorithm)

#else
type SecretBox = NSec.Experimental.Sodium.NaclXSalsa20Poly1305
type SecretBoxCryptoAlgorithm(?useRandomNonce: bool) =
inherit CryptoAlgorithm()
let useRandomNonce = Option.defaultValue false useRandomNonce

[<Literal>]
let SECRET_BOX_NONCE_BYTES = 24

let secretBox = SecretBox()

let getNonce () =
let mutable arr = Array.zeroCreate SECRET_BOX_NONCE_BYTES
if useRandomNonce then
arr <- RandomUtils.GetBytes(SECRET_BOX_NONCE_BYTES)
arr

member val UseRandomNonce = useRandomNonce with get, set

override this.Encrypt(key, plainText) =
let n = getNonce()
let nonce = NSec.Cryptography.Nonce(ReadOnlySpan(n), 0)
use encryptionKey =
let keySpan = ReadOnlySpan(key)
let blobF = NSec.Cryptography.KeyBlobFormat.RawSymmetricKey;
NSec.Cryptography.Key.Import(secretBox, keySpan, blobF)
let macAndCipherText = secretBox.Encrypt(encryptionKey, &nonce, ReadOnlySpan(plainText));
let result = Array.zeroCreate (n.Length + macAndCipherText.Length)
Array.blit n 0 result 0 SECRET_BOX_NONCE_BYTES
Array.blit macAndCipherText 0 result n.Length macAndCipherText.Length
result

override this.Decrypt(key, nonceAndMacAndCipherText) =
let nonceBytes = Array.zeroCreate(SECRET_BOX_NONCE_BYTES)
Buffer.BlockCopy(nonceAndMacAndCipherText, 0, nonceBytes, 0,nonceBytes.Length);
let nonce = NSec.Cryptography.Nonce(ReadOnlySpan(nonceBytes), 0);
let macAndCipherText = Array.zeroCreate(nonceAndMacAndCipherText.Length - nonceBytes.Length)
Buffer.BlockCopy(nonceAndMacAndCipherText, nonceBytes.Length, macAndCipherText, 0, macAndCipherText.Length);
let keySpan = new ReadOnlySpan<byte>(key);
let blobF = NSec.Cryptography.KeyBlobFormat.RawSymmetricKey;
use encryptionKey = NSec.Cryptography.Key.Import(secretBox, keySpan, blobF);
match (secretBox.Decrypt(encryptionKey, &nonce, ReadOnlySpan(macAndCipherText))) with
| true, plaintext -> plaintext
| false, _ ->
raise <| CryptographicException("Failed to decode data")

module CryptoAlgorithm =
[<CompiledName("InitMacaroon")>]
/// Run this function if function if you want to use third party caveat feature. Otherwise it is not necessary.
/// If you try to add/verify 3rd party caveats without doing this, it will throw Exception.
let initMacaroon() =
Macaroon.Crypto <- (SecretBoxCryptoAlgorithm() :> CryptoAlgorithm)

#endif
6 changes: 1 addition & 5 deletions src/DotNetLightning.Core/Payment/LSAT/MacaroonIdentifier.fs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
namespace DotNetLightning.Payment.LSAT

open System
open System.Net
open System.Net.Http.Headers
open DotNetLightning.Utils.Primitives
open NBitcoin
open DotNetLightning.Core.Utils.Extensions
open DotNetLightning.Utils
open Macaroons
open NSec.Cryptography
open ResultUtils
open NBitcoin.Crypto

module private Helpers =
Expand Down
15 changes: 15 additions & 0 deletions src/Macaroons/DummyCryptoAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Macaroons
{
public class DummyCryptoAlgorithm : CryptoAlgorithm
{
public override byte[] Encrypt(byte[] key, byte[] plainText)
{
throw new System.NotImplementedException();
}

public override byte[] Decrypt(byte[] key, byte[] cipherText)
{
throw new System.NotImplementedException();
}
}
}
2 changes: 1 addition & 1 deletion src/Macaroons/Macaroon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Macaroons
public class Macaroon
{

public static CryptoAlgorithm Crypto = new SecretBoxCryptoAlgorithm();
public static CryptoAlgorithm Crypto = new DummyCryptoAlgorithm();

public const int MACAROON_HASH_BYTES = 32;
public const int MACAROON_MAX_STRLEN = 32768;
Expand Down
7 changes: 1 addition & 6 deletions src/Macaroons/Macaroons.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\NSec\Cryptography\NSec.Cryptography.csproj" />
<ProjectReference Include="..\NSec\Experimental\NSec.Experimental.csproj" />
</ItemGroup>

<PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NBitcoin" Version="5.0.39" />
<PackageReference Include="NBitcoin" Version="5.0.3" />
</ItemGroup>
</Project>
77 changes: 0 additions & 77 deletions src/Macaroons/SecretBoxCryptoAlgorithm.cs

This file was deleted.

99 changes: 93 additions & 6 deletions tests/DotNetLightning.Core.Tests/LSATTests.fs
Original file line number Diff line number Diff line change
@@ -1,17 +1,104 @@
module DotNetLightning.Tests.LSATTests

open System.Collections.Generic
open System.Collections.Immutable
open System
open System.Linq
open Expecto
open DotNetLightning.Payment.LSAT
open DotNetLightning.Payment.LSAT
open DotNetLightning.Payment.LSAT
open Macaroons
open Macaroons
open ResultUtils

// These tests go through the examples from the tutorial on
// the original libmacaroons GitHub page at https://github.com/rescrv/libmacaroons
[<Tests>]
let macaroonTests =
let Secret = "this is our super secret key; only we should know it";
let Identifier = "we used our secret key";
let Location = "http://mybank/";

let Secret2 = "this is a different super-secret key; never use the same secret twice";
let Identifier2 = "we used our other secret key";
let Location2 = "http://mybank/"
CryptoAlgorithm.initMacaroon()
testList "macaroon sanity tests" [
testCase "can create empty macaroon with signature" <| fun _ ->
let m = Macaroon(Location, Secret, Identifier)
Expect.equal Identifier (m.Identifier.ToString()) ""
Expect.equal Location (m.Location.ToString()) ""
Expect.equal("E3D9E02908526C4C0039AE15114115D97FDD68BF2BA379B342AAF0F617D0552F".ToLowerInvariant()) (m.Signature.ToString()) ""
Expect.equal (0) (m.Caveats.Count) ""
testCase "can Add third party caveat" <| fun _ ->
try
let m = new Macaroon(Location2, Secret2, Identifier2);
m.AddFirstPartyCaveat("account = 3735928559") |> ignore

// - just checking (this should although be covered in other tests) ...
Expect.equal("1434e674ad84fdfdc9bc1aa00785325c8b6d57341fc7ce200ba4680c80786dda") (m.Signature.ToString()) ""

// Act
let caveat_key = "4; guaranteed random by a fair toss of the dice"
// string predicate = "user = Alice";
// # send_to_auth(caveat_key, predicate)
// # identifier = recv_from_auth()
let identifier = "this was how we remind auth of key/pred"

m.AddThirdPartyCaveat("http://auth.mybank/", caveat_key, identifier) |> ignore

// Assert
Expect.equal("d27db2fd1f22760e4c3dae8137e2d8fc1df6c0741c18aed4b97256bf78d1f55c") (m.Signature.ToString()) ""

let expectedStringRepresentation =
[
@"Location = http://mybank/";
@"Identifier = we used our other secret key";
@"CId = account = 3735928559";
@"CId = this was how we remind auth of key/pred";
@" VId = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA027FAuBYhtHwJ58FX6UlVNFtFsGxQHS7uD_w_dedwv4Jjw7UorCREw5rXbRqIKhr";
@" Cl = http://auth.mybank/";
@"Signature = d27db2fd1f22760e4c3dae8137e2d8fc1df6c0741c18aed4b97256bf78d1f55c"
""
]
|> String.concat Environment.NewLine

Expect.equal(expectedStringRepresentation) (m.Inspect()) ""

let thirdPartyCaveats = m.ThirdPartyCaveats.ToList()
Expect.equal 1 (thirdPartyCaveats.Count) ""
Expect.equal "http://auth.mybank/" (thirdPartyCaveats.[0].Cl.ToString()) ""
Expect.equal "this was how we remind auth of key/pred" (thirdPartyCaveats.[0].CId.ToString()) ""
with
| :? NotSupportedException ->
// We do not (yet) support third party caveats in BouncyCastle build.
// So this exception is fine.
()

testCase "Can prepare for request" <| fun _ ->
try
// Arrange
let m = new Macaroon(Location2, Secret2, Identifier2);
m.AddFirstPartyCaveat("account = 3735928559") |> ignore

let caveat_key = "4; guaranteed random by a fair toss of the dice";
let identifier = "this was how we remind auth of key/pred";
m.AddThirdPartyCaveat("http://auth.mybank/", caveat_key, identifier) |> ignore

let d = Macaroon("http://auth.mybank/", caveat_key, identifier)
d.AddFirstPartyCaveat("time < 2015-01-01T00:00") |> ignore

// Act
let dp = m.PrepareForRequest(d)

// Assert
Expect.equal("82a80681f9f32d419af12f6a71787a1bac3ab199df934ed950ddf20c25ac8c65") (d.Signature.ToString()) ""
Expect.equal("2eb01d0dd2b4475330739140188648cf25dda0425ea9f661f1574ca0a9eac54e") (dp.Signature.ToString()) ""
with
| :? NotSupportedException ->
// We do not (yet) support third party caveats in BouncyCastle build.
// So this exception is fine.
()
]

[<Tests>]
let tests =
let lsatTests =
testList "LSAT tests" [
testCase "service decode tests" <| fun _ ->
let r = Service.ParseMany("a:0")
Expand Down
Loading

0 comments on commit 87489bf

Please sign in to comment.