Commit a17b5f3d authored by Jeremy Bokobza's avatar Jeremy Bokobza

Added base classes for integration with tumblebit.

NStratis and NBitcoin are not playing nicely together so as a temporary measure I've brought all the NTumbleBit code as part of our solution and I've replaced the reference to NBitcoin to NStratis. A solution possibly involving extern aliases should be integrated at some point.
parent 4b13ab87
......@@ -23,6 +23,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.TumbleBit.Client", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.Common", "src\Breeze.Common\Breeze.Common.csproj", "{C726817D-9E2F-4DDC-90A4-B6895CF5309B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TumbleBit", "TumbleBit", "{1B724678-2B73-483E-B981-3A6733C2194E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTumbleBit", "src\NTumbleBit\NTumbleBit.csproj", "{29E411B1-5687-43EE-A71B-6CCEC2289129}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -53,6 +57,10 @@ Global
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Release|Any CPU.Build.0 = Release|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -64,5 +72,6 @@ Global
{1B598E33-667F-496D-BC0D-88276E8E7632} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{C726817D-9E2F-4DDC-90A4-B6895CF5309B} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{29E411B1-5687-43EE-A71B-6CCEC2289129} = {1B724678-2B73-483E-B981-3A6733C2194E}
EndGlobalSection
EndGlobal
......@@ -14,6 +14,7 @@
<ItemGroup>
<ProjectReference Include="..\Breeze.Api\Breeze.Api.csproj" />
<ProjectReference Include="..\Breeze.TumbleBit.Client\Breeze.TumbleBit.Client.csproj" />
<ProjectReference Include="..\Breeze.Wallet\Breeze.Wallet.csproj" />
</ItemGroup>
......
using System;
using System.Linq;
using System.Threading;
using Breeze.Api;
using Breeze.TumbleBit;
using Microsoft.Extensions.Logging;
using Stratis.Bitcoin;
using Stratis.Bitcoin.Builder;
......@@ -19,13 +21,22 @@ namespace Breeze.Daemon
Logs.Configure(new LoggerFactory().AddConsole(LogLevel.Trace, false));
NodeSettings nodeSettings = NodeSettings.FromArguments(args);
var node = (FullNode)new FullNodeBuilder()
var fullNodeBuilder = new FullNodeBuilder()
.UseNodeSettings(nodeSettings)
.UseWallet()
.UseBlockNotification()
.UseTransactionNotification()
.UseApi()
.Build();
.UseApi();
// add the tumbler's settings
var tumblerAddress = args.SingleOrDefault(arg => arg.StartsWith("-tumbler-uri="));
if (!string.IsNullOrEmpty(tumblerAddress))
{
tumblerAddress = tumblerAddress.Replace("-tumbler-uri=", string.Empty);
fullNodeBuilder.UseTumbleBit(new Uri(tumblerAddress));
}
var node = (FullNode)fullNodeBuilder.Build();
// start Full Node - this will also start the API
node.Start();
......
......@@ -5,7 +5,7 @@
},
"Breeze.Daemon TestNet": {
"commandName": "Project",
"commandLineArgs": "-testnet"
"commandLineArgs": "-testnet -tumbler-uri=http://localhost:5050"
}
}
}
\ No newline at end of file
......@@ -9,15 +9,24 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<PreBuildEvent></PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;NETSTANDARD1_6</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" />
<PackageReference Include="refit" Version="3.0.1" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.1" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.8-alpha" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Breeze.Common\Breeze.Common.csproj" />
<ProjectReference Include="..\NTumbleBit\NTumbleBit.csproj" />
</ItemGroup>
</Project>
\ No newline at end of file
using Breeze.TumbleBit.Models;
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Breeze.Common.JsonErrors;
using Microsoft.AspNetCore.Mvc;
using Breeze.TumbleBit.Client;
namespace Breeze.TumbleBit.Controllers
{
......@@ -9,15 +14,36 @@ namespace Breeze.TumbleBit.Controllers
[Route("api/v{version:apiVersion}/[controller]")]
public class TumbleBitController : Controller
{
private readonly ITumbleBitManager tumbleBitManager;
public TumbleBitController(ITumbleBitManager tumbleBitManager)
{
this.tumbleBitManager = tumbleBitManager;
}
/// <summary>
/// Connect to a tumbler.
/// </summary>
/// <param name="request">The object containing the parameters used to connect to a tumbler.</param>
[Route("connect")]
[HttpPost]
public IActionResult Connect([FromBody]TumblerConnectionRequest request)
[HttpGet]
public async Task<IActionResult> ConnectAsync()
{
// checks the request is valid
if (!this.ModelState.IsValid)
{
return this.Ok();
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
}
try
{
var tumblerParameters = await this.tumbleBitManager.ConnectToTumblerAsync();
return this.Json(tumblerParameters);
}
catch (Exception e)
{
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, $"An error occured connecting to the tumbler.", e.ToString());
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NTumbleBit.ClassicTumbler;
namespace Breeze.TumbleBit.Client
{
/// <summary>
/// An interface for managing interactions with the TumbleBit service.
/// </summary>
public interface ITumbleBitManager
{
/// <summary>
/// Connects to the tumbler.
/// </summary>
/// <returns></returns>
Task<ClassicTumblerParameters> ConnectToTumblerAsync();
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NTumbleBit;
using NTumbleBit.ClassicTumbler;
using Refit;
namespace Breeze.TumbleBit.Client
{
/// <summary>
/// The tumbler service communicating with the tumbler server.
/// </summary>
public interface ITumblerService
{
/// <summary>
/// Gets the tumbler's parameters.
/// </summary>
/// <returns></returns>
[Get("/api/v1/tumblers/0/parameters")]
Task<ClassicTumblerParameters> GetClassicTumblerParametersAsync();
}
}
using System;
using Breeze.TumbleBit.Client;
using Breeze.TumbleBit.Controllers;
using Stratis.Bitcoin.Builder.Feature;
using Microsoft.Extensions.DependencyInjection;
using Stratis.Bitcoin.Builder;
using Stratis.Bitcoin.Logging;
using Microsoft.Extensions.Logging;
using Serilog;
namespace Breeze.TumbleBit
{
public class TumbleBitFeature : FullNodeFeature
{
public TumbleBitFeature()
{
}
public override void Start()
{
}
public override void Stop()
{
}
}
public static class TumbleBitFeatureExtension
{
public static IFullNodeBuilder UseTumbleBit(this IFullNodeBuilder fullNodeBuilder, Uri serverAddress)
{
fullNodeBuilder.ConfigureFeature(features =>
{
features
.AddFeature<TumbleBitFeature>()
.FeatureServices(services =>
{
services.AddSingleton<ITumbleBitManager>(new TumbleBitManager(serverAddress));
services.AddSingleton<TumbleBitController>();
});
});
return fullNodeBuilder;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NTumbleBit.ClassicTumbler;
using Refit;
using NBitcoin.JsonConverters;
using NTumbleBit.JsonConverters;
namespace Breeze.TumbleBit.Client
{
/// <summary>
/// An implementation of a tumbler manager.
/// </summary>
/// <seealso cref="Breeze.TumbleBit.Client.ITumbleBitManager" />
public class TumbleBitManager : ITumbleBitManager
{
private ITumblerService tumblerService;
public TumbleBitManager(Uri serverAddress)
{
this.InitializeTumblerService(serverAddress);
}
/// <summary>
/// Initializes the tumbler service.
/// </summary>
/// <param name="serverAddress">The server address.</param>
public void InitializeTumblerService(Uri serverAddress)
{
this.tumblerService = RestService.For<ITumblerService>(serverAddress.ToString(),
new RefitSettings
{
JsonSerializerSettings = new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new NetworkJsonConverter(), new RsaKeyJsonConverter(), new UInt256JsonConverter() }
}
});
}
/// <inheritdoc />
public async Task<ClassicTumblerParameters> ConnectToTumblerAsync()
{
return await this.tumblerService.GetClassicTumblerParametersAsync();
}
}
}
using NTumbleBit.BouncyCastle.Math;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NTumbleBit
{
public class BlindFactor
{
public BlindFactor(byte[] v)
{
if(v == null)
throw new ArgumentNullException(nameof(v));
_Value = new BigInteger(1, v);
}
internal BlindFactor(BigInteger v)
{
if(v == null)
throw new ArgumentNullException(nameof(v));
_Value = v;
}
internal BigInteger _Value;
public byte[] ToBytes()
{
return _Value.ToByteArrayUnsigned();
}
}
}
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class Asn1Generator
{
private Stream _out;
protected Asn1Generator(
Stream outStream)
{
_out = outStream;
}
protected Stream Out
{
get
{
return _out;
}
}
public abstract void AddObject(Asn1Encodable obj);
public abstract Stream GetRawOutputStream();
public abstract void Close();
}
}
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal interface Asn1OctetStringParser
: IAsn1Convertible
{
Stream GetOctetStream();
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
internal interface Asn1SequenceParser
: IAsn1Convertible
{
IAsn1Convertible ReadObject();
}
}
using System;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
/**
* ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
* a [n] where n is some number - these are assumed to follow the construction
* rules (as with sequences).
*/
internal abstract class Asn1TaggedObject
: Asn1Object
{
internal int tagNo;
// internal bool empty;
internal bool explicitly;
internal Asn1Encodable obj;
public static Asn1TaggedObject GetInstance(
Asn1TaggedObject obj,
bool explicitly)
{
if(explicitly)
{
return (Asn1TaggedObject)obj.GetObject();
}
throw new ArgumentException("implicitly tagged tagged object");
}
public static Asn1TaggedObject GetInstance(
object obj)
{
if(obj == null || obj is Asn1TaggedObject)
{
return (Asn1TaggedObject)obj;
}
throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, nameof(obj));
}
/**
* @param tagNo the tag number for this object.
* @param obj the tagged object.
*/
protected Asn1TaggedObject(
int tagNo,
Asn1Encodable obj)
{
explicitly = true;
this.tagNo = tagNo;
this.obj = obj;
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
Asn1TaggedObject other = asn1Object as Asn1TaggedObject;
if(other == null)
return false;
return tagNo == other.tagNo
// && this.empty == other.empty
&& explicitly == other.explicitly // TODO Should this be part of equality?
&& Platform.Equals(GetObject(), other.GetObject());
}
protected override int Asn1GetHashCode()
{
int code = tagNo.GetHashCode();
// TODO: actually this is wrong - the problem is that a re-encoded
// object may end up with a different hashCode due to implicit
// tagging. As implicit tagging is ambiguous if a sequence is involved
// it seems the only correct method for both equals and hashCode is to
// compare the encodings...
// code ^= explicitly.GetHashCode();
if(obj != null)
{
code ^= obj.GetHashCode();
}
return code;
}
public int TagNo
{
get
{
return tagNo;
}
}
/**
* return whether or not the object may be explicitly tagged.
* <p>
* Note: if the object has been read from an input stream, the only
* time you can be sure if isExplicit is returning the true state of
* affairs is if it returns false. An implicitly tagged object may appear
* to be explicitly tagged, so you need to understand the context under
* which the reading was done as well, see GetObject below.</p>
*/
public bool IsExplicit()
{
return explicitly;
}
public bool IsEmpty()
{
return false; //empty;
}
/**
* return whatever was following the tag.
* <p>
* Note: tagged objects are generally context dependent if you're
* trying to extract a tagged object you should be going via the
* appropriate GetInstance method.</p>
*/
public Asn1Object GetObject()
{
if(obj != null)
{
return obj.ToAsn1Object();
}
return null;
}
public override string ToString()
{
return "[" + tagNo + "]" + obj;
}
}
}
\ No newline at end of file
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class Asn1Encodable
: IAsn1Convertible
{
public const string Der = "DER";
public const string Ber = "BER";
public sealed override int GetHashCode()
{
return ToAsn1Object().CallAsn1GetHashCode();
}
public sealed override bool Equals(
object obj)
{
if(obj == this)
return true;
IAsn1Convertible other = obj as IAsn1Convertible;
if(other == null)
return false;
Asn1Object o1 = ToAsn1Object();
Asn1Object o2 = other.ToAsn1Object();
return o1 == o2 || o1.CallAsn1Equals(o2);
}
public abstract Asn1Object ToAsn1Object();
}
}
using System;
using System.Collections;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class Asn1EncodableVector
: IEnumerable
{
private IList v = Platform.CreateArrayList();
public static Asn1EncodableVector FromEnumerable(
IEnumerable e)
{
Asn1EncodableVector v = new Asn1EncodableVector();
foreach(Asn1Encodable obj in e)
{
v.Add(obj);
}
return v;
}
// public Asn1EncodableVector()
// {
// }
public Asn1EncodableVector(
params Asn1Encodable[] v)
{
Add(v);
}
// public void Add(
// Asn1Encodable obj)
// {
// v.Add(obj);
// }
public void Add(
params Asn1Encodable[] objs)
{
foreach(Asn1Encodable obj in objs)
{
v.Add(obj);
}
}
public void AddOptional(
params Asn1Encodable[] objs)
{
if(objs != null)
{
foreach(Asn1Encodable obj in objs)
{
if(obj != null)
{
v.Add(obj);
}
}
}
}
public Asn1Encodable this[
int index]
{
get
{
return (Asn1Encodable)v[index];
}
}
[Obsolete("Use 'object[index]' syntax instead")]
public Asn1Encodable Get(
int index)
{
return this[index];
}
[Obsolete("Use 'Count' property instead")]
public int Size
{
get
{
return v.Count;
}
}
public int Count
{
get
{
return v.Count;
}
}
public IEnumerator GetEnumerator()
{
return v.GetEnumerator();
}
}
}
using System;
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class Asn1Exception
: IOException
{
public Asn1Exception()
: base()
{
}
public Asn1Exception(
string message)
: base(message)
{
}
public Asn1Exception(
string message,
Exception exception)
: base(message, exception)
{
}
}
}
using System;
using System.IO;
using NTumbleBit.BouncyCastle.Utilities.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
/**
* a general purpose ASN.1 decoder - note: this class differs from the
* others in that it returns null after it has read the last object in
* the stream. If an ASN.1 Null is encountered a Der/BER Null object is
* returned.
*/
internal class Asn1InputStream
: FilterStream
{
private readonly int limit;
private readonly byte[][] tmpBuffers;
internal static int FindLimit(Stream input)
{
if(input is LimitedInputStream)
{
return ((LimitedInputStream)input).GetRemaining();
}
else if(input is MemoryStream)
{
MemoryStream mem = (MemoryStream)input;
return (int)(mem.Length - mem.Position);
}
return int.MaxValue;
}
public Asn1InputStream(
Stream inputStream)
: this(inputStream, FindLimit(inputStream))
{
}
/**
* Create an ASN1InputStream where no DER object will be longer than limit.
*
* @param input stream containing ASN.1 encoded data.
* @param limit maximum size of a DER encoded object.
*/
public Asn1InputStream(
Stream inputStream,
int limit)
: base(inputStream)
{
this.limit = limit;
tmpBuffers = new byte[16][];
}
/**
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
* the stream is automatically limited to the length of the input array.
*
* @param input array containing ASN.1 encoded data.
*/
public Asn1InputStream(
byte[] input)
: this(new MemoryStream(input, false), input.Length)
{
}
/**
* build an object given its tag and the number of bytes to construct it from.
*/
private Asn1Object BuildObject(
int tag,
int tagNo,
int length)
{
bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(s, length);
if((tag & Asn1Tags.Application) != 0)
{
throw new IOException("invalid ECDSA sig");
}
if((tag & Asn1Tags.Tagged) != 0)
{
throw new IOException("invalid ECDSA sig");
}
if(isConstructed)
{
switch(tagNo)
{
case Asn1Tags.Sequence:
return CreateDerSequence(defIn);
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
}
internal Asn1EncodableVector BuildEncodableVector()
{
Asn1EncodableVector v = new Asn1EncodableVector();
Asn1Object o;
while((o = ReadObject()) != null)
{
v.Add(o);
}
return v;
}
internal virtual Asn1EncodableVector BuildDerEncodableVector(
DefiniteLengthInputStream dIn)
{
return new Asn1InputStream(dIn).BuildEncodableVector();
}
internal virtual DerSequence CreateDerSequence(
DefiniteLengthInputStream dIn)
{
return DerSequence.FromVector(BuildDerEncodableVector(dIn));
}
public Asn1Object ReadObject()
{
int tag = ReadByte();
if(tag <= 0)
{
if(tag == 0)
throw new IOException("unexpected end-of-contents marker");
return null;
}
//
// calculate tag number
//
int tagNo = ReadTagNumber(s, tag);
//
// calculate length
//
int length = ReadLength(s, limit);
if(length < 0) // indefinite length method
{
throw new IOException("indefinite length primitive encoding encountered");
}
else
{
try
{
return BuildObject(tag, tagNo, length);
}
catch(ArgumentException e)
{
throw new Asn1Exception("corrupted stream detected", e);
}
}
}
internal static int ReadTagNumber(
Stream s,
int tag)
{
int tagNo = tag & 0x1f;
//
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
//
if(tagNo == 0x1f)
{
tagNo = 0;
int b = s.ReadByte();
// X.690-0207 8.1.2.4.2
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
if((b & 0x7f) == 0) // Note: -1 will pass
{
throw new IOException("Corrupted stream - invalid high tag number found");
}
while((b >= 0) && ((b & 0x80) != 0))
{
tagNo |= (b & 0x7f);
tagNo <<= 7;
b = s.ReadByte();
}
if(b < 0)
throw new EndOfStreamException("EOF found inside tag value.");
tagNo |= (b & 0x7f);
}
return tagNo;
}
internal static int ReadLength(
Stream s,
int limit)
{
int length = s.ReadByte();
if(length < 0)
throw new EndOfStreamException("EOF found when length expected");
if(length == 0x80)
return -1; // indefinite-length encoding
if(length > 127)
{
int size = length & 0x7f;
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
if(size > 4)
throw new IOException("DER length more than 4 bytes: " + size);
length = 0;
for(int i = 0; i < size; i++)
{
int next = s.ReadByte();
if(next < 0)
throw new EndOfStreamException("EOF found reading length");
length = (length << 8) + next;
}
if(length < 0)
throw new IOException("Corrupted stream - negative length found");
if(length >= limit) // after all we must have read at least 1 byte
throw new IOException("Corrupted stream - out of bounds length found");
}
return length;
}
internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
{
int len = defIn.GetRemaining();
if(len >= tmpBuffers.Length)
{
return defIn.ToArray();
}
byte[] buf = tmpBuffers[len];
if(buf == null)
{
buf = tmpBuffers[len] = new byte[len];
}
defIn.ReadAllIntoByteArray(buf);
return buf;
}
internal static Asn1Object CreatePrimitiveDerObject(
int tagNo,
DefiniteLengthInputStream defIn,
byte[][] tmpBuffers)
{
switch(tagNo)
{
case Asn1Tags.Boolean:
throw new IOException("invalid ECDSA sig");
case Asn1Tags.Enumerated:
throw new IOException("invalid ECDSA sig");
case Asn1Tags.ObjectIdentifier:
return DerObjectIdentifier.FromOctetString(GetBuffer(defIn, tmpBuffers));
}
byte[] bytes = defIn.ToArray();
switch(tagNo)
{
case Asn1Tags.Integer:
return new DerInteger(bytes);
case Asn1Tags.OctetString:
return new DerOctetString(bytes);
case Asn1Tags.Null:
return DerNull.Instance; // actual content is ignored (enforce 0 length?)
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
/**
* A Null object.
*/
internal abstract class Asn1Null
: Asn1Object
{
internal Asn1Null()
{
}
public override string ToString()
{
return "NULL";
}
}
}
using System;
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class Asn1Object
: Asn1Encodable
{
/// <summary>Create a base ASN.1 object from a byte array.</summary>
/// <param name="data">The byte array to parse.</param>
/// <returns>The base ASN.1 object represented by the byte array.</returns>
/// <exception cref="IOException">If there is a problem parsing the data.</exception>
public static Asn1Object FromByteArray(
byte[] data)
{
try
{
MemoryStream input = new MemoryStream(data, false);
Asn1InputStream asn1 = new Asn1InputStream(input, data.Length);
Asn1Object result = asn1.ReadObject();
if(input.Position != input.Length)
throw new IOException("extra data found after object");
return result;
}
catch(InvalidCastException)
{
throw new IOException("cannot recognise object in byte array");
}
}
/// <summary>Read a base ASN.1 object from a stream.</summary>
/// <param name="inStr">The stream to parse.</param>
/// <returns>The base ASN.1 object represented by the byte array.</returns>
/// <exception cref="IOException">If there is a problem parsing the data.</exception>
public static Asn1Object FromStream(
Stream inStr)
{
try
{
return new Asn1InputStream(inStr).ReadObject();
}
catch(InvalidCastException)
{
throw new IOException("cannot recognise object in stream");
}
}
public sealed override Asn1Object ToAsn1Object()
{
return this;
}
internal abstract void Encode(DerOutputStream derOut);
public byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
Asn1OutputStream aOut = new Asn1OutputStream(bOut);
aOut.WriteObject(this);
return bOut.ToArray();
}
protected abstract bool Asn1Equals(Asn1Object asn1Object);
protected abstract int Asn1GetHashCode();
internal bool CallAsn1Equals(Asn1Object obj)
{
return Asn1Equals(obj);
}
internal int CallAsn1GetHashCode()
{
return Asn1GetHashCode();
}
}
}
using System;
using System.IO;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class Asn1OctetString
: Asn1Object, Asn1OctetStringParser
{
internal byte[] str;
/**
* @param string the octets making up the octet string.
*/
internal Asn1OctetString(
byte[] str)
{
if(str == null)
throw new ArgumentNullException(nameof(str));
this.str = str;
}
public Stream GetOctetStream()
{
return new MemoryStream(str, false);
}
public Asn1OctetStringParser Parser
{
get
{
return this;
}
}
public virtual byte[] GetOctets()
{
return str;
}
protected override int Asn1GetHashCode()
{
return Arrays.GetHashCode(GetOctets());
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
DerOctetString other = asn1Object as DerOctetString;
if(other == null)
return false;
return Arrays.AreEqual(GetOctets(), other.GetOctets());
}
}
}
using System;
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class Asn1OutputStream
: DerOutputStream
{
public Asn1OutputStream(Stream os) : base(os)
{
}
[Obsolete("Use version taking an Asn1Encodable arg instead")]
public override void WriteObject(
object obj)
{
if(obj == null)
{
WriteNull();
}
else if(obj is Asn1Object)
{
((Asn1Object)obj).Encode(this);
}
else if(obj is Asn1Encodable)
{
((Asn1Encodable)obj).ToAsn1Object().Encode(this);
}
else
{
throw new IOException("object not Asn1Encodable");
}
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.IO;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class Asn1Sequence
: Asn1Object, IEnumerable
{
private readonly IList seq;
/**
* return an Asn1Sequence from the given object.
*
* @param obj the object we want converted.
* @exception ArgumentException if the object cannot be converted.
*/
public static Asn1Sequence GetInstance(
object obj)
{
if(obj == null || obj is Asn1Sequence)
{
return (Asn1Sequence)obj;
}
else if(obj is Asn1SequenceParser)
{
return GetInstance(((Asn1SequenceParser)obj).ToAsn1Object());
}
else if(obj is byte[])
{
try
{
return GetInstance(FromByteArray((byte[])obj));
}
catch(IOException e)
{
throw new ArgumentException("failed to construct sequence from byte[]: " + e.Message);
}
}
else if(obj is Asn1Encodable)
{
Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
if(primitive is Asn1Sequence)
{
return (Asn1Sequence)primitive;
}
}
throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), nameof(obj));
}
protected internal Asn1Sequence(
int capacity)
{
seq = Platform.CreateArrayList(capacity);
}
public virtual IEnumerator GetEnumerator()
{
return seq.GetEnumerator();
}
[Obsolete("Use GetEnumerator() instead")]
public IEnumerator GetObjects()
{
return GetEnumerator();
}
private class Asn1SequenceParserImpl
: Asn1SequenceParser
{
private readonly Asn1Sequence outer;
private readonly int max;
private int index;
public Asn1SequenceParserImpl(
Asn1Sequence outer)
{
this.outer = outer;
max = outer.Count;
}
public IAsn1Convertible ReadObject()
{
if(index == max)
return null;
Asn1Encodable obj = outer[index++];
if(obj is Asn1Sequence)
return ((Asn1Sequence)obj).Parser;
// NB: Asn1OctetString implements Asn1OctetStringParser directly
// if (obj is Asn1OctetString)
// return ((Asn1OctetString)obj).Parser;
return obj;
}
public Asn1Object ToAsn1Object()
{
return outer;
}
}
public virtual Asn1SequenceParser Parser
{
get
{
return new Asn1SequenceParserImpl(this);
}
}
/**
* return the object at the sequence position indicated by index.
*
* @param index the sequence number (starting at zero) of the object
* @return the object at the sequence position indicated by index.
*/
public virtual Asn1Encodable this[int index]
{
get
{
return (Asn1Encodable)seq[index];
}
}
[Obsolete("Use 'object[index]' syntax instead")]
public Asn1Encodable GetObjectAt(
int index)
{
return this[index];
}
[Obsolete("Use 'Count' property instead")]
public int Size
{
get
{
return Count;
}
}
public virtual int Count
{
get
{
return seq.Count;
}
}
protected override int Asn1GetHashCode()
{
int hc = Count;
foreach(object o in this)
{
hc *= 17;
if(o == null)
{
hc ^= DerNull.Instance.GetHashCode();
}
else
{
hc ^= o.GetHashCode();
}
}
return hc;
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
Asn1Sequence other = asn1Object as Asn1Sequence;
if(other == null)
return false;
if(Count != other.Count)
return false;
IEnumerator s1 = GetEnumerator();
IEnumerator s2 = other.GetEnumerator();
while(s1.MoveNext() && s2.MoveNext())
{
Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
if(!o1.Equals(o2))
return false;
}
return true;
}
private Asn1Encodable GetCurrent(IEnumerator e)
{
Asn1Encodable encObj = (Asn1Encodable)e.Current;
// unfortunately null was allowed as a substitute for DER null
if(encObj == null)
return DerNull.Instance;
return encObj;
}
protected internal void AddObject(
Asn1Encodable obj)
{
seq.Add(obj);
}
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class Asn1Tags
{
public const int Boolean = 0x01;
public const int Integer = 0x02;
public const int BitString = 0x03;
public const int OctetString = 0x04;
public const int Null = 0x05;
public const int ObjectIdentifier = 0x06;
public const int External = 0x08;
public const int Enumerated = 0x0a;
public const int Sequence = 0x10;
public const int SequenceOf = 0x10; // for completeness
public const int Set = 0x11;
public const int SetOf = 0x11; // for completeness
public const int NumericString = 0x12;
public const int PrintableString = 0x13;
public const int T61String = 0x14;
public const int VideotexString = 0x15;
public const int IA5String = 0x16;
public const int UtcTime = 0x17;
public const int GeneralizedTime = 0x18;
public const int GraphicString = 0x19;
public const int VisibleString = 0x1a;
public const int GeneralString = 0x1b;
public const int UniversalString = 0x1c;
public const int BmpString = 0x1e;
public const int Utf8String = 0x0c;
public const int Constructed = 0x20;
public const int Application = 0x40;
public const int Tagged = 0x80;
}
}
using System.IO;
using NTumbleBit.BouncyCastle.Utilities.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class DerGenerator
: Asn1Generator
{
private bool _tagged = false;
private bool _isExplicit;
private int _tagNo;
protected DerGenerator(
Stream outStream)
: base(outStream)
{
}
protected DerGenerator(
Stream outStream,
int tagNo,
bool isExplicit)
: base(outStream)
{
_tagged = true;
_isExplicit = isExplicit;
_tagNo = tagNo;
}
private static void WriteLength(
Stream outStr,
int length)
{
if(length > 127)
{
int size = 1;
int val = length;
while((val >>= 8) != 0)
{
size++;
}
outStr.WriteByte((byte)(size | 0x80));
for(int i = (size - 1) * 8; i >= 0; i -= 8)
{
outStr.WriteByte((byte)(length >> i));
}
}
else
{
outStr.WriteByte((byte)length);
}
}
internal static void WriteDerEncoded(
Stream outStream,
int tag,
byte[] bytes)
{
outStream.WriteByte((byte)tag);
WriteLength(outStream, bytes.Length);
outStream.Write(bytes, 0, bytes.Length);
}
internal void WriteDerEncoded(
int tag,
byte[] bytes)
{
if(_tagged)
{
int tagNum = _tagNo | Asn1Tags.Tagged;
if(_isExplicit)
{
int newTag = _tagNo | Asn1Tags.Constructed | Asn1Tags.Tagged;
MemoryStream bOut = new MemoryStream();
WriteDerEncoded(bOut, tag, bytes);
WriteDerEncoded(Out, newTag, bOut.ToArray());
}
else
{
if((tag & Asn1Tags.Constructed) != 0)
{
tagNum |= Asn1Tags.Constructed;
}
WriteDerEncoded(Out, tagNum, bytes);
}
}
else
{
WriteDerEncoded(Out, tag, bytes);
}
}
internal static void WriteDerEncoded(
Stream outStr,
int tag,
Stream inStr)
{
WriteDerEncoded(outStr, tag, Streams.ReadAll(inStr));
}
}
}
using System.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerSequenceGenerator
: DerGenerator
{
private readonly MemoryStream _bOut = new MemoryStream();
public DerSequenceGenerator(
Stream outStream)
: base(outStream)
{
}
public DerSequenceGenerator(
Stream outStream,
int tagNo,
bool isExplicit)
: base(outStream, tagNo, isExplicit)
{
}
public override void AddObject(
Asn1Encodable obj)
{
new DerOutputStream(_bOut).WriteObject(obj);
}
public override Stream GetRawOutputStream()
{
return _bOut;
}
public override void Close()
{
WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Sequence, _bOut.ToArray());
}
}
}
using System;
using System.IO;
using NTumbleBit.BouncyCastle.Utilities.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DefiniteLengthInputStream
: LimitedInputStream
{
private static readonly byte[] EmptyBytes = new byte[0];
private readonly int _originalLength;
private int _remaining;
internal DefiniteLengthInputStream(
Stream inStream,
int length)
: base(inStream, length)
{
if(length < 0)
throw new ArgumentException("negative lengths not allowed", nameof(length));
_originalLength = length;
_remaining = length;
if(length == 0)
{
SetParentEofDetect(true);
}
}
internal int Remaining
{
get
{
return _remaining;
}
}
public override int ReadByte()
{
if(_remaining == 0)
return -1;
int b = _in.ReadByte();
if(b < 0)
throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
if(--_remaining == 0)
{
SetParentEofDetect(true);
}
return b;
}
public override int Read(
byte[] buf,
int off,
int len)
{
if(_remaining == 0)
return 0;
int toRead = System.Math.Min(len, _remaining);
int numRead = _in.Read(buf, off, toRead);
if(numRead < 1)
throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
if((_remaining -= numRead) == 0)
{
SetParentEofDetect(true);
}
return numRead;
}
internal void ReadAllIntoByteArray(byte[] buf)
{
if(_remaining != buf.Length)
throw new ArgumentException("buffer length not right for data");
if((_remaining -= Streams.ReadFully(_in, buf)) != 0)
throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
SetParentEofDetect(true);
}
internal byte[] ToArray()
{
if(_remaining == 0)
return EmptyBytes;
byte[] bytes = new byte[_remaining];
if((_remaining -= Streams.ReadFully(_in, bytes)) != 0)
throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
SetParentEofDetect(true);
return bytes;
}
}
}
using System;
using NTumbleBit.BouncyCastle.Math;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerInteger
: Asn1Object
{
private readonly byte[] bytes;
/**
* return an integer from the passed in object
*
* @exception ArgumentException if the object cannot be converted.
*/
public static DerInteger GetInstance(
object obj)
{
if(obj == null || obj is DerInteger)
{
return (DerInteger)obj;
}
throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
}
public DerInteger(
int value)
{
bytes = BigInteger.ValueOf(value).ToByteArray();
}
public DerInteger(
BigInteger value)
{
if(value == null)
throw new ArgumentNullException(nameof(value));
bytes = value.ToByteArray();
}
public DerInteger(
byte[] bytes)
{
this.bytes = bytes;
}
public BigInteger Value
{
get
{
return new BigInteger(bytes);
}
}
/**
* in some cases positive values Get crammed into a space,
* that's not quite big enough...
*/
public BigInteger PositiveValue
{
get
{
return new BigInteger(1, bytes);
}
}
internal override void Encode(
DerOutputStream derOut)
{
derOut.WriteEncoded(Asn1Tags.Integer, bytes);
}
protected override int Asn1GetHashCode()
{
return Arrays.GetHashCode(bytes);
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
DerInteger other = asn1Object as DerInteger;
if(other == null)
return false;
return Arrays.AreEqual(bytes, other.bytes);
}
public override string ToString()
{
return Value.ToString();
}
}
}
using System;
namespace NTumbleBit.BouncyCastle.Asn1
{
/**
* A Null object.
*/
internal class DerNull
: Asn1Null
{
public static readonly DerNull Instance = new DerNull(0);
private byte[] zeroBytes = new byte[0];
[Obsolete("Use static Instance object")]
public DerNull()
{
}
protected internal DerNull(int dummy)
{
}
internal override void Encode(
DerOutputStream derOut)
{
derOut.WriteEncoded(Asn1Tags.Null, zeroBytes);
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
return asn1Object is DerNull;
}
protected override int Asn1GetHashCode()
{
return -1;
}
}
}
using System;
using System.IO;
using System.Text;
using NTumbleBit.BouncyCastle.Math;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerObjectIdentifier
: Asn1Object
{
private readonly string identifier;
private byte[] body = null;
public DerObjectIdentifier(
string identifier)
{
if(identifier == null)
throw new ArgumentNullException(nameof(identifier));
if(!IsValidIdentifier(identifier))
throw new FormatException("string " + identifier + " not an OID");
this.identifier = identifier;
}
internal DerObjectIdentifier(DerObjectIdentifier oid, string branchID)
{
if(!IsValidBranchID(branchID, 0))
throw new ArgumentException("string " + branchID + " not a valid OID branch", nameof(branchID));
identifier = oid.Id + "." + branchID;
}
// TODO Change to ID?
public string Id
{
get
{
return identifier;
}
}
public virtual DerObjectIdentifier Branch(string branchID)
{
return new DerObjectIdentifier(this, branchID);
}
/**
* Return true if this oid is an extension of the passed in branch, stem.
* @param stem the arc or branch that is a possible parent.
* @return true if the branch is on the passed in stem, false otherwise.
*/
public virtual bool On(DerObjectIdentifier stem)
{
string id = Id, stemId = stem.Id;
return id.Length > stemId.Length && id[stemId.Length] == '.' && Platform.StartsWith(id, stemId);
}
internal DerObjectIdentifier(byte[] bytes)
{
identifier = MakeOidStringFromBytes(bytes);
body = Arrays.Clone(bytes);
}
private void WriteField(
Stream outputStream,
long fieldValue)
{
byte[] result = new byte[9];
int pos = 8;
result[pos] = (byte)(fieldValue & 0x7f);
while(fieldValue >= (1L << 7))
{
fieldValue >>= 7;
result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
}
outputStream.Write(result, pos, 9 - pos);
}
private void WriteField(
Stream outputStream,
BigInteger fieldValue)
{
int byteCount = (fieldValue.BitLength + 6) / 7;
if(byteCount == 0)
{
outputStream.WriteByte(0);
}
else
{
BigInteger tmpValue = fieldValue;
byte[] tmp = new byte[byteCount];
for(int i = byteCount - 1; i >= 0; i--)
{
tmp[i] = (byte)((tmpValue.IntValue & 0x7f) | 0x80);
tmpValue = tmpValue.ShiftRight(7);
}
tmp[byteCount - 1] &= 0x7f;
outputStream.Write(tmp, 0, tmp.Length);
}
}
protected override int Asn1GetHashCode()
{
return identifier.GetHashCode();
}
protected override bool Asn1Equals(
Asn1Object asn1Object)
{
DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
if(other == null)
return false;
return identifier.Equals(other.identifier);
}
public override string ToString()
{
return identifier;
}
private static bool IsValidBranchID(
String branchID, int start)
{
bool periodAllowed = false;
int pos = branchID.Length;
while(--pos >= start)
{
char ch = branchID[pos];
// TODO Leading zeroes?
if('0' <= ch && ch <= '9')
{
periodAllowed = true;
continue;
}
if(ch == '.')
{
if(!periodAllowed)
return false;
periodAllowed = false;
continue;
}
return false;
}
return periodAllowed;
}
private static bool IsValidIdentifier(string identifier)
{
if(identifier.Length < 3 || identifier[1] != '.')
return false;
char first = identifier[0];
if(first < '0' || first > '2')
return false;
return IsValidBranchID(identifier, 2);
}
private const long LONG_LIMIT = (long.MaxValue >> 7) - 0x7f;
private static string MakeOidStringFromBytes(
byte[] bytes)
{
StringBuilder objId = new StringBuilder();
long value = 0;
BigInteger bigValue = null;
bool first = true;
for(int i = 0; i != bytes.Length; i++)
{
int b = bytes[i];
if(value <= LONG_LIMIT)
{
value += (b & 0x7f);
if((b & 0x80) == 0) // end of number reached
{
if(first)
{
if(value < 40)
{
objId.Append('0');
}
else if(value < 80)
{
objId.Append('1');
value -= 40;
}
else
{
objId.Append('2');
value -= 80;
}
first = false;
}
objId.Append('.');
objId.Append(value);
value = 0;
}
else
{
value <<= 7;
}
}
else
{
if(bigValue == null)
{
bigValue = BigInteger.ValueOf(value);
}
bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f));
if((b & 0x80) == 0)
{
if(first)
{
objId.Append('2');
bigValue = bigValue.Subtract(BigInteger.ValueOf(80));
first = false;
}
objId.Append('.');
objId.Append(bigValue);
bigValue = null;
value = 0;
}
else
{
bigValue = bigValue.ShiftLeft(7);
}
}
}
return objId.ToString();
}
private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024];
internal byte[] GetBody()
{
lock(this)
{
if(body == null)
{
MemoryStream bOut = new MemoryStream();
DoOutput(bOut);
body = bOut.ToArray();
}
}
return body;
}
private void DoOutput(MemoryStream bOut)
{
OidTokenizer tok = new OidTokenizer(identifier);
string token = tok.NextToken();
int first = int.Parse(token) * 40;
token = tok.NextToken();
if(token.Length <= 18)
{
WriteField(bOut, first + Int64.Parse(token));
}
else
{
WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first)));
}
while(tok.HasMoreTokens)
{
token = tok.NextToken();
if(token.Length <= 18)
{
WriteField(bOut, Int64.Parse(token));
}
else
{
WriteField(bOut, new BigInteger(token));
}
}
}
internal override void Encode(DerOutputStream derOut)
{
derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, GetBody());
}
internal static Asn1Object FromOctetString(byte[] enc)
{
int hashCode = Arrays.GetHashCode(enc);
int first = hashCode & 1023;
lock(cache)
{
DerObjectIdentifier entry = cache[first];
if(entry != null && Arrays.AreEqual(enc, entry.GetBody()))
{
return entry;
}
return cache[first] = new DerObjectIdentifier(enc);
}
}
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerOctetString
: Asn1OctetString
{
/// <param name="str">The octets making up the octet string.</param>
public DerOctetString(
byte[] str)
: base(str)
{
}
internal override void Encode(
DerOutputStream derOut)
{
derOut.WriteEncoded(Asn1Tags.OctetString, str);
}
internal static void Encode(
DerOutputStream derOut,
byte[] bytes,
int offset,
int length)
{
derOut.WriteEncoded(Asn1Tags.OctetString, bytes, offset, length);
}
}
}
using System;
using System.IO;
using NTumbleBit.BouncyCastle.Utilities.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerOutputStream
: FilterStream
{
public DerOutputStream(Stream os)
: base(os)
{
}
private void WriteLength(
int length)
{
if(length > 127)
{
int size = 1;
uint val = (uint)length;
while((val >>= 8) != 0)
{
size++;
}
WriteByte((byte)(size | 0x80));
for(int i = (size - 1) * 8; i >= 0; i -= 8)
{
WriteByte((byte)(length >> i));
}
}
else
{
WriteByte((byte)length);
}
}
internal void WriteEncoded(
int tag,
byte[] bytes)
{
WriteByte((byte)tag);
WriteLength(bytes.Length);
Write(bytes, 0, bytes.Length);
}
internal void WriteEncoded(
int tag,
byte first,
byte[] bytes)
{
WriteByte((byte)tag);
WriteLength(bytes.Length + 1);
WriteByte(first);
Write(bytes, 0, bytes.Length);
}
internal void WriteEncoded(
int tag,
byte[] bytes,
int offset,
int length)
{
WriteByte((byte)tag);
WriteLength(length);
Write(bytes, offset, length);
}
internal void WriteTag(
int flags,
int tagNo)
{
if(tagNo < 31)
{
WriteByte((byte)(flags | tagNo));
}
else
{
WriteByte((byte)(flags | 0x1f));
if(tagNo < 128)
{
WriteByte((byte)tagNo);
}
else
{
byte[] stack = new byte[5];
int pos = stack.Length;
stack[--pos] = (byte)(tagNo & 0x7F);
do
{
tagNo >>= 7;
stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
}
while(tagNo > 127);
Write(stack, pos, stack.Length - pos);
}
}
}
internal void WriteEncoded(
int flags,
int tagNo,
byte[] bytes)
{
WriteTag(flags, tagNo);
WriteLength(bytes.Length);
Write(bytes, 0, bytes.Length);
}
protected void WriteNull()
{
WriteByte(Asn1Tags.Null);
WriteByte(0x00);
}
[Obsolete("Use version taking an Asn1Encodable arg instead")]
public virtual void WriteObject(
object obj)
{
if(obj == null)
{
WriteNull();
}
else if(obj is Asn1Object)
{
((Asn1Object)obj).Encode(this);
}
else if(obj is Asn1Encodable)
{
((Asn1Encodable)obj).ToAsn1Object().Encode(this);
}
else
{
throw new IOException("object not Asn1Object");
}
}
public virtual void WriteObject(
Asn1Encodable obj)
{
if(obj == null)
{
WriteNull();
}
else
{
obj.ToAsn1Object().Encode(this);
}
}
public virtual void WriteObject(
Asn1Object obj)
{
if(obj == null)
{
WriteNull();
}
else
{
obj.Encode(this);
}
}
}
}
using System.IO;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal class DerSequence
: Asn1Sequence
{
public static readonly DerSequence Empty = new DerSequence();
public static DerSequence FromVector(
Asn1EncodableVector v)
{
return v.Count < 1 ? Empty : new DerSequence(v);
}
/**
* create an empty sequence
*/
public DerSequence()
: base(0)
{
}
/**
* create a sequence containing one object
*/
public DerSequence(
Asn1Encodable obj)
: base(1)
{
AddObject(obj);
}
public DerSequence(
params Asn1Encodable[] v)
: base(v.Length)
{
foreach(Asn1Encodable ae in v)
{
AddObject(ae);
}
}
/**
* create a sequence containing a vector of objects.
*/
public DerSequence(
Asn1EncodableVector v)
: base(v.Count)
{
foreach(Asn1Encodable ae in v)
{
AddObject(ae);
}
}
/*
* A note on the implementation:
* <p>
* As Der requires the constructed, definite-length model to
* be used for structured types, this varies slightly from the
* ASN.1 descriptions given. Rather than just outputing Sequence,
* we also have to specify Constructed, and the objects length.
*/
internal override void Encode(
DerOutputStream derOut)
{
// TODO Intermediate buffer could be avoided if we could calculate expected length
MemoryStream bOut = new MemoryStream();
DerOutputStream dOut = new DerOutputStream(bOut);
foreach(Asn1Encodable obj in this)
{
dOut.WriteObject(obj);
}
Platform.Dispose(dOut);
byte[] bytes = bOut.ToArray();
derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, bytes);
}
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
internal interface IAsn1Convertible
{
Asn1Object ToAsn1Object();
}
}
using System.IO;
using NTumbleBit.BouncyCastle.Utilities.IO;
namespace NTumbleBit.BouncyCastle.Asn1
{
internal abstract class LimitedInputStream
: BaseInputStream
{
protected readonly Stream _in;
private int _limit;
internal LimitedInputStream(
Stream inStream,
int limit)
{
_in = inStream;
_limit = limit;
}
internal virtual int GetRemaining()
{
// TODO: maybe one day this can become more accurate
return _limit;
}
protected virtual void SetParentEofDetect(bool on)
{
}
}
}
namespace NTumbleBit.BouncyCastle.Asn1
{
/**
* class for breaking up an Oid into it's component tokens, ala
* java.util.StringTokenizer. We need this class as some of the
* lightweight Java environment don't support classes like
* StringTokenizer.
*/
public class OidTokenizer
{
private string oid;
private int index;
public OidTokenizer(
string oid)
{
this.oid = oid;
}
public bool HasMoreTokens
{
get
{
return index != -1;
}
}
public string NextToken()
{
if(index == -1)
{
return null;
}
int end = oid.IndexOf('.', index);
if(end == -1)
{
string lastToken = oid.Substring(index);
index = -1;
return lastToken;
}
string nextToken = oid.Substring(index, end - index);
index = end + 1;
return nextToken;
}
}
}
\ No newline at end of file
using System;
namespace NTumbleBit.BouncyCastle.Asn1.X509
{
internal class AlgorithmIdentifier
: Asn1Encodable
{
private readonly DerObjectIdentifier objectID;
private readonly Asn1Encodable parameters;
private readonly bool parametersDefined;
public AlgorithmIdentifier(
DerObjectIdentifier objectID)
{
this.objectID = objectID;
}
public AlgorithmIdentifier(
string objectID)
{
this.objectID = new DerObjectIdentifier(objectID);
}
public AlgorithmIdentifier(
DerObjectIdentifier objectID,
Asn1Encodable parameters)
{
this.objectID = objectID;
this.parameters = parameters;
parametersDefined = true;
}
public virtual DerObjectIdentifier ObjectID
{
get
{
return objectID;
}
}
public Asn1Encodable Parameters
{
get
{
return parameters;
}
}
/**
* Produce an object suitable for an Asn1OutputStream.
* <pre>
* AlgorithmIdentifier ::= Sequence {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
* </pre>
*/
public override Asn1Object ToAsn1Object()
{
Asn1EncodableVector v = new Asn1EncodableVector(objectID);
if(parametersDefined)
{
if(parameters != null)
{
v.Add(parameters);
}
else
{
v.Add(DerNull.Instance);
}
}
return new DerSequence(v);
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.IO;
using NTumbleBit.BouncyCastle.Asn1.X509;
using NTumbleBit.BouncyCastle.Math;
namespace NTumbleBit.BouncyCastle.Asn1.Pkcs
{
internal class PrivateKeyInfo
: Asn1Encodable
{
private readonly Asn1Object privKey;
private readonly AlgorithmIdentifier algID;
public PrivateKeyInfo(
AlgorithmIdentifier algID,
Asn1Object privateKey)
{
privKey = privateKey;
this.algID = algID;
}
public AlgorithmIdentifier AlgorithmID
{
get
{
return algID;
}
}
public Asn1Object PrivateKey
{
get
{
return privKey;
}
}
/**
* write out an RSA private key with its associated information
* as described in Pkcs8.
* <pre>
* PrivateKeyInfo ::= Sequence {
* version Version,
* privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
* privateKey PrivateKey,
* attributes [0] IMPLICIT Attributes OPTIONAL
* }
* Version ::= Integer {v1(0)} (v1,...)
*
* PrivateKey ::= OCTET STRING
*
* Attributes ::= Set OF Attr
* </pre>
*/
public override Asn1Object ToAsn1Object()
{
Asn1EncodableVector v = new Asn1EncodableVector(
new DerInteger(0),
algID,
new DerOctetString(privKey.GetEncoded()));
return new DerSequence(v);
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using NTumbleBit.BouncyCastle.Asn1;
using NTumbleBit.BouncyCastle.Math;
namespace Org.BouncyCastle.Asn1.Pkcs
{
internal class RsaPrivateKeyStructure
: Asn1Encodable
{
private readonly BigInteger modulus;
private readonly BigInteger publicExponent;
private readonly BigInteger privateExponent;
private readonly BigInteger prime1;
private readonly BigInteger prime2;
private readonly BigInteger exponent1;
private readonly BigInteger exponent2;
private readonly BigInteger coefficient;
public RsaPrivateKeyStructure(
BigInteger modulus,
BigInteger publicExponent,
BigInteger privateExponent,
BigInteger prime1,
BigInteger prime2,
BigInteger exponent1,
BigInteger exponent2,
BigInteger coefficient)
{
this.modulus = modulus;
this.publicExponent = publicExponent;
this.privateExponent = privateExponent;
this.prime1 = prime1;
this.prime2 = prime2;
this.exponent1 = exponent1;
this.exponent2 = exponent2;
this.coefficient = coefficient;
}
public RsaPrivateKeyStructure(
Asn1Sequence seq)
{
BigInteger version = ((DerInteger)seq[0]).Value;
if(version.IntValue != 0)
throw new ArgumentException("wrong version for RSA private key");
modulus = ((DerInteger)seq[1]).Value;
publicExponent = ((DerInteger)seq[2]).Value;
privateExponent = ((DerInteger)seq[3]).Value;
prime1 = ((DerInteger)seq[4]).Value;
prime2 = ((DerInteger)seq[5]).Value;
exponent1 = ((DerInteger)seq[6]).Value;
exponent2 = ((DerInteger)seq[7]).Value;
coefficient = ((DerInteger)seq[8]).Value;
}
public BigInteger Modulus
{
get
{
return modulus;
}
}
public BigInteger PublicExponent
{
get
{
return publicExponent;
}
}
public BigInteger PrivateExponent
{
get
{
return privateExponent;
}
}
public BigInteger Prime1
{
get
{
return prime1;
}
}
public BigInteger Prime2
{
get
{
return prime2;
}
}
public BigInteger Exponent1
{
get
{
return exponent1;
}
}
public BigInteger Exponent2
{
get
{
return exponent2;
}
}
public BigInteger Coefficient
{
get
{
return coefficient;
}
}
/**
* This outputs the key in Pkcs1v2 format.
* <pre>
* RsaPrivateKey ::= Sequence {
* version Version,
* modulus Integer, -- n
* publicExponent Integer, -- e
* privateExponent Integer, -- d
* prime1 Integer, -- p
* prime2 Integer, -- q
* exponent1 Integer, -- d mod (p-1)
* exponent2 Integer, -- d mod (q-1)
* coefficient Integer -- (inverse of q) mod p
* }
*
* Version ::= Integer
* </pre>
* <p>This routine is written to output Pkcs1 version 0, private keys.</p>
*/
public override Asn1Object ToAsn1Object()
{
return new DerSequence(
new DerInteger(0), // version
new DerInteger(Modulus),
new DerInteger(PublicExponent),
new DerInteger(PrivateExponent),
new DerInteger(Prime1),
new DerInteger(Prime2),
new DerInteger(Exponent1),
new DerInteger(Exponent2),
new DerInteger(Coefficient));
}
}
}
\ No newline at end of file
using NTumbleBit.BouncyCastle.Asn1;
using NTumbleBit.BouncyCastle.Math;
using System;
using System.Collections;
namespace NTumbleBit.BouncyCastle.Asn1.X509
{
internal class RsaPublicKeyStructure
: Asn1Encodable
{
private BigInteger modulus;
private BigInteger publicExponent;
public static RsaPublicKeyStructure GetInstance(
object obj)
{
if(obj == null || obj is RsaPublicKeyStructure)
{
return (RsaPublicKeyStructure)obj;
}
if(obj is Asn1Sequence)
{
return new RsaPublicKeyStructure((Asn1Sequence)obj);
}
throw new ArgumentException("Invalid RsaPublicKeyStructure: " + obj.GetType().Name);
}
public RsaPublicKeyStructure(
BigInteger modulus,
BigInteger publicExponent)
{
if(modulus == null)
throw new ArgumentNullException(nameof(modulus));
if(publicExponent == null)
throw new ArgumentNullException(nameof(publicExponent));
if(modulus.SignValue <= 0)
throw new ArgumentException("Not a valid RSA modulus", nameof(modulus));
if(publicExponent.SignValue <= 0)
throw new ArgumentException("Not a valid RSA public exponent", nameof(publicExponent));
this.modulus = modulus;
this.publicExponent = publicExponent;
}
internal RsaPublicKeyStructure(
Asn1Sequence seq)
{
if(seq.Count != 2)
throw new ArgumentException("Bad sequence size: " + seq.Count);
// Note: we are accepting technically incorrect (i.e. negative) values here
modulus = DerInteger.GetInstance(seq[0]).PositiveValue;
publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue;
}
public BigInteger Modulus
{
get
{
return modulus;
}
}
public BigInteger PublicExponent
{
get
{
return publicExponent;
}
}
/**
* This outputs the key in Pkcs1v2 format.
* <pre>
* RSAPublicKey ::= Sequence {
* modulus Integer, -- n
* publicExponent Integer, -- e
* }
* </pre>
*/
public override Asn1Object ToAsn1Object()
{
return new DerSequence(
new DerInteger(Modulus),
new DerInteger(PublicExponent));
}
}
}
\ No newline at end of file
namespace NTumbleBit.BouncyCastle.Asn1.Sec
{
internal abstract class SecObjectIdentifiers
{
/**
* EllipticCurve OBJECT IDENTIFIER ::= {
* iso(1) identified-organization(3) certicom(132) curve(0)
* }
*/
public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.132.0");
public static readonly DerObjectIdentifier SecT163k1 = new DerObjectIdentifier(EllipticCurve + ".1");
public static readonly DerObjectIdentifier SecT163r1 = new DerObjectIdentifier(EllipticCurve + ".2");
public static readonly DerObjectIdentifier SecT239k1 = new DerObjectIdentifier(EllipticCurve + ".3");
public static readonly DerObjectIdentifier SecT113r1 = new DerObjectIdentifier(EllipticCurve + ".4");
public static readonly DerObjectIdentifier SecT113r2 = new DerObjectIdentifier(EllipticCurve + ".5");
public static readonly DerObjectIdentifier SecP112r1 = new DerObjectIdentifier(EllipticCurve + ".6");
public static readonly DerObjectIdentifier SecP112r2 = new DerObjectIdentifier(EllipticCurve + ".7");
public static readonly DerObjectIdentifier SecP160r1 = new DerObjectIdentifier(EllipticCurve + ".8");
public static readonly DerObjectIdentifier SecP160k1 = new DerObjectIdentifier(EllipticCurve + ".9");
public static readonly DerObjectIdentifier SecP256k1 = new DerObjectIdentifier(EllipticCurve + ".10");
public static readonly DerObjectIdentifier SecT163r2 = new DerObjectIdentifier(EllipticCurve + ".15");
public static readonly DerObjectIdentifier SecT283k1 = new DerObjectIdentifier(EllipticCurve + ".16");
public static readonly DerObjectIdentifier SecT283r1 = new DerObjectIdentifier(EllipticCurve + ".17");
public static readonly DerObjectIdentifier SecT131r1 = new DerObjectIdentifier(EllipticCurve + ".22");
public static readonly DerObjectIdentifier SecT131r2 = new DerObjectIdentifier(EllipticCurve + ".23");
public static readonly DerObjectIdentifier SecT193r1 = new DerObjectIdentifier(EllipticCurve + ".24");
public static readonly DerObjectIdentifier SecT193r2 = new DerObjectIdentifier(EllipticCurve + ".25");
public static readonly DerObjectIdentifier SecT233k1 = new DerObjectIdentifier(EllipticCurve + ".26");
public static readonly DerObjectIdentifier SecT233r1 = new DerObjectIdentifier(EllipticCurve + ".27");
public static readonly DerObjectIdentifier SecP128r1 = new DerObjectIdentifier(EllipticCurve + ".28");
public static readonly DerObjectIdentifier SecP128r2 = new DerObjectIdentifier(EllipticCurve + ".29");
public static readonly DerObjectIdentifier SecP160r2 = new DerObjectIdentifier(EllipticCurve + ".30");
public static readonly DerObjectIdentifier SecP192k1 = new DerObjectIdentifier(EllipticCurve + ".31");
public static readonly DerObjectIdentifier SecP224k1 = new DerObjectIdentifier(EllipticCurve + ".32");
public static readonly DerObjectIdentifier SecP224r1 = new DerObjectIdentifier(EllipticCurve + ".33");
public static readonly DerObjectIdentifier SecP384r1 = new DerObjectIdentifier(EllipticCurve + ".34");
public static readonly DerObjectIdentifier SecP521r1 = new DerObjectIdentifier(EllipticCurve + ".35");
public static readonly DerObjectIdentifier SecT409k1 = new DerObjectIdentifier(EllipticCurve + ".36");
public static readonly DerObjectIdentifier SecT409r1 = new DerObjectIdentifier(EllipticCurve + ".37");
public static readonly DerObjectIdentifier SecT571k1 = new DerObjectIdentifier(EllipticCurve + ".38");
public static readonly DerObjectIdentifier SecT571r1 = new DerObjectIdentifier(EllipticCurve + ".39");
}
}
\ No newline at end of file
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* a holding class for public/private parameter pairs.
*/
internal class AsymmetricCipherKeyPair
{
private readonly AsymmetricKeyParameter publicParameter;
private readonly AsymmetricKeyParameter privateParameter;
/**
* basic constructor.
*
* @param publicParam a public key parameters object.
* @param privateParam the corresponding private key parameters.
*/
public AsymmetricCipherKeyPair(
AsymmetricKeyParameter publicParameter,
AsymmetricKeyParameter privateParameter)
{
if(publicParameter.IsPrivate)
throw new ArgumentException("Expected a public key", nameof(publicParameter));
if(!privateParameter.IsPrivate)
throw new ArgumentException("Expected a private key", nameof(privateParameter));
this.publicParameter = publicParameter;
this.privateParameter = privateParameter;
}
/**
* return the public key parameters.
*
* @return the public key parameters.
*/
public AsymmetricKeyParameter Public
{
get
{
return publicParameter;
}
}
/**
* return the private key parameters.
*
* @return the private key parameters.
*/
public AsymmetricKeyParameter Private
{
get
{
return privateParameter;
}
}
}
}
\ No newline at end of file
namespace NTumbleBit.BouncyCastle.Crypto
{
internal abstract class AsymmetricKeyParameter
: ICipherParameters
{
private readonly bool privateKey;
protected AsymmetricKeyParameter(
bool privateKey)
{
this.privateKey = privateKey;
}
public bool IsPrivate
{
get
{
return privateKey;
}
}
public override bool Equals(
object obj)
{
AsymmetricKeyParameter other = obj as AsymmetricKeyParameter;
if(other == null)
{
return false;
}
return Equals(other);
}
protected bool Equals(
AsymmetricKeyParameter other)
{
return privateKey == other.privateKey;
}
public override int GetHashCode()
{
return privateKey.GetHashCode();
}
}
}
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* A wrapper class that allows block ciphers to be used to process data in
* a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
* buffer is full and more data is being added, or on a doFinal.
* <p>
* Note: in the case where the underlying cipher is either a CFB cipher or an
* OFB one the last block may not be a multiple of the block size.
* </p>
*/
internal class BufferedBlockCipher
: BufferedCipherBase
{
internal byte[] buf;
internal int bufOff;
internal bool forEncryption;
internal IBlockCipher cipher;
/**
* constructor for subclasses
*/
protected BufferedBlockCipher()
{
}
/**
* Create a buffered block cipher without padding.
*
* @param cipher the underlying block cipher this buffering object wraps.
* false otherwise.
*/
public BufferedBlockCipher(
IBlockCipher cipher)
{
if(cipher == null)
throw new ArgumentNullException(nameof(cipher));
this.cipher = cipher;
buf = new byte[cipher.GetBlockSize()];
bufOff = 0;
}
public override string AlgorithmName
{
get
{
return cipher.AlgorithmName;
}
}
/**
* initialise the cipher.
*
* @param forEncryption if true the cipher is initialised for
* encryption, if false for decryption.
* @param param the key and other data required by the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
// Note: This doubles as the Init in the event that this cipher is being used as an IWrapper
public override void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
Reset();
cipher.Init(forEncryption, parameters);
}
/**
* return the blocksize for the underlying cipher.
*
* @return the blocksize for the underlying cipher.
*/
public override int GetBlockSize()
{
return cipher.GetBlockSize();
}
/**
* return the size of the output buffer required for an update
* an input of len bytes.
*
* @param len the length of the input.
* @return the space required to accommodate a call to update
* with len bytes of input.
*/
public override int GetUpdateOutputSize(
int length)
{
int total = length + bufOff;
int leftOver = total % buf.Length;
return total - leftOver;
}
/**
* return the size of the output buffer required for an update plus a
* doFinal with an input of len bytes.
*
* @param len the length of the input.
* @return the space required to accommodate a call to update and doFinal
* with len bytes of input.
*/
public override int GetOutputSize(
int length)
{
// Note: Can assume IsPartialBlockOkay is true for purposes of this calculation
return length + bufOff;
}
/**
* process a single byte, producing an output block if necessary.
*
* @param in the input byte.
* @param out the space for any output that might be produced.
* @param outOff the offset from which the output will be copied.
* @return the number of output bytes copied to out.
* @exception DataLengthException if there isn't enough space in out.
* @exception InvalidOperationException if the cipher isn't initialised.
*/
public override int ProcessByte(
byte input,
byte[] output,
int outOff)
{
buf[bufOff++] = input;
if(bufOff == buf.Length)
{
if((outOff + buf.Length) > output.Length)
throw new DataLengthException("output buffer too short");
bufOff = 0;
return cipher.ProcessBlock(buf, 0, output, outOff);
}
return 0;
}
public override byte[] ProcessByte(
byte input)
{
int outLength = GetUpdateOutputSize(1);
byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
int pos = ProcessByte(input, outBytes, 0);
if(outLength > 0 && pos < outLength)
{
byte[] tmp = new byte[pos];
Array.Copy(outBytes, 0, tmp, 0, pos);
outBytes = tmp;
}
return outBytes;
}
public override byte[] ProcessBytes(
byte[] input,
int inOff,
int length)
{
if(input == null)
throw new ArgumentNullException(nameof(input));
if(length < 1)
return null;
int outLength = GetUpdateOutputSize(length);
byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
int pos = ProcessBytes(input, inOff, length, outBytes, 0);
if(outLength > 0 && pos < outLength)
{
byte[] tmp = new byte[pos];
Array.Copy(outBytes, 0, tmp, 0, pos);
outBytes = tmp;
}
return outBytes;
}
/**
* process an array of bytes, producing output if necessary.
*
* @param in the input byte array.
* @param inOff the offset at which the input data starts.
* @param len the number of bytes to be copied out of the input array.
* @param out the space for any output that might be produced.
* @param outOff the offset from which the output will be copied.
* @return the number of output bytes copied to out.
* @exception DataLengthException if there isn't enough space in out.
* @exception InvalidOperationException if the cipher isn't initialised.
*/
public override int ProcessBytes(
byte[] input,
int inOff,
int length,
byte[] output,
int outOff)
{
if(length < 1)
{
if(length < 0)
throw new ArgumentException("Can't have a negative input length!");
return 0;
}
int blockSize = GetBlockSize();
int outLength = GetUpdateOutputSize(length);
if(outLength > 0)
{
Check.OutputLength(output, outOff, outLength, "output buffer too short");
}
int resultLen = 0;
int gapLen = buf.Length - bufOff;
if(length > gapLen)
{
Array.Copy(input, inOff, buf, bufOff, gapLen);
resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
bufOff = 0;
length -= gapLen;
inOff += gapLen;
while(length > buf.Length)
{
resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
length -= blockSize;
inOff += blockSize;
}
}
Array.Copy(input, inOff, buf, bufOff, length);
bufOff += length;
if(bufOff == buf.Length)
{
resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
bufOff = 0;
}
return resultLen;
}
public override byte[] DoFinal()
{
byte[] outBytes = EmptyBuffer;
int length = GetOutputSize(0);
if(length > 0)
{
outBytes = new byte[length];
int pos = DoFinal(outBytes, 0);
if(pos < outBytes.Length)
{
byte[] tmp = new byte[pos];
Array.Copy(outBytes, 0, tmp, 0, pos);
outBytes = tmp;
}
}
else
{
Reset();
}
return outBytes;
}
public override byte[] DoFinal(
byte[] input,
int inOff,
int inLen)
{
if(input == null)
throw new ArgumentNullException(nameof(input));
int length = GetOutputSize(inLen);
byte[] outBytes = EmptyBuffer;
if(length > 0)
{
outBytes = new byte[length];
int pos = (inLen > 0)
? ProcessBytes(input, inOff, inLen, outBytes, 0)
: 0;
pos += DoFinal(outBytes, pos);
if(pos < outBytes.Length)
{
byte[] tmp = new byte[pos];
Array.Copy(outBytes, 0, tmp, 0, pos);
outBytes = tmp;
}
}
else
{
Reset();
}
return outBytes;
}
/**
* Process the last block in the buffer.
*
* @param out the array the block currently being held is copied into.
* @param outOff the offset at which the copying starts.
* @return the number of output bytes copied to out.
* @exception DataLengthException if there is insufficient space in out for
* the output, or the input is not block size aligned and should be.
* @exception InvalidOperationException if the underlying cipher is not
* initialised.
* @exception InvalidCipherTextException if padding is expected and not found.
* @exception DataLengthException if the input is not block size
* aligned.
*/
public override int DoFinal(
byte[] output,
int outOff)
{
try
{
if(bufOff != 0)
{
Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
Check.OutputLength(output, outOff, bufOff, "output buffer too short for DoFinal()");
// NB: Can't copy directly, or we may write too much output
cipher.ProcessBlock(buf, 0, buf, 0);
Array.Copy(buf, 0, output, outOff, bufOff);
}
return bufOff;
}
finally
{
Reset();
}
}
/**
* Reset the buffer and cipher. After resetting the object is in the same
* state as it was after the last init (if there was one).
*/
public override void Reset()
{
Array.Clear(buf, 0, buf.Length);
bufOff = 0;
cipher.Reset();
}
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
internal abstract class BufferedCipherBase
: IBufferedCipher
{
protected static readonly byte[] EmptyBuffer = new byte[0];
public abstract string AlgorithmName
{
get;
}
public abstract void Init(bool forEncryption, ICipherParameters parameters);
public abstract int GetBlockSize();
public abstract int GetOutputSize(int inputLen);
public abstract int GetUpdateOutputSize(int inputLen);
public abstract byte[] ProcessByte(byte input);
public virtual int ProcessByte(
byte input,
byte[] output,
int outOff)
{
byte[] outBytes = ProcessByte(input);
if(outBytes == null)
return 0;
if(outOff + outBytes.Length > output.Length)
throw new DataLengthException("output buffer too short");
outBytes.CopyTo(output, outOff);
return outBytes.Length;
}
public virtual byte[] ProcessBytes(
byte[] input)
{
return ProcessBytes(input, 0, input.Length);
}
public abstract byte[] ProcessBytes(byte[] input, int inOff, int length);
public virtual int ProcessBytes(
byte[] input,
byte[] output,
int outOff)
{
return ProcessBytes(input, 0, input.Length, output, outOff);
}
public virtual int ProcessBytes(
byte[] input,
int inOff,
int length,
byte[] output,
int outOff)
{
byte[] outBytes = ProcessBytes(input, inOff, length);
if(outBytes == null)
return 0;
if(outOff + outBytes.Length > output.Length)
throw new DataLengthException("output buffer too short");
outBytes.CopyTo(output, outOff);
return outBytes.Length;
}
public abstract byte[] DoFinal();
public virtual byte[] DoFinal(
byte[] input)
{
return DoFinal(input, 0, input.Length);
}
public abstract byte[] DoFinal(
byte[] input,
int inOff,
int length);
public virtual int DoFinal(
byte[] output,
int outOff)
{
byte[] outBytes = DoFinal();
if(outOff + outBytes.Length > output.Length)
throw new DataLengthException("output buffer too short");
outBytes.CopyTo(output, outOff);
return outBytes.Length;
}
public virtual int DoFinal(
byte[] input,
byte[] output,
int outOff)
{
return DoFinal(input, 0, input.Length, output, outOff);
}
public virtual int DoFinal(
byte[] input,
int inOff,
int length,
byte[] output,
int outOff)
{
int len = ProcessBytes(input, inOff, length, output, outOff);
len += DoFinal(output, outOff + len);
return len;
}
public abstract void Reset();
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
internal class Check
{
internal static void DataLength(bool condition, string msg)
{
if(condition)
throw new DataLengthException(msg);
}
internal static void DataLength(byte[] buf, int off, int len, string msg)
{
if(off + len > buf.Length)
throw new DataLengthException(msg);
}
internal static void OutputLength(byte[] buf, int off, int len, string msg)
{
if(off + len > buf.Length)
throw new OutputLengthException(msg);
}
}
}
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
internal class CryptoException
: Exception
{
public CryptoException()
{
}
public CryptoException(
string message)
: base(message)
{
}
public CryptoException(
string message,
Exception exception)
: base(message, exception)
{
}
}
}
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* this exception is thrown if a buffer that is meant to have output
* copied into it turns out to be too short, or if we've been given
* insufficient input. In general this exception will Get thrown rather
* than an ArrayOutOfBounds exception.
*/
internal class DataLengthException
: CryptoException
{
/**
* base constructor.
*/
public DataLengthException()
{
}
/**
* create a DataLengthException with the given message.
*
* @param message the message to be carried with the exception.
*/
public DataLengthException(
string message)
: base(message)
{
}
public DataLengthException(
string message,
Exception exception)
: base(message, exception)
{
}
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/// <remarks>Base interface for a public/private key block cipher.</remarks>
internal interface IAsymmetricBlockCipher
{
/// <summary>The name of the algorithm this cipher implements.</summary>
string AlgorithmName
{
get;
}
/// <summary>Initialise the cipher.</summary>
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
/// <param name="parameters">The key or other data required by the cipher.</param>
void Init(bool forEncryption, ICipherParameters parameters);
/// <returns>The maximum size, in bytes, an input block may be.</returns>
int GetInputBlockSize();
/// <returns>The maximum size, in bytes, an output block will be.</returns>
int GetOutputBlockSize();
/// <summary>Process a block.</summary>
/// <param name="inBuf">The input buffer.</param>
/// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
/// <param name="inLen">The length of the input block.</param>
/// <exception cref="InvalidCipherTextException">Input decrypts improperly.</exception>
/// <exception cref="DataLengthException">Input is too large for the cipher.</exception>
byte[] ProcessBlock(byte[] inBuf, int inOff, int inLen);
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/// <remarks>Base interface for a symmetric key block cipher.</remarks>
internal interface IBlockCipher
{
/// <summary>The name of the algorithm this cipher implements.</summary>
string AlgorithmName
{
get;
}
/// <summary>Initialise the cipher.</summary>
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
/// <param name="parameters">The key or other data required by the cipher.</param>
void Init(bool forEncryption, ICipherParameters parameters);
/// <returns>The block size for this cipher, in bytes.</returns>
int GetBlockSize();
/// <summary>Indicates whether this cipher can handle partial blocks.</summary>
bool IsPartialBlockOkay
{
get;
}
/// <summary>Process a block.</summary>
/// <param name="inBuf">The input buffer.</param>
/// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
/// <param name="outBuf">The output buffer.</param>
/// <param name="outOff">The offset into <paramref>outBuf</paramref> to write the output block.</param>
/// <exception cref="DataLengthException">If input block is wrong size, or outBuf too small.</exception>
/// <returns>The number of bytes processed and produced.</returns>
int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff);
/// <summary>
/// Reset the cipher to the same state as it was after the last init (if there was one).
/// </summary>
void Reset();
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/// <remarks>Block cipher engines are expected to conform to this interface.</remarks>
internal interface IBufferedCipher
{
/// <summary>The name of the algorithm this cipher implements.</summary>
string AlgorithmName
{
get;
}
/// <summary>Initialise the cipher.</summary>
/// <param name="forEncryption">If true the cipher is initialised for encryption,
/// if false for decryption.</param>
/// <param name="parameters">The key and other data required by the cipher.</param>
void Init(bool forEncryption, ICipherParameters parameters);
int GetBlockSize();
int GetOutputSize(int inputLen);
int GetUpdateOutputSize(int inputLen);
byte[] ProcessByte(byte input);
int ProcessByte(byte input, byte[] output, int outOff);
byte[] ProcessBytes(byte[] input);
byte[] ProcessBytes(byte[] input, int inOff, int length);
int ProcessBytes(byte[] input, byte[] output, int outOff);
int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
byte[] DoFinal();
byte[] DoFinal(byte[] input);
byte[] DoFinal(byte[] input, int inOff, int length);
int DoFinal(byte[] output, int outOff);
int DoFinal(byte[] input, byte[] output, int outOff);
int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff);
/// <summary>
/// Reset the cipher. After resetting the cipher is in the same state
/// as it was after the last init (if there was one).
/// </summary>
void Reset();
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* all parameter classes implement this.
*/
internal interface ICipherParameters
{
}
}
using NTumbleBit.BouncyCastle.Math;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* interface for classes implementing the Digital Signature Algorithm
*/
internal interface IDsa
{
string AlgorithmName
{
get;
}
/**
* initialise the signer for signature generation or signature
* verification.
*
* @param forSigning true if we are generating a signature, false
* otherwise.
* @param param key parameters for signature generation.
*/
void Init(bool forSigning, ICipherParameters parameters);
/**
* sign the passed in message (usually the output of a hash function).
*
* @param message the message to be signed.
* @return two big integers representing the r and s values respectively.
*/
BigInteger[] GenerateSignature(byte[] message);
/**
* verify the message message against the signature values r and s.
*
* @param message the message that was supposed to have been signed.
* @param r the r signature value.
* @param s the s signature value.
*/
bool VerifySignature(byte[] message, BigInteger r, BigInteger s);
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* interface that a message digest conforms to.
*/
internal interface IDigest
{
/**
* return the algorithm name
*
* @return the algorithm name
*/
string AlgorithmName
{
get;
}
/**
* return the size, in bytes, of the digest produced by this message digest.
*
* @return the size, in bytes, of the digest produced by this message digest.
*/
int GetDigestSize();
/**
* return the size, in bytes, of the internal buffer used by this digest.
*
* @return the size, in bytes, of the internal buffer used by this digest.
*/
int GetByteLength();
/**
* update the message digest with a single byte.
*
* @param inByte the input byte to be entered.
*/
void Update(byte input);
/**
* update the message digest with a block of bytes.
*
* @param input the byte array containing the data.
* @param inOff the offset into the byte array where the data starts.
* @param len the length of the data.
*/
void BlockUpdate(byte[] input, int inOff, int length);
/**
* Close the digest, producing the final digest value. The doFinal
* call leaves the digest reset.
*
* @param output the array the digest is to be copied into.
* @param outOff the offset into the out array the digest is to start at.
*/
int DoFinal(byte[] output, int outOff);
/**
* reset the digest back to it's initial state.
*/
void Reset();
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* The base interface for implementations of message authentication codes (MACs).
*/
internal interface IMac
{
/**
* Initialise the MAC.
*
* @param param the key and other data required by the MAC.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
void Init(ICipherParameters parameters);
/**
* Return the name of the algorithm the MAC implements.
*
* @return the name of the algorithm the MAC implements.
*/
string AlgorithmName
{
get;
}
/**
* Return the block size for this MAC (in bytes).
*
* @return the block size for this MAC in bytes.
*/
int GetMacSize();
/**
* add a single byte to the mac for processing.
*
* @param in the byte to be processed.
* @exception InvalidOperationException if the MAC is not initialised.
*/
void Update(byte input);
/**
* @param in the array containing the input.
* @param inOff the index in the array the data begins at.
* @param len the length of the input starting at inOff.
* @exception InvalidOperationException if the MAC is not initialised.
* @exception DataLengthException if there isn't enough data in in.
*/
void BlockUpdate(byte[] input, int inOff, int len);
/**
* Compute the final stage of the MAC writing the output to the out
* parameter.
* <p>
* doFinal leaves the MAC in the same state it was after the last init.
* </p>
* @param out the array the MAC is to be output to.
* @param outOff the offset into the out buffer the output is to start at.
* @exception DataLengthException if there isn't enough space in out.
* @exception InvalidOperationException if the MAC is not initialised.
*/
int DoFinal(byte[] output, int outOff);
/**
* Reset the MAC. At the end of resetting the MAC should be in the
* in the same state it was after the last init (if there was one).
*/
void Reset();
}
}
namespace NTumbleBit.BouncyCastle.Crypto
{
internal interface ISigner
{
/**
* Return the name of the algorithm the signer implements.
*
* @return the name of the algorithm the signer implements.
*/
string AlgorithmName
{
get;
}
/**
* Initialise the signer for signing or verification.
*
* @param forSigning true if for signing, false otherwise
* @param param necessary parameters.
*/
void Init(bool forSigning, ICipherParameters parameters);
/**
* update the internal digest with the byte b
*/
void Update(byte input);
/**
* update the internal digest with the byte array in
*/
void BlockUpdate(byte[] input, int inOff, int length);
/**
* Generate a signature for the message we've been loaded with using
* the key we were initialised with.
*/
byte[] GenerateSignature();
/**
* return true if the internal state represents the signature described
* in the passed in array.
*/
bool VerifySignature(byte[] signature);
/**
* reset the internal state
*/
void Reset();
}
}
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* this exception is thrown whenever we find something we don't expect in a
* message.
*/
internal class InvalidCipherTextException
: CryptoException
{
/**
* base constructor.
*/
public InvalidCipherTextException()
{
}
/**
* create a InvalidCipherTextException with the given message.
*
* @param message the message to be carried with the exception.
*/
public InvalidCipherTextException(
string message)
: base(message)
{
}
public InvalidCipherTextException(
string message,
Exception exception)
: base(message, exception)
{
}
}
}
using System;
using NTumbleBit.BouncyCastle.Security;
namespace NTumbleBit.BouncyCastle.Crypto
{
/**
* The base class for parameters to key generators.
*/
internal class KeyGenerationParameters
{
private SecureRandom random;
private int strength;
/**
* initialise the generator with a source of randomness
* and a strength (in bits).
*
* @param random the random byte source.
* @param strength the size, in bits, of the keys we want to produce.
*/
public KeyGenerationParameters(
SecureRandom random,
int strength)
{
if(random == null)
throw new ArgumentNullException(nameof(random));
if(strength < 1)
throw new ArgumentException("strength must be a positive value", nameof(strength));
this.random = random;
this.strength = strength;
}
/**
* return the random source associated with this
* generator.
*
* @return the generators random source.
*/
public SecureRandom Random
{
get
{
return random;
}
}
/**
* return the bit strength for keys produced by this generator,
*
* @return the strength of the keys this generator produces (in bits).
*/
public int Strength
{
get
{
return strength;
}
}
}
}
\ No newline at end of file
using System;
namespace NTumbleBit.BouncyCastle.Crypto
{
internal class OutputLengthException
: DataLengthException
{
public OutputLengthException()
{
}
public OutputLengthException(
string message)
: base(message)
{
}
public OutputLengthException(
string message,
Exception exception)
: base(message, exception)
{
}
}
}
using System;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Crypto.Digests
{
/**
* base implementation of MD4 family style digest as outlined in
* "Handbook of Applied Cryptography", pages 344 - 347.
*/
internal abstract class GeneralDigest
: IDigest, IMemoable
{
private const int BYTE_LENGTH = 64;
private byte[] xBuf;
private int xBufOff;
private long byteCount;
internal GeneralDigest()
{
xBuf = new byte[4];
}
internal GeneralDigest(GeneralDigest t)
{
xBuf = new byte[t.xBuf.Length];
CopyIn(t);
}
protected void CopyIn(GeneralDigest t)
{
Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
xBufOff = t.xBufOff;
byteCount = t.byteCount;
}
public void Update(byte input)
{
xBuf[xBufOff++] = input;
if(xBufOff == xBuf.Length)
{
ProcessWord(xBuf, 0);
xBufOff = 0;
}
byteCount++;
}
public void BlockUpdate(
byte[] input,
int inOff,
int length)
{
length = System.Math.Max(0, length);
//
// fill the current word
//
int i = 0;
if(xBufOff != 0)
{
while(i < length)
{
xBuf[xBufOff++] = input[inOff + i++];
if(xBufOff == 4)
{
ProcessWord(xBuf, 0);
xBufOff = 0;
break;
}
}
}
//
// process whole words.
//
int limit = ((length - i) & ~3) + i;
for(; i < limit; i += 4)
{
ProcessWord(input, inOff + i);
}
//
// load in the remainder.
//
while(i < length)
{
xBuf[xBufOff++] = input[inOff + i++];
}
byteCount += length;
}
public void Finish()
{
long bitLength = (byteCount << 3);
//
// add the pad bytes.
//
Update((byte)128);
while(xBufOff != 0)
Update((byte)0);
ProcessLength(bitLength);
ProcessBlock();
}
public virtual void Reset()
{
byteCount = 0;
xBufOff = 0;
Array.Clear(xBuf, 0, xBuf.Length);
}
public int GetByteLength()
{
return BYTE_LENGTH;
}
internal abstract void ProcessWord(byte[] input, int inOff);
internal abstract void ProcessLength(long bitLength);
internal abstract void ProcessBlock();
public abstract string AlgorithmName
{
get;
}
public abstract int GetDigestSize();
public abstract int DoFinal(byte[] output, int outOff);
public abstract IMemoable Copy();
public abstract void Reset(IMemoable t);
}
}
using System;
using NTumbleBit.BouncyCastle.Crypto.Utilities;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Crypto.Digests
{
/**
* Base class for SHA-384 and SHA-512.
*/
internal abstract class LongDigest
: IDigest, IMemoable
{
private int MyByteLength = 128;
private byte[] xBuf;
private int xBufOff;
private long byteCount1;
private long byteCount2;
internal ulong H1, H2, H3, H4, H5, H6, H7, H8;
private ulong[] W = new ulong[80];
private int wOff;
/**
* Constructor for variable length word
*/
internal LongDigest()
{
xBuf = new byte[8];
Reset();
}
/**
* Copy constructor. We are using copy constructors in place
* of the object.Clone() interface as this interface is not
* supported by J2ME.
*/
internal LongDigest(
LongDigest t)
{
xBuf = new byte[t.xBuf.Length];
CopyIn(t);
}
protected void CopyIn(LongDigest t)
{
Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
xBufOff = t.xBufOff;
byteCount1 = t.byteCount1;
byteCount2 = t.byteCount2;
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
H4 = t.H4;
H5 = t.H5;
H6 = t.H6;
H7 = t.H7;
H8 = t.H8;
Array.Copy(t.W, 0, W, 0, t.W.Length);
wOff = t.wOff;
}
public void Update(
byte input)
{
xBuf[xBufOff++] = input;
if(xBufOff == xBuf.Length)
{
ProcessWord(xBuf, 0);
xBufOff = 0;
}
byteCount1++;
}
public void BlockUpdate(
byte[] input,
int inOff,
int length)
{
//
// fill the current word
//
while((xBufOff != 0) && (length > 0))
{
Update(input[inOff]);
inOff++;
length--;
}
//
// process whole words.
//
while(length > xBuf.Length)
{
ProcessWord(input, inOff);
inOff += xBuf.Length;
length -= xBuf.Length;
byteCount1 += xBuf.Length;
}
//
// load in the remainder.
//
while(length > 0)
{
Update(input[inOff]);
inOff++;
length--;
}
}
public void Finish()
{
AdjustByteCounts();
long lowBitLength = byteCount1 << 3;
long hiBitLength = byteCount2;
//
// add the pad bytes.
//
Update((byte)128);
while(xBufOff != 0)
{
Update((byte)0);
}
ProcessLength(lowBitLength, hiBitLength);
ProcessBlock();
}
public virtual void Reset()
{
byteCount1 = 0;
byteCount2 = 0;
xBufOff = 0;
for(int i = 0; i < xBuf.Length; i++)
{
xBuf[i] = 0;
}
wOff = 0;
Array.Clear(W, 0, W.Length);
}
internal void ProcessWord(
byte[] input,
int inOff)
{
W[wOff] = Pack.BE_To_UInt64(input, inOff);
if(++wOff == 16)
{
ProcessBlock();
}
}
/**
* adjust the byte counts so that byteCount2 represents the
* upper long (less 3 bits) word of the byte count.
*/
private void AdjustByteCounts()
{
if(byteCount1 > 0x1fffffffffffffffL)
{
byteCount2 += (long)((ulong)byteCount1 >> 61);
byteCount1 &= 0x1fffffffffffffffL;
}
}
internal void ProcessLength(
long lowW,
long hiW)
{
if(wOff > 14)
{
ProcessBlock();
}
W[14] = (ulong)hiW;
W[15] = (ulong)lowW;
}
internal void ProcessBlock()
{
AdjustByteCounts();
//
// expand 16 word block into 80 word blocks.
//
for(int ti = 16; ti <= 79; ++ti)
{
W[ti] = Sigma1(W[ti - 2]) + W[ti - 7] + Sigma0(W[ti - 15]) + W[ti - 16];
}
//
// set up working variables.
//
ulong a = H1;
ulong b = H2;
ulong c = H3;
ulong d = H4;
ulong e = H5;
ulong f = H6;
ulong g = H7;
ulong h = H8;
int t = 0;
for(int i = 0; i < 10; i++)
{
// t = 8 * i
h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
d += h;
h += Sum0(a) + Maj(a, b, c);
// t = 8 * i + 1
g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
c += g;
g += Sum0(h) + Maj(h, a, b);
// t = 8 * i + 2
f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
b += f;
f += Sum0(g) + Maj(g, h, a);
// t = 8 * i + 3
e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
a += e;
e += Sum0(f) + Maj(f, g, h);
// t = 8 * i + 4
d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
h += d;
d += Sum0(e) + Maj(e, f, g);
// t = 8 * i + 5
c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
g += c;
c += Sum0(d) + Maj(d, e, f);
// t = 8 * i + 6
b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
f += b;
b += Sum0(c) + Maj(c, d, e);
// t = 8 * i + 7
a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
e += a;
a += Sum0(b) + Maj(b, c, d);
}
H1 += a;
H2 += b;
H3 += c;
H4 += d;
H5 += e;
H6 += f;
H7 += g;
H8 += h;
//
// reset the offset and clean out the word buffer.
//
wOff = 0;
Array.Clear(W, 0, 16);
}
/* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
private static ulong Ch(ulong x, ulong y, ulong z)
{
return (x & y) ^ (~x & z);
}
private static ulong Maj(ulong x, ulong y, ulong z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
private static ulong Sum0(ulong x)
{
return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
}
private static ulong Sum1(ulong x)
{
return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
}
private static ulong Sigma0(ulong x)
{
return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
}
private static ulong Sigma1(ulong x)
{
return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
}
/* SHA-384 and SHA-512 Constants
* (represent the first 64 bits of the fractional parts of the
* cube roots of the first sixty-four prime numbers)
*/
internal static readonly ulong[] K =
{
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
public int GetByteLength()
{
return MyByteLength;
}
public abstract string AlgorithmName
{
get;
}
public abstract int GetDigestSize();
public abstract int DoFinal(byte[] output, int outOff);
public abstract IMemoable Copy();
public abstract void Reset(IMemoable t);
}
}
using System;
using NTumbleBit.BouncyCastle.Crypto.Utilities;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Crypto.Digests
{
/**
* implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
*
* It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
* is the "endianness" of the word processing!
*/
internal class Sha1Digest
: GeneralDigest
{
private const int DigestLength = 20;
private uint H1, H2, H3, H4, H5;
private uint[] X = new uint[80];
private int xOff;
public Sha1Digest()
{
Reset();
}
/**
* Copy constructor. This will copy the state of the provided
* message digest.
*/
public Sha1Digest(Sha1Digest t)
: base(t)
{
CopyIn(t);
}
private void CopyIn(Sha1Digest t)
{
base.CopyIn(t);
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
H4 = t.H4;
H5 = t.H5;
Array.Copy(t.X, 0, X, 0, t.X.Length);
xOff = t.xOff;
}
public override string AlgorithmName
{
get
{
return "SHA-1";
}
}
public override int GetDigestSize()
{
return DigestLength;
}
internal override void ProcessWord(
byte[] input,
int inOff)
{
X[xOff] = Pack.BE_To_UInt32(input, inOff);
if(++xOff == 16)
{
ProcessBlock();
}
}
internal override void ProcessLength(long bitLength)
{
if(xOff > 14)
{
ProcessBlock();
}
X[14] = (uint)((ulong)bitLength >> 32);
X[15] = (uint)((ulong)bitLength);
}
public override int DoFinal(
byte[] output,
int outOff)
{
Finish();
Pack.UInt32_To_BE(H1, output, outOff);
Pack.UInt32_To_BE(H2, output, outOff + 4);
Pack.UInt32_To_BE(H3, output, outOff + 8);
Pack.UInt32_To_BE(H4, output, outOff + 12);
Pack.UInt32_To_BE(H5, output, outOff + 16);
Reset();
return DigestLength;
}
/**
* reset the chaining variables
*/
public override void Reset()
{
base.Reset();
H1 = 0x67452301;
H2 = 0xefcdab89;
H3 = 0x98badcfe;
H4 = 0x10325476;
H5 = 0xc3d2e1f0;
xOff = 0;
Array.Clear(X, 0, X.Length);
}
//
// Additive constants
//
private const uint Y1 = 0x5a827999;
private const uint Y2 = 0x6ed9eba1;
private const uint Y3 = 0x8f1bbcdc;
private const uint Y4 = 0xca62c1d6;
private static uint F(uint u, uint v, uint w)
{
return (u & v) | (~u & w);
}
private static uint H(uint u, uint v, uint w)
{
return u ^ v ^ w;
}
private static uint G(uint u, uint v, uint w)
{
return (u & v) | (u & w) | (v & w);
}
internal override void ProcessBlock()
{
//
// expand 16 word block into 80 word block.
//
for(int i = 16; i < 80; i++)
{
uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
X[i] = t << 1 | t >> 31;
}
//
// set up working variables.
//
uint A = H1;
uint B = H2;
uint C = H3;
uint D = H4;
uint E = H5;
//
// round 1
//
int idx = 0;
for(int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + F(B, C, D) + X[idx++] + Y1;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + F(A, B, C) + X[idx++] + Y1;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + F(E, A, B) + X[idx++] + Y1;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + F(D, E, A) + X[idx++] + Y1;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + F(C, D, E) + X[idx++] + Y1;
C = C << 30 | (C >> 2);
}
//
// round 2
//
for(int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y2;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y2;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y2;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y2;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y2;
C = C << 30 | (C >> 2);
}
//
// round 3
//
for(int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + G(B, C, D) + X[idx++] + Y3;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + G(A, B, C) + X[idx++] + Y3;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + G(E, A, B) + X[idx++] + Y3;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + G(D, E, A) + X[idx++] + Y3;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3;
C = C << 30 | (C >> 2);
}
//
// round 4
//
for(int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y4;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y4;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y4;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y4;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y4;
C = C << 30 | (C >> 2);
}
H1 += A;
H2 += B;
H3 += C;
H4 += D;
H5 += E;
//
// reset start of the buffer.
//
xOff = 0;
Array.Clear(X, 0, 16);
}
public override IMemoable Copy()
{
return new Sha1Digest(this);
}
public override void Reset(IMemoable other)
{
Sha1Digest d = (Sha1Digest)other;
CopyIn(d);
}
}
}
using NTumbleBit.BouncyCastle.Crypto.Utilities;
using NTumbleBit.BouncyCastle.Utilities;
namespace NTumbleBit.BouncyCastle.Crypto.Digests
{
/**
* Draft FIPS 180-2 implementation of SHA-384. <b>Note:</b> As this is
* based on a draft this implementation is subject to change.
*
* <pre>
* block word digest
* SHA-1 512 32 160
* SHA-256 512 32 256
* SHA-384 1024 64 384
* SHA-512 1024 64 512
* </pre>
*/
internal class Sha384Digest
: LongDigest
{
private const int DigestLength = 48;
public Sha384Digest()
{
}
/**
* Copy constructor. This will copy the state of the provided
* message digest.
*/
public Sha384Digest(
Sha384Digest t)
: base(t)
{
}
public override string AlgorithmName
{
get
{
return "SHA-384";
}
}
public override int GetDigestSize()
{
return DigestLength;
}
public override int DoFinal(
byte[] output,
int outOff)
{
Finish();
Pack.UInt64_To_BE(H1, output, outOff);
Pack.UInt64_To_BE(H2, output, outOff + 8);
Pack.UInt64_To_BE(H3, output, outOff + 16);
Pack.UInt64_To_BE(H4, output, outOff + 24);
Pack.UInt64_To_BE(H5, output, outOff + 32);
Pack.UInt64_To_BE(H6, output, outOff + 40);
Reset();
return DigestLength;
}
/**
* reset the chaining variables
*/
public override void Reset()
{
base.Reset();
/* SHA-384 initial hash value
* The first 64 bits of the fractional parts of the square roots
* of the 9th through 16th prime numbers
*/
H1 = 0xcbbb9d5dc1059ed8;
H2 = 0x629a292a367cd507;
H3 = 0x9159015a3070dd17;
H4 = 0x152fecd8f70e5939;
H5 = 0x67332667ffc00b31;
H6 = 0x8eb44a8768581511;
H7 = 0xdb0c2e0d64f98fa7;
H8 = 0x47b5481dbefa4fa4;
}
public override IMemoable Copy()
{
return new Sha384Digest(this);
}
public override void Reset(IMemoable other)
{
Sha384Digest d = (Sha384Digest)other;
CopyIn(d);
}
}
}
This diff is collapsed.
This diff is collapsed.
using NTumbleBit.BouncyCastle.Security;
namespace NTumbleBit.BouncyCastle.Crypto.Paddings
{
/**
* Block cipher padders are expected to conform to this interface
*/
internal interface IBlockCipherPadding
{
/**
* Initialise the padder.
*
* @param param parameters, if any required.
*/
void Init();
//throws ArgumentException;
/**
* Return the name of the algorithm the cipher implements.
*
* @return the name of the algorithm the cipher implements.
*/
string PaddingName
{
get;
}
/**
* add the pad bytes to the passed in block, returning the
* number of bytes added.
*/
int AddPadding(byte[] input, int inOff);
/**
* return the number of pad bytes present in the block.
* @exception InvalidCipherTextException if the padding is badly formed
* or invalid.
*/
int PadCount(byte[] input);
//throws InvalidCipherTextException;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment