Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion NOnion.Tests/CircuitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ static private CircuitNodeDetail ConvertToCircuitNodeDetail(ServerDescriptorEntr
var fingerprintBytes = Hex.ToByteArray(server.Fingerprint.Value);
var nTorOnionKeyBytes = Base64Util.FromString(server.NTorOnionKey.Value);
var endpoint = IPEndPoint.Parse($"{server.Address.Value}:{server.OnionRouterPort.Value}");
return CircuitNodeDetail.NewCreate(endpoint, nTorOnionKeyBytes, fingerprintBytes);
return CircuitNodeDetail.NewCreate(endpoint,
new NTorOnionKey(nTorOnionKeyBytes),
new IdentityKey(fingerprintBytes));
}

/* It's possible that the router returned by GetRandomFallbackDirectory
Expand Down
2 changes: 1 addition & 1 deletion NOnion.Tests/KeyBlindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class KeyBlindingTests
[Test]
public void CheckBlindedPublicKey()
{
var computed = HiddenServicesCipher.CalculateBlindedPublicKey(blindingFactor, publicKey);
var computed = HiddenServicesCipher.CalculateBlindedPublicKey(blindingFactor, publicKey).ToByteArray();
CollectionAssert.AreEqual(computed, blindedPublicKey);
}
}
Expand Down
4 changes: 2 additions & 2 deletions NOnion.Tests/TorDirectoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ private async Task ReturnRandomRouter()
TorDirectory directory = await TorDirectory.BootstrapAsync(FallbackDirectorySelector.GetRandomFallbackDirectory(), cachePath);
var (endPoint, router) = await directory.GetRouterAsync(RouterType.Normal);
Assert.IsTrue(router.IsCreate);
Assert.IsFalse(((CircuitNodeDetail.Create)router).IdentityKey.All(x => x == 0));
Assert.IsFalse(((CircuitNodeDetail.Create)router).NTorOnionKey.All(x => x == 0));
Assert.IsFalse(((CircuitNodeDetail.Create)router).IdentityKey.ToByteArray().All(x => x == 0));
Assert.IsFalse(((CircuitNodeDetail.Create)router).NTorOnionKey.ToByteArray().All(x => x == 0));
Assert.IsNotNull(((CircuitNodeDetail.Create)router).EndPoint);
Assert.That(endPoint, Is.EqualTo(((CircuitNodeDetail.Create)router).EndPoint));
}
Expand Down
11 changes: 7 additions & 4 deletions NOnion/Cells/Relay/RelayIntroduce.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type RelayIntroduceInnerData =
{
RendezvousCookie: array<byte>
Extensions: List<RelayIntroExtension>
OnionKey: array<byte>
OnionKey: NTorOnionKey
RendezvousLinkSpecifiers: List<LinkSpecifier>
}

Expand Down Expand Up @@ -41,7 +41,8 @@ type RelayIntroduceInnerData =
if onionKeyLength <> Constants.NTorPublicKeyLength then
failwith "Invalid onion key length"

let onionKey = reader.ReadBytes Constants.NTorPublicKeyLength
let onionKey =
reader.ReadBytes Constants.NTorPublicKeyLength |> NTorOnionKey

let rec readLinkSpecifier (n: byte) (state: List<LinkSpecifier>) =
if n = 0uy then
Expand All @@ -62,6 +63,8 @@ type RelayIntroduceInnerData =
}

member self.ToBytes() =
let onionKeyBytes = self.OnionKey.ToByteArray()

Array.concat
[
self.RendezvousCookie
Expand All @@ -70,10 +73,10 @@ type RelayIntroduceInnerData =
|> List.map(fun ext -> ext.ToBytes())
|> Array.concat
Array.singleton 1uy
self.OnionKey.Length
onionKeyBytes.Length
|> uint16
|> IntegerSerialization.FromUInt16ToBigEndianByteArray
self.OnionKey
onionKeyBytes
self.RendezvousLinkSpecifiers.Length |> byte |> Array.singleton
self.RendezvousLinkSpecifiers
|> List.map(fun link -> link.ToBytes())
Expand Down
9 changes: 9 additions & 0 deletions NOnion/Constants.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ module Constants =
[<Literal>]
let KdfLength = 92

[<Literal>]
let IdentityKeyLength = 20

[<Literal>]
let Ed25519PrivateKeyLength = 32

[<Literal>]
let ExpandedEd25519PrivateKeyLength = 64

let internal SupportedProtocolVersion: array<uint16> = [| 3us |]

(*
Expand Down
13 changes: 7 additions & 6 deletions NOnion/Crypto/HiddenServicesCipher.fs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,15 @@ module HiddenServicesCipher =
Ed25519Clamp blindingFactor

match Ed25519.CalculateBlindedPublicKey(publicKey, blindingFactor) with
| true, output -> output
| true, output -> ED25519PublicKey.FromBytes output
| false, _ -> failwith "can't calculate blinded public key"

let CalculateExpandedBlindedPrivateKey
(blindingFactor: array<byte>)
(masterPrivateKey: array<byte>)
=
let expandedMasterPrivateKey = Array.zeroCreate 64
: ExpandedEd25519PrivateKey =
let expandedMasterPrivateKey =
Array.zeroCreate Constants.ExpandedEd25519PrivateKeyLength

let hashEngine = Sha512Digest()
hashEngine.BlockUpdate(masterPrivateKey, 0, masterPrivateKey.Length)
Expand All @@ -112,14 +113,14 @@ module HiddenServicesCipher =
"Derive temporary signing key hash input"
)
with
| true, output -> output
| true, output -> ExpandedEd25519PrivateKey output
| false, _ -> failwith "can't calculate blinded private key"


let BuildBlindedPublicKey
(periodNumber: uint64, periodLength: uint64)
(publicKey: array<byte>)
=
: ED25519PublicKey =
let blindingFactor =
CalculateBlindingFactor periodNumber periodLength publicKey

Expand Down Expand Up @@ -154,7 +155,7 @@ module HiddenServicesCipher =
[
"subcredential" |> Encoding.ASCII.GetBytes
credential
blindedKey
blindedKey.ToByteArray()
]
|> SHA3256

Expand Down
13 changes: 9 additions & 4 deletions NOnion/Directory/HiddenServiceDescriptorDocument.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ open NOnion.Utility

type IntroductionPointEntry =
{
OnionKey: Option<array<byte>>
OnionKey: Option<NTorOnionKey>
AuthKey: Option<Certificate>
EncKey: Option<array<byte>>
EncKeyCert: Option<Certificate>
Expand Down Expand Up @@ -60,7 +60,10 @@ type IntroductionPointEntry =
innerParse
{ state with
OnionKey =
readWord() |> Convert.FromBase64String |> Some
readWord()
|> Convert.FromBase64String
|> NTorOnionKey
|> Some
}
| "enc-key" ->
lines.Dequeue() |> ignore<string>
Expand Down Expand Up @@ -127,9 +130,11 @@ type IntroductionPointEntry =
"HS document (most inner wrapper) is incomplete, missing linkspecifier"

match self.OnionKey with
| Some onionKey ->
| Some nTorOnionKey ->
appendLine(
sprintf "onion-key ntor %s" (Convert.ToBase64String onionKey)
sprintf
"onion-key ntor %s"
(Convert.ToBase64String <| nTorOnionKey.ToByteArray())
)
|> ignore<StringBuilder>
| None ->
Expand Down
8 changes: 4 additions & 4 deletions NOnion/Directory/TorDirectory.fs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ type TorDirectory =
endpoint,
CircuitNodeDetail.Create(
endpoint,
nTorOnionKeyBytes,
fingerprintBytes
NTorOnionKey nTorOnionKeyBytes,
IdentityKey fingerprintBytes
)
}

Expand Down Expand Up @@ -583,7 +583,7 @@ type TorDirectory =
|> Async.StartAsTask

member self.GetResponsibleHiddenServiceDirectories
(blindedPublicKey: array<byte>)
(ED25519PublicKey blindedPublicKey)
(sharedRandomValue: string)
(periodNumber: uint64)
(periodLength: uint64)
Expand Down Expand Up @@ -654,7 +654,7 @@ type TorDirectory =
Array.concat
[
"store-at-idx" |> Encoding.ASCII.GetBytes
blindedPublicKey
blindedPublicKey.GetEncoded()
replicaNum
|> uint64
|> IntegerSerialization.FromUInt64ToBigEndianByteArray
Expand Down
69 changes: 69 additions & 0 deletions NOnion/KeyTypes.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace NOnion

open Org.BouncyCastle.Crypto.Parameters


type ExpandedEd25519PrivateKey(bytes: array<byte>) =
do
if bytes.Length <> Constants.ExpandedEd25519PrivateKeyLength then
failwithf
"Invalid private key (length=%d), %d expected"
bytes.Length
Constants.ExpandedEd25519PrivateKeyLength

member self.ToByteArray() =
bytes

[<RequireQualifiedAccess>]
type Ed25519PrivateKey =
| Normal of Ed25519PrivateKeyParameters
| Expanded of ExpandedEd25519PrivateKey

static member FromBytes(bytes: array<byte>) : Ed25519PrivateKey =
if bytes.Length = Constants.ExpandedEd25519PrivateKeyLength then
Expanded <| ExpandedEd25519PrivateKey bytes
elif bytes.Length = Constants.Ed25519PrivateKeyLength then
Normal <| Ed25519PrivateKeyParameters(bytes, 0)
else
failwithf
"Invalid private key (length=%d), private key should either be %d (standard ed25519) or %d bytes (expanded ed25519 key)"
bytes.Length
Constants.Ed25519PrivateKeyLength
Constants.ExpandedEd25519PrivateKeyLength

member self.ToByteArray() =
match self with
| Normal key -> key.GetEncoded()
| Expanded key -> key.ToByteArray()

type ED25519PublicKey =
| ED25519PublicKey of Ed25519PublicKeyParameters

static member FromBytes(bytes: array<byte>) : ED25519PublicKey =
ED25519PublicKey <| Ed25519PublicKeyParameters(bytes, 0)

member self.ToByteArray() =
match self with
| ED25519PublicKey publicKeyParams -> publicKeyParams.GetEncoded()

type NTorOnionKey(bytes: array<byte>) =
do
if bytes.Length <> Constants.NTorPublicKeyLength then
failwithf
"Invalid onion key length, expected %d, got %d"
Constants.NTorPublicKeyLength
bytes.Length

member self.ToByteArray() =
bytes

type IdentityKey(bytes: array<byte>) =
do
if bytes.Length <> Constants.IdentityKeyLength then
failwithf
"Invalid identity key length, expected %d, got %d"
Constants.IdentityKeyLength
bytes.Length

member self.ToByteArray() =
bytes
1 change: 1 addition & 0 deletions NOnion/NOnion.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Compile Include="RelayIntroduceStatus.fs" />
<Compile Include="Exceptions.fs" />
<Compile Include="HandshakeType.fs" />
<Compile Include="KeyTypes.fs" />
<Compile Include="Utility\EmbeddedResourceUtility.fs" />
<Compile Include="Utility\PemUtility.fs" />
<Compile Include="Utility\FSharpUtil.fs" />
Expand Down
6 changes: 3 additions & 3 deletions NOnion/Network/TorCircuit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ type CircuitNodeDetail =
| FastCreate
| Create of
EndPoint: IPEndPoint *
NTorOnionKey: array<byte> *
IdentityKey: array<byte>
NTorOnionKey: NTorOnionKey *
IdentityKey: IdentityKey
Comment thread
aarani marked this conversation as resolved.
Outdated

member self.GetIdentityKey() =
match self with
Expand Down Expand Up @@ -694,7 +694,7 @@ and TorCircuit
{
LinkSpecifier.Type =
LinkSpecifierType.LegacyIdentity
Data = identityKey
Data = identityKey.ToByteArray()
}
]
HandshakeType = HandshakeType.NTor
Expand Down
6 changes: 3 additions & 3 deletions NOnion/Network/TorGuard.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type TorGuard
(
client: TcpClient,
sslStream: SslStream,
fingerprintOpt: Option<array<byte>>
fingerprintOpt: Option<IdentityKey>
) =
let shutdownToken = new CancellationTokenSource()

Expand Down Expand Up @@ -116,7 +116,7 @@ type TorGuard

static member private InnerNewClient
(ipEndpoint: IPEndPoint)
(fingerprintOpt: Option<array<byte>>)
(fingerprintOpt: Option<IdentityKey>)
=
async {
let tcpClient = new TcpClient()
Expand Down Expand Up @@ -475,7 +475,7 @@ type TorGuard
let sha1 = SHA1.Create()
let hash = sha1.ComputeHash(getPublicKeyBytes idCertificate)

if hash <> fingerprint then
if hash <> fingerprint.ToByteArray() then
raise
<| GuardConnectionFailedException("RSA Identity was invalid")
| None -> ()
Expand Down
11 changes: 6 additions & 5 deletions NOnion/Services/TorServiceClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ type TorServiceClient =
(sprintf
"/tor/hs/%i/%s"
Constants.HiddenServices.Version
((Convert.ToBase64String
blindedPublicKey)))
(Convert.ToBase64String
<| blindedPublicKey.ToByteArray
()))
false

return
Expand Down Expand Up @@ -188,7 +189,7 @@ type TorServiceClient =
let secretInput =
Array.concat
[
blindedPublicKey
blindedPublicKey.ToByteArray()
HiddenServicesCipher.GetSubCredential
(periodNum, periodLength)
publicKey
Expand Down Expand Up @@ -372,7 +373,7 @@ type TorServiceClient =
CircuitNodeDetail.Create(
endpointSpecifier,
introductionPoint.OnionKey.Value,
identityKey
IdentityKey identityKey
)

return
Expand Down Expand Up @@ -433,7 +434,7 @@ type TorServiceClient =
{
LinkSpecifier.Type =
LinkSpecifierType.LegacyIdentity
Data = identityKey
Data = identityKey.ToByteArray()
}
]
}
Expand Down
Loading