diff options
Diffstat (limited to 'crypto/src')
194 files changed, 4586 insertions, 2343 deletions
diff --git a/crypto/src/BouncyCastle.Crypto.csproj b/crypto/src/BouncyCastle.Crypto.csproj index 44925aebd..8c77860b1 100644 --- a/crypto/src/BouncyCastle.Crypto.csproj +++ b/crypto/src/BouncyCastle.Crypto.csproj @@ -1,31 +1,57 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net6.0;netstandard2.0;net462</TargetFrameworks> + <TargetFrameworks>net6.0;netstandard2.0;net461</TargetFrameworks> <RootNamespace>Org.BouncyCastle</RootNamespace> - <AssemblyOriginatorKeyFile>..\..\BouncyCastle.snk</AssemblyOriginatorKeyFile> + <AssemblyOriginatorKeyFile>..\..\BouncyCastle.NET.snk</AssemblyOriginatorKeyFile> <SignAssembly>true</SignAssembly> <NoWarn>1591</NoWarn> - <Authors /> + <AssemblyName>BouncyCastle.Cryptography</AssemblyName> + <AssemblyTitle>BouncyCastle.NET Cryptography ($(TargetFramework))</AssemblyTitle> + <Authors>Legion of the Bouncy Castle Inc.</Authors> <Company>Legion of the Bouncy Castle Inc.</Company> <Copyright>Copyright © Legion of the Bouncy Castle Inc. 2000-2022</Copyright> - <DebugType>embedded</DebugType> <Description>BouncyCastle.NET is a popular cryptography library for .NET</Description> - <EmbedUntrackedSources>true</EmbedUntrackedSources> - <PackageIconUrl>https://www.bouncycastle.org/images/csharp_logo.gif</PackageIconUrl> + <PackageIcon>packageIcon.png</PackageIcon> + <PackageIconUrl>https://www.bouncycastle.org/images/nuget_packageIcon.png</PackageIconUrl> <PackageId>BouncyCastle.Cryptography</PackageId> - <PackageLicenseFile>License.html</PackageLicenseFile> + <PackageLicenseFile>LICENSE.md</PackageLicenseFile> <PackageProjectUrl>https://www.bouncycastle.org/csharp/</PackageProjectUrl> + <PackageReadmeFile>README.md</PackageReadmeFile> <PackageReleaseNotes>https://www.bouncycastle.org/csharp/</PackageReleaseNotes> - <PackageTags>bouncycastle cryptography dtls encryption security tls</PackageTags> + <PackageTags>bouncycastle cryptography dtls encryption open-source post-quantum security tls</PackageTags> <Product>BouncyCastle.NET</Product> - <!--<PublishRepositoryUrl>true</PublishRepositoryUrl>--> <RepositoryType>git</RepositoryType> <RepositoryUrl>https://github.com/bcgit/bc-csharp</RepositoryUrl> <Title>BouncyCastle.NET Cryptography</Title> </PropertyGroup> + <!--Source-Level Debugging--> + <PropertyGroup> + <DebugType>embedded</DebugType> + <EmbedAllSources>true</EmbedAllSources> + </PropertyGroup> + + <!--Package Validation--> + <PropertyGroup> + <EnablePackageValidation>true</EnablePackageValidation> + + <!-- TODO: Enable this once there is a baseline version to compare to. --> + <!--<PackageValidationBaselineVersion>2.0.0</PackageValidationBaselineVersion>--> + + <!-- In case we disable signing for local builds, ignore identity mismatch with baseline version. --> + <NoWarn Condition="'$(SignAssembly)' != 'true'">$(NoWarn);CP0003</NoWarn> + + <!-- + We added Span-based variant methods to several APIs. Code that uses those methods or implements the + affected interfaces (or abstract classes) will not be backward compatible. + + TODO: Use suppressions for each individual case of a Span-based method. + --> + <NoWarn>$(NoWarn);CP0005;CP0006</NoWarn> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'"> <DefineConstants>DEBUG;TRACE</DefineConstants> </PropertyGroup> @@ -38,27 +64,25 @@ <ItemGroup> <None Remove="**\*.properties" /> <EmbeddedResource Include="**\*.properties" /> + <None Include="..\..\LICENSE.md" Pack="true" PackagePath="\" /> + <None Include="..\..\packageIcon.png" Pack="true" PackagePath="\" /> + <None Include="..\..\README.md" Pack="true" PackagePath="\" /> </ItemGroup> <ItemGroup> - <None Include="..\License.html"> - <Pack>True</Pack> - <PackagePath>\</PackagePath> - </None> - </ItemGroup> - <ItemGroup> <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> <PackageReference Include="Nerdbank.GitVersioning" Version="3.5.119"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> + <Target Name="FixAssemblyAttributes" AfterTargets="GetBuildVersion"> + <PropertyGroup> + <!-- Here we can override/use any MSBuild properties set by Nerdbank.GitVersioning --> + </PropertyGroup> + </Target> </Project> diff --git a/crypto/src/asn1/Asn1GeneralizedTime.cs b/crypto/src/asn1/Asn1GeneralizedTime.cs index e844c8ca2..139384c1a 100644 --- a/crypto/src/asn1/Asn1GeneralizedTime.cs +++ b/crypto/src/asn1/Asn1GeneralizedTime.cs @@ -11,8 +11,7 @@ namespace Org.BouncyCastle.Asn1 * Base class representing the ASN.1 GeneralizedTime type. * <p> * The main difference between these and UTC time is a 4 digit year. - * </p> - * <p> + * </p><p> * One second resolution date+time on UTC timezone (Z) * with 4 digit year (valid from 0001 to 9999). * </p><p> @@ -24,18 +23,18 @@ namespace Org.BouncyCastle.Asn1 * * <h3>11: Restrictions on BER employed by both CER and DER</h3> * <h4>11.7 GeneralizedTime </h4> - * <p> + * </p><p> * <b>11.7.1</b> The encoding shall terminate with a "Z", * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on * GeneralizedTime. * </p><p> * <b>11.7.2</b> The seconds element shall always be present. - * </p> - * <p> + * </p><p> * <b>11.7.3</b> The fractional-seconds elements, if present, * shall omit all trailing zeros; if the elements correspond to 0, * they shall be wholly omitted, and the decimal point element also * shall be omitted. + * </p> */ public class Asn1GeneralizedTime : Asn1Object diff --git a/crypto/src/asn1/Asn1Null.cs b/crypto/src/asn1/Asn1Null.cs index 9ea9b4375..77304c0fb 100644 --- a/crypto/src/asn1/Asn1Null.cs +++ b/crypto/src/asn1/Asn1Null.cs @@ -25,21 +25,23 @@ namespace Org.BouncyCastle.Asn1 public static Asn1Null GetInstance(object obj) { - if (obj == null || obj is Asn1Null) - { - return (Asn1Null)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1Null asn1Null) + return asn1Null; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1Null) - return (Asn1Null)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1Null converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1Null)Meta.Instance.FromByteArray((byte[])obj); + return (Asn1Null)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1ObjectDescriptor.cs b/crypto/src/asn1/Asn1ObjectDescriptor.cs index 9c99f441e..13521a744 100644 --- a/crypto/src/asn1/Asn1ObjectDescriptor.cs +++ b/crypto/src/asn1/Asn1ObjectDescriptor.cs @@ -36,21 +36,23 @@ namespace Org.BouncyCastle.Asn1 */ public static Asn1ObjectDescriptor GetInstance(object obj) { - if (obj == null || obj is Asn1ObjectDescriptor) - { - return (Asn1ObjectDescriptor)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1ObjectDescriptor asn1ObjectDescriptor) + return asn1ObjectDescriptor; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1ObjectDescriptor) - return (Asn1ObjectDescriptor)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1ObjectDescriptor converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1ObjectDescriptor)Meta.Instance.FromByteArray((byte[])obj); + return (Asn1ObjectDescriptor)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs index d34686134..8f7da8800 100644 --- a/crypto/src/asn1/Asn1OctetString.cs +++ b/crypto/src/asn1/Asn1OctetString.cs @@ -36,22 +36,23 @@ namespace Org.BouncyCastle.Asn1 */ public static Asn1OctetString GetInstance(object obj) { - if (obj == null || obj is Asn1OctetString) - { - return (Asn1OctetString)obj; - } - //else if (obj is Asn1OctetStringParser) - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1OctetString asn1OctetString) + return asn1OctetString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1OctetString) - return (Asn1OctetString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1OctetString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1OctetString)Meta.Instance.FromByteArray((byte[])obj); + return (Asn1OctetString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs index 59178ea31..163e3848c 100644 --- a/crypto/src/asn1/Asn1OutputStream.cs +++ b/crypto/src/asn1/Asn1OutputStream.cs @@ -1,5 +1,10 @@ using System; using System.IO; +using System.Diagnostics; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +using System.Buffers.Binary; +using System.Numerics; +#endif using Org.BouncyCastle.Utilities.IO; @@ -73,15 +78,19 @@ namespace Org.BouncyCastle.Asn1 { if (dl < 128) { + Debug.Assert(dl >= 0); WriteByte((byte)dl); return; } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span<byte> stack = stackalloc byte[5]; + Span<byte> encoding = stackalloc byte[5]; + BinaryPrimitives.WriteUInt32BigEndian(encoding[1..], (uint)dl); + int leadingZeroBytes = BitOperations.LeadingZeroCount((uint)dl) / 8; + encoding[leadingZeroBytes] = (byte)(0x84 - leadingZeroBytes); + Write(encoding[leadingZeroBytes..]); #else byte[] stack = new byte[5]; -#endif int pos = stack.Length; do @@ -94,9 +103,6 @@ namespace Org.BouncyCastle.Asn1 int count = stack.Length - pos; stack[--pos] = (byte)(0x80 | count); -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Write(stack[pos..]); -#else Write(stack, pos, count + 1); #endif } diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs index a1997864d..3c4bf237a 100644 --- a/crypto/src/asn1/Asn1RelativeOid.cs +++ b/crypto/src/asn1/Asn1RelativeOid.cs @@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1 public static Asn1RelativeOid GetInstance(object obj) { - if (obj == null || obj is Asn1RelativeOid) - { - return (Asn1RelativeOid)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1RelativeOid asn1RelativeOid) + return asn1RelativeOid; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1RelativeOid) - return (Asn1RelativeOid)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1RelativeOid converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1RelativeOid)FromByteArray((byte[])obj); + return (Asn1RelativeOid)FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs index 1a123e26d..a8191de99 100644 --- a/crypto/src/asn1/Asn1Sequence.cs +++ b/crypto/src/asn1/Asn1Sequence.cs @@ -30,22 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static Asn1Sequence GetInstance(object obj) { - if (obj == null || obj is Asn1Sequence) - { - return (Asn1Sequence)obj; - } - //else if (obj is Asn1SequenceParser) - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1Sequence asn1Sequence) + return asn1Sequence; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1Sequence) - return (Asn1Sequence)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1Sequence converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1Sequence)Meta.Instance.FromByteArray((byte[])obj); + return (Asn1Sequence)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs index faec50eb0..2b3810e43 100644 --- a/crypto/src/asn1/Asn1Set.cs +++ b/crypto/src/asn1/Asn1Set.cs @@ -31,22 +31,23 @@ namespace Org.BouncyCastle.Asn1 */ public static Asn1Set GetInstance(object obj) { - if (obj == null || obj is Asn1Set) - { - return (Asn1Set)obj; - } - //else if (obj is Asn1SetParser) - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1Set asn1Set) + return asn1Set; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is Asn1Set) - return (Asn1Set)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is Asn1Set converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (Asn1Set)Meta.Instance.FromByteArray((byte[])obj); + return (Asn1Set)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs index 46aa137a8..63ab6a5d0 100644 --- a/crypto/src/asn1/Asn1TaggedObject.cs +++ b/crypto/src/asn1/Asn1TaggedObject.cs @@ -21,22 +21,23 @@ namespace Org.BouncyCastle.Asn1 public static Asn1TaggedObject GetInstance(object obj) { - if (obj == null || obj is Asn1TaggedObject) - { - return (Asn1TaggedObject)obj; - } - //else if (obj is Asn1TaggedObjectParser) - else if (obj is IAsn1Convertible asn1Convertible) + if (obj == null) + return null; + + if (obj is Asn1TaggedObject asn1TaggedObject) + return asn1TaggedObject; + + if (obj is IAsn1Convertible asn1Convertible) { Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); - if (asn1Object is Asn1TaggedObject taggedObject) - return taggedObject; + if (asn1Object is Asn1TaggedObject converted) + return converted; } - else if (obj is byte[] byteArray) + else if (obj is byte[] bytes) { try { - return CheckedCast(FromByteArray(byteArray)); + return CheckedCast(FromByteArray(bytes)); } catch (IOException e) { diff --git a/crypto/src/asn1/ConstructedBitStream.cs b/crypto/src/asn1/ConstructedBitStream.cs index 49f54fc1b..f089dac75 100644 --- a/crypto/src/asn1/ConstructedBitStream.cs +++ b/crypto/src/asn1/ConstructedBitStream.cs @@ -33,6 +33,9 @@ namespace Org.BouncyCastle.Asn1 { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else if (count < 1) return 0; @@ -75,8 +78,57 @@ namespace Org.BouncyCastle.Asn1 m_currentStream = m_currentParser.GetBitStream(); } } +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + if (buffer.IsEmpty) + return 0; + + if (m_currentStream == null) + { + if (!m_first) + return 0; + + m_currentParser = GetNextParser(); + if (m_currentParser == null) + return 0; + + m_first = false; + m_currentStream = m_currentParser.GetBitStream(); + } + + int totalRead = 0; + + for (;;) + { + int numRead = m_currentStream.Read(buffer[totalRead..]); + + if (numRead > 0) + { + totalRead += numRead; + + if (totalRead == buffer.Length) + return totalRead; + } + else + { + m_padBits = m_currentParser.PadBits; + m_currentParser = GetNextParser(); + if (m_currentParser == null) + { + m_currentStream = null; + return totalRead; + } + + m_currentStream = m_currentParser.GetBitStream(); + } + } + } +#endif + public override int ReadByte() { if (m_currentStream == null) diff --git a/crypto/src/asn1/ConstructedOctetStream.cs b/crypto/src/asn1/ConstructedOctetStream.cs index 12aa14e74..d005f9fe7 100644 --- a/crypto/src/asn1/ConstructedOctetStream.cs +++ b/crypto/src/asn1/ConstructedOctetStream.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using Org.BouncyCastle.Utilities; @@ -22,6 +23,9 @@ namespace Org.BouncyCastle.Asn1 { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else if (count < 1) return 0; @@ -63,8 +67,56 @@ namespace Org.BouncyCastle.Asn1 m_currentStream = next.GetOctetStream(); } } +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + if (buffer.IsEmpty) + return 0; + + if (m_currentStream == null) + { + if (!m_first) + return 0; + + Asn1OctetStringParser next = GetNextParser(); + if (next == null) + return 0; + + m_first = false; + m_currentStream = next.GetOctetStream(); + } + + int totalRead = 0; + + for (;;) + { + int numRead = m_currentStream.Read(buffer[totalRead..]); + + if (numRead > 0) + { + totalRead += numRead; + + if (totalRead == buffer.Length) + return totalRead; + } + else + { + Asn1OctetStringParser next = GetNextParser(); + if (next == null) + { + m_currentStream = null; + return totalRead; + } + + m_currentStream = next.GetOctetStream(); + } + } + } +#endif + public override int ReadByte() { if (m_currentStream == null) diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs index 9fba95165..207930062 100644 --- a/crypto/src/asn1/DERExternal.cs +++ b/crypto/src/asn1/DERExternal.cs @@ -25,21 +25,23 @@ namespace Org.BouncyCastle.Asn1 public static DerExternal GetInstance(object obj) { - if (obj == null || obj is DerExternal) - { - return (DerExternal)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerExternal derExternal) + return derExternal; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerExternal) - return (DerExternal)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerExternal converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerExternal)Meta.Instance.FromByteArray((byte[])obj); + return (DerExternal)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DefiniteLengthInputStream.cs b/crypto/src/asn1/DefiniteLengthInputStream.cs index ed5bd2446..89f0d5a62 100644 --- a/crypto/src/asn1/DefiniteLengthInputStream.cs +++ b/crypto/src/asn1/DefiniteLengthInputStream.cs @@ -79,6 +79,27 @@ namespace Org.BouncyCastle.Asn1 return numRead; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + if (_remaining == 0) + return 0; + + int toRead = System.Math.Min(buffer.Length, _remaining); + int numRead = _in.Read(buffer[..toRead]); + + if (numRead < 1) + throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining); + + if ((_remaining -= numRead) == 0) + { + SetParentEofDetect(); + } + + return numRead; + } +#endif + internal void ReadAllIntoByteArray(byte[] buf) { if (_remaining != buf.Length) diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs index a289eed1b..284a4b830 100644 --- a/crypto/src/asn1/DerBMPString.cs +++ b/crypto/src/asn1/DerBMPString.cs @@ -31,21 +31,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerBmpString GetInstance(object obj) { - if (obj == null || obj is DerBmpString) - { - return (DerBmpString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerBmpString derBmpString) + return derBmpString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerBmpString) - return (DerBmpString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerBmpString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerBmpString)Meta.Instance.FromByteArray((byte[])obj); + return (DerBmpString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs index 8aab88353..44b3bb95a 100644 --- a/crypto/src/asn1/DerBitString.cs +++ b/crypto/src/asn1/DerBitString.cs @@ -38,22 +38,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerBitString GetInstance(object obj) { - if (obj == null || obj is DerBitString) - { - return (DerBitString)obj; - } - //else if (obj is Asn1BitStringParser) - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerBitString derBitString) + return derBitString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerBitString) - return (DerBitString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerBitString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return GetInstance(FromByteArray((byte[])obj)); + return GetInstance(FromByteArray(bytes)); } catch (IOException e) { diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs index ad578ae80..6256db6e0 100644 --- a/crypto/src/asn1/DerBoolean.cs +++ b/crypto/src/asn1/DerBoolean.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerBoolean GetInstance(object obj) { - if (obj == null || obj is DerBoolean) - { - return (DerBoolean)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerBoolean derBoolean) + return derBoolean; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerBoolean) - return (DerBoolean)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerBoolean converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerBoolean)Meta.Instance.FromByteArray((byte[])obj); + return (DerBoolean)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs index 920b3dc8e..b85c5a43e 100644 --- a/crypto/src/asn1/DerEnumerated.cs +++ b/crypto/src/asn1/DerEnumerated.cs @@ -28,21 +28,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerEnumerated GetInstance(object obj) { - if (obj == null || obj is DerEnumerated) - { - return (DerEnumerated)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerEnumerated derEnumerated) + return derEnumerated; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerEnumerated) - return (DerEnumerated)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerEnumerated converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerEnumerated)Meta.Instance.FromByteArray((byte[])obj); + return (DerEnumerated)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs index e6637732a..6a378307d 100644 --- a/crypto/src/asn1/DerGeneralString.cs +++ b/crypto/src/asn1/DerGeneralString.cs @@ -22,21 +22,23 @@ namespace Org.BouncyCastle.Asn1 public static DerGeneralString GetInstance(object obj) { - if (obj == null || obj is DerGeneralString) - { - return (DerGeneralString) obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerGeneralString derGeneralString) + return derGeneralString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerGeneralString) - return (DerGeneralString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerGeneralString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerGeneralString)Meta.Instance.FromByteArray((byte[])obj); + return (DerGeneralString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerGraphicString.cs b/crypto/src/asn1/DerGraphicString.cs index cb32d14eb..85330eb33 100644 --- a/crypto/src/asn1/DerGraphicString.cs +++ b/crypto/src/asn1/DerGraphicString.cs @@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerGraphicString GetInstance(object obj) { - if (obj == null || obj is DerGraphicString) - { - return (DerGraphicString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerGraphicString derGraphicString) + return derGraphicString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerGraphicString) - return (DerGraphicString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerGraphicString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerGraphicString)Meta.Instance.FromByteArray((byte[])obj); + return (DerGraphicString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs index a56879831..de2860130 100644 --- a/crypto/src/asn1/DerIA5String.cs +++ b/crypto/src/asn1/DerIA5String.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerIA5String GetInstance(object obj) { - if (obj == null || obj is DerIA5String) - { - return (DerIA5String)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerIA5String derIA5String) + return derIA5String; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerIA5String) - return (DerIA5String)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerIA5String converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerIA5String)Meta.Instance.FromByteArray((byte[])obj); + return (DerIA5String)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs index c8d4e47df..05a790743 100644 --- a/crypto/src/asn1/DerInteger.cs +++ b/crypto/src/asn1/DerInteger.cs @@ -42,21 +42,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerInteger GetInstance(object obj) { - if (obj == null || obj is DerInteger) - { - return (DerInteger)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerInteger derInteger) + return derInteger; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerInteger) - return (DerInteger)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerInteger converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerInteger)Meta.Instance.FromByteArray((byte[])obj); + return (DerInteger)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs index 693ff7d6e..819d946b1 100644 --- a/crypto/src/asn1/DerNumericString.cs +++ b/crypto/src/asn1/DerNumericString.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerNumericString GetInstance(object obj) { - if (obj == null || obj is DerNumericString) - { - return (DerNumericString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerNumericString derNumericString) + return derNumericString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerNumericString) - return (DerNumericString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerNumericString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerNumericString)Meta.Instance.FromByteArray((byte[])obj); + return (DerNumericString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs index b10f8f8b6..cb5771958 100644 --- a/crypto/src/asn1/DerObjectIdentifier.cs +++ b/crypto/src/asn1/DerObjectIdentifier.cs @@ -34,21 +34,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerObjectIdentifier GetInstance(object obj) { - if (obj == null || obj is DerObjectIdentifier) - { - return (DerObjectIdentifier)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerObjectIdentifier derObjectIdentifier) + return derObjectIdentifier; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerObjectIdentifier) - return (DerObjectIdentifier)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerObjectIdentifier converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerObjectIdentifier)Meta.Instance.FromByteArray((byte[])obj); + return (DerObjectIdentifier)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs index 3c44a2d52..5830afa47 100644 --- a/crypto/src/asn1/DerPrintableString.cs +++ b/crypto/src/asn1/DerPrintableString.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerPrintableString GetInstance(object obj) { - if (obj == null || obj is DerPrintableString) - { - return (DerPrintableString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerPrintableString derPrintableString) + return derPrintableString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerPrintableString) - return (DerPrintableString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerPrintableString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerPrintableString)Meta.Instance.FromByteArray((byte[])obj); + return (DerPrintableString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs index a0e4f1d22..45f57ae0a 100644 --- a/crypto/src/asn1/DerT61String.cs +++ b/crypto/src/asn1/DerT61String.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerT61String GetInstance(object obj) { - if (obj == null || obj is DerT61String) - { - return (DerT61String)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerT61String derT61String) + return derT61String; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerT61String) - return (DerT61String)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerT61String converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerT61String)Meta.Instance.FromByteArray((byte[])obj); + return (DerT61String)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs index d15a19d39..9472f5082 100644 --- a/crypto/src/asn1/DerUTF8String.cs +++ b/crypto/src/asn1/DerUTF8String.cs @@ -30,21 +30,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerUtf8String GetInstance(object obj) { - if (obj == null || obj is DerUtf8String) - { - return (DerUtf8String)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerUtf8String derUtf8String) + return derUtf8String; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerUtf8String) - return (DerUtf8String)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerUtf8String converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerUtf8String)Meta.Instance.FromByteArray((byte[])obj); + return (DerUtf8String)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs index e4e93bd7d..1183ed1f3 100644 --- a/crypto/src/asn1/DerUniversalString.cs +++ b/crypto/src/asn1/DerUniversalString.cs @@ -32,24 +32,25 @@ namespace Org.BouncyCastle.Asn1 * * @exception ArgumentException if the object cannot be converted. */ - public static DerUniversalString GetInstance( - object obj) + public static DerUniversalString GetInstance(object obj) { - if (obj == null || obj is DerUniversalString) - { - return (DerUniversalString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerUniversalString derUniversalString) + return derUniversalString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerUniversalString) - return (DerUniversalString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerUniversalString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerUniversalString)Meta.Instance.FromByteArray((byte[])obj); + return (DerUniversalString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerVideotexString.cs b/crypto/src/asn1/DerVideotexString.cs index a5fbe0602..636af0499 100644 --- a/crypto/src/asn1/DerVideotexString.cs +++ b/crypto/src/asn1/DerVideotexString.cs @@ -29,21 +29,23 @@ namespace Org.BouncyCastle.Asn1 */ public static DerVideotexString GetInstance(object obj) { - if (obj == null || obj is DerVideotexString) - { - return (DerVideotexString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerVideotexString derVideotexString) + return derVideotexString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerVideotexString) - return (DerVideotexString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerVideotexString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerVideotexString)Meta.Instance.FromByteArray((byte[])obj); + return (DerVideotexString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs index 359370040..77fe54c9a 100644 --- a/crypto/src/asn1/DerVisibleString.cs +++ b/crypto/src/asn1/DerVisibleString.cs @@ -28,24 +28,25 @@ namespace Org.BouncyCastle.Asn1 * * @exception ArgumentException if the object cannot be converted. */ - public static DerVisibleString GetInstance( - object obj) + public static DerVisibleString GetInstance(object obj) { - if (obj == null || obj is DerVisibleString) - { - return (DerVisibleString)obj; - } - else if (obj is IAsn1Convertible) + if (obj == null) + return null; + + if (obj is DerVisibleString derVisibleString) + return derVisibleString; + + if (obj is IAsn1Convertible asn1Convertible) { - Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object(); - if (asn1Object is DerVisibleString) - return (DerVisibleString)asn1Object; + Asn1Object asn1Object = asn1Convertible.ToAsn1Object(); + if (asn1Object is DerVisibleString converted) + return converted; } - else if (obj is byte[]) + else if (obj is byte[] bytes) { try { - return (DerVisibleString)Meta.Instance.FromByteArray((byte[])obj); + return (DerVisibleString)Meta.Instance.FromByteArray(bytes); } catch (IOException e) { diff --git a/crypto/src/asn1/IndefiniteLengthInputStream.cs b/crypto/src/asn1/IndefiniteLengthInputStream.cs index 1c8bd9a15..e192e9e8b 100644 --- a/crypto/src/asn1/IndefiniteLengthInputStream.cs +++ b/crypto/src/asn1/IndefiniteLengthInputStream.cs @@ -57,7 +57,28 @@ namespace Org.BouncyCastle.Asn1 return numRead + 1; } - public override int ReadByte() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + // Only use this optimisation if we aren't checking for 00 + if (_eofOn00 || buffer.Length <= 1) + return base.Read(buffer); + + if (_lookAhead < 0) + return 0; + + int numRead = _in.Read(buffer[1..]); + if (numRead <= 0) + throw new EndOfStreamException(); + + buffer[0] = (byte)_lookAhead; + _lookAhead = RequireByte(); + + return numRead + 1; + } +#endif + + public override int ReadByte() { if (_eofOn00 && _lookAhead <= 0) { diff --git a/crypto/src/asn1/cmp/CertReqTemplateContent.cs b/crypto/src/asn1/cmp/CertReqTemplateContent.cs index b229cd28b..c25c71ad1 100644 --- a/crypto/src/asn1/cmp/CertReqTemplateContent.cs +++ b/crypto/src/asn1/cmp/CertReqTemplateContent.cs @@ -9,12 +9,13 @@ namespace Org.BouncyCastle.Asn1.Cmp * GenRep: {id-it 19}, CertReqTemplateContent | < absent > * <p> * CertReqTemplateValue ::= CertReqTemplateContent - * <p> + * </p><p> * CertReqTemplateContent ::= SEQUENCE { * certTemplate CertTemplate, * keySpec Controls OPTIONAL } - * <p> + * </p><p> * Controls ::= SEQUENCE SIZE (1..MAX) OF AttributeTypeAndValue + * </p> */ public class CertReqTemplateContent : Asn1Encodable diff --git a/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs index fa83841a4..1b3227c47 100644 --- a/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs +++ b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs @@ -234,8 +234,9 @@ namespace Org.BouncyCastle.Asn1.Cmp * 1.2.840.113549.1.9.16.1.21 * <p> * id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types - * <p> + * </p><p> * id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21} + * </p> */ public static readonly DerObjectIdentifier ct_encKeyWithID = new DerObjectIdentifier("1.2.840.113549.1.9.16.1.21"); diff --git a/crypto/src/asn1/cmp/CrlSource.cs b/crypto/src/asn1/cmp/CrlSource.cs index 13aaa526a..9e2526ec2 100644 --- a/crypto/src/asn1/cmp/CrlSource.cs +++ b/crypto/src/asn1/cmp/CrlSource.cs @@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Asn1.Cmp * CRLSource ::= CHOICE { * dpn [0] DistributionPointName, * issuer [1] GeneralNames } - * <p> + * </p> */ public class CrlSource : Asn1Encodable, IAsn1Choice diff --git a/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs b/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs index b1eaf616d..696b08b94 100644 --- a/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs +++ b/crypto/src/asn1/cmp/RootCaKeyUpdateContent.cs @@ -7,14 +7,15 @@ namespace Org.BouncyCastle.Asn1.Cmp * GenRep: {id-it 18}, RootCaKeyUpdateContent | < absent > * <p> * RootCaCertValue ::= CMPCertificate - * <p> + * </p><p> * RootCaKeyUpdateValue ::= RootCaKeyUpdateContent - * <p> + * </p><p> * RootCaKeyUpdateContent ::= SEQUENCE { * newWithNew CMPCertificate, * newWithOld [0] CMPCertificate OPTIONAL, * oldWithNew [1] CMPCertificate OPTIONAL * } + * </p> */ public class RootCaKeyUpdateContent : Asn1Encodable diff --git a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs index 78354896f..f6335cdac 100644 --- a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs +++ b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs @@ -1,6 +1,4 @@ -using System; - -namespace Org.BouncyCastle.Asn1.Cms +namespace Org.BouncyCastle.Asn1.Cms { public class OtherRevocationInfoFormat : Asn1Encodable @@ -44,8 +42,8 @@ namespace Org.BouncyCastle.Asn1.Cms */ public static OtherRevocationInfoFormat GetInstance(object obj) { - if (obj is OtherRevocationInfoFormat) - return (OtherRevocationInfoFormat)obj; + if (obj is OtherRevocationInfoFormat otherRevocationInfoFormat) + return otherRevocationInfoFormat; if (obj != null) return new OtherRevocationInfoFormat(Asn1Sequence.GetInstance(obj)); return null; diff --git a/crypto/src/asn1/cms/Time.cs b/crypto/src/asn1/cms/Time.cs index 89f1e4dae..67c73285b 100644 --- a/crypto/src/asn1/cms/Time.cs +++ b/crypto/src/asn1/cms/Time.cs @@ -35,17 +35,15 @@ namespace Org.BouncyCastle.Asn1.Cms */ public Time(DateTime date) { - string d = date.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z"; + DateTime d = date.ToUniversalTime(); - int year = int.Parse(d.Substring(0, 4)); - - if (year < 1950 || year > 2049) + if (d.Year < 1950 || d.Year > 2049) { time = new DerGeneralizedTime(d); } else { - time = new DerUtcTime(d.Substring(2)); + time = new DerUtcTime(d); } } diff --git a/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs b/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs new file mode 100644 index 000000000..e7208bab2 --- /dev/null +++ b/crypto/src/asn1/cryptlib/CryptlibObjectIdentifiers.cs @@ -0,0 +1,11 @@ +namespace Org.BouncyCastle.Asn1.Cryptlib +{ + internal class CryptlibObjectIdentifiers + { + internal static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029"); + + internal static readonly DerObjectIdentifier ecc = cryptlib.Branch("1.5"); + + internal static readonly DerObjectIdentifier curvey25519 = ecc.Branch("1"); + } +} diff --git a/crypto/src/asn1/x509/KeyPurposeId.cs b/crypto/src/asn1/x509/KeyPurposeId.cs index 1a564b97a..d0b9bb7e6 100644 --- a/crypto/src/asn1/x509/KeyPurposeId.cs +++ b/crypto/src/asn1/x509/KeyPurposeId.cs @@ -1,3 +1,5 @@ +using System; + namespace Org.BouncyCastle.Asn1.X509 { /** @@ -9,30 +11,86 @@ namespace Org.BouncyCastle.Asn1.X509 public sealed class KeyPurposeID : DerObjectIdentifier { - private const string IdKP = "1.3.6.1.5.5.7.3"; + private const string id_kp = "1.3.6.1.5.5.7.3"; - private KeyPurposeID( - string id) + private KeyPurposeID(string id) : base(id) { } public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0"); - public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1"); - public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2"); - public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3"); - public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4"); - public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5"); - public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6"); - public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7"); - public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8"); - public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9"); - - // + + public static readonly KeyPurposeID id_kp_serverAuth = new KeyPurposeID(id_kp + ".1"); + public static readonly KeyPurposeID id_kp_clientAuth = new KeyPurposeID(id_kp + ".2"); + public static readonly KeyPurposeID id_kp_codeSigning = new KeyPurposeID(id_kp + ".3"); + public static readonly KeyPurposeID id_kp_emailProtection = new KeyPurposeID(id_kp + ".4"); + public static readonly KeyPurposeID id_kp_ipsecEndSystem = new KeyPurposeID(id_kp + ".5"); + public static readonly KeyPurposeID id_kp_ipsecTunnel = new KeyPurposeID(id_kp + ".6"); + public static readonly KeyPurposeID id_kp_ipsecUser = new KeyPurposeID(id_kp + ".7"); + public static readonly KeyPurposeID id_kp_timeStamping = new KeyPurposeID(id_kp + ".8"); + public static readonly KeyPurposeID id_kp_OCSPSigning = new KeyPurposeID(id_kp + ".9"); + public static readonly KeyPurposeID id_kp_dvcs = new KeyPurposeID(id_kp + ".10"); + public static readonly KeyPurposeID id_kp_sbgpCertAAServerAuth = new KeyPurposeID(id_kp + ".11"); + public static readonly KeyPurposeID id_kp_scvp_responder = new KeyPurposeID(id_kp + ".12"); + public static readonly KeyPurposeID id_kp_eapOverPPP = new KeyPurposeID(id_kp + ".13"); + public static readonly KeyPurposeID id_kp_eapOverLAN = new KeyPurposeID(id_kp + ".14"); + public static readonly KeyPurposeID id_kp_scvpServer = new KeyPurposeID(id_kp + ".15"); + public static readonly KeyPurposeID id_kp_scvpClient = new KeyPurposeID(id_kp + ".16"); + public static readonly KeyPurposeID id_kp_ipsecIKE = new KeyPurposeID(id_kp + ".17"); + public static readonly KeyPurposeID id_kp_capwapAC = new KeyPurposeID(id_kp + ".18"); + public static readonly KeyPurposeID id_kp_capwapWTP = new KeyPurposeID(id_kp + ".19"); + + public static readonly KeyPurposeID id_kp_cmcCA = new KeyPurposeID(id_kp + ".27"); + public static readonly KeyPurposeID id_kp_cmcRA = new KeyPurposeID(id_kp + ".28"); + public static readonly KeyPurposeID id_kp_cmKGA = new KeyPurposeID(id_kp + ".32"); + + // // microsoft key purpose ids // - public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2"); + public static readonly KeyPurposeID id_kp_smartcardlogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2"); + + public static readonly KeyPurposeID id_kp_macAddress = new KeyPurposeID("1.3.6.1.1.1.1.22"); + + /// <summary>Microsoft Server Gated Crypto (msSGC).</summary> + /// <remarks>see https://www.alvestrand.no/objectid/1.3.6.1.4.1.311.10.3.3.html</remarks> + public static readonly KeyPurposeID id_kp_msSGC = new KeyPurposeID("1.3.6.1.4.1.311.10.3.3"); + + private const string id_pkinit = "1.3.6.1.5.2.3"; + + public static readonly KeyPurposeID scSysNodeNumber = new KeyPurposeID(id_pkinit + ".0"); + public static readonly KeyPurposeID id_pkinit_authData = new KeyPurposeID(id_pkinit + ".1"); + public static readonly KeyPurposeID id_pkinit_DHKeyData = new KeyPurposeID(id_pkinit + ".2"); + public static readonly KeyPurposeID id_pkinit_rkeyData = new KeyPurposeID(id_pkinit + ".3"); + public static readonly KeyPurposeID keyPurposeClientAuth = new KeyPurposeID(id_pkinit + ".4"); + public static readonly KeyPurposeID keyPurposeKdc = new KeyPurposeID(id_pkinit + ".5"); + + /// <summary>Netscape Server Gated Crypto (nsSGC).</summary> + /// <remarks>see https://www.alvestrand.no/objectid/2.16.840.1.113730.4.1.html</remarks> + public static readonly KeyPurposeID id_kp_nsSGC = new KeyPurposeID("2.16.840.1.113730.4.1"); + + [Obsolete("Use 'id_kp_serverAuth' instead")] + public static readonly KeyPurposeID IdKPServerAuth = id_kp_serverAuth; + [Obsolete("Use 'id_kp_clientAuth' instead")] + public static readonly KeyPurposeID IdKPClientAuth = id_kp_clientAuth; + [Obsolete("Use 'id_kp_codeSigning' instead")] + public static readonly KeyPurposeID IdKPCodeSigning = id_kp_codeSigning; + [Obsolete("Use 'id_kp_emailProtection' instead")] + public static readonly KeyPurposeID IdKPEmailProtection = id_kp_emailProtection; + [Obsolete("Use 'id_kp_ipsecEndSystem' instead")] + public static readonly KeyPurposeID IdKPIpsecEndSystem = id_kp_ipsecEndSystem; + [Obsolete("Use 'id_kp_ipsecTunnel' instead")] + public static readonly KeyPurposeID IdKPIpsecTunnel = id_kp_ipsecTunnel; + [Obsolete("Use 'id_kp_ipsecUser' instead")] + public static readonly KeyPurposeID IdKPIpsecUser = id_kp_ipsecUser; + [Obsolete("Use 'id_kp_timeStamping' instead")] + public static readonly KeyPurposeID IdKPTimeStamping = id_kp_timeStamping; + [Obsolete("Use 'id_kp_OCSPSigning' instead")] + public static readonly KeyPurposeID IdKPOcspSigning = id_kp_OCSPSigning; + + [Obsolete("Use 'id_kp_smartcardlogon' instead")] + public static readonly KeyPurposeID IdKPSmartCardLogon = id_kp_smartcardlogon; - public static readonly KeyPurposeID IdKPMacAddress = new KeyPurposeID("1.3.6.1.1.1.1.22"); + [Obsolete("Use 'id_kp_macAddress' instead")] + public static readonly KeyPurposeID IdKPMacAddress = id_kp_macAddress; } } diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs index 1a6ac15c0..8260043aa 100644 --- a/crypto/src/asn1/x509/Time.cs +++ b/crypto/src/asn1/x509/Time.cs @@ -35,17 +35,15 @@ namespace Org.BouncyCastle.Asn1.X509 */ public Time(DateTime date) { - string d = date.ToUniversalTime().ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z"; + DateTime d = date.ToUniversalTime(); - int year = int.Parse(d.Substring(0, 4)); - - if (year < 1950 || year > 2049) + if (d.Year < 1950 || d.Year > 2049) { time = new DerGeneralizedTime(d); } else { - time = new DerUtcTime(d.Substring(2)); + time = new DerUtcTime(d); } } diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs index 1c5ebd7c5..4fbb8baae 100644 --- a/crypto/src/bcpg/ArmoredInputStream.cs +++ b/crypto/src/bcpg/ArmoredInputStream.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -330,6 +331,26 @@ namespace Org.BouncyCastle.Bcpg return pos; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + /* + * TODO Currently can't return partial data when exception thrown (breaking test case), so we don't inherit + * the base class implementation. Probably the reason is that throws don't mark this instance as 'failed'. + */ + int pos = 0; + while (pos < buffer.Length) + { + int b = ReadByte(); + if (b < 0) + break; + + buffer[pos++] = (byte)b; + } + return pos; + } +#endif + public override int ReadByte() { if (start) diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs index 7f3bcc2ef..bfed1972a 100644 --- a/crypto/src/bcpg/ArmoredOutputStream.cs +++ b/crypto/src/bcpg/ArmoredOutputStream.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Reflection; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; @@ -98,7 +99,15 @@ namespace Org.BouncyCastle.Bcpg private static readonly string footerStart = "-----END PGP "; private static readonly string footerTail = "-----"; - private static readonly string Version = "BCPG C# v" + typeof(ArmoredOutputStream).Assembly.GetName().Version; + private static string CreateVersion() + { + var assembly = Assembly.GetExecutingAssembly(); + var title = assembly.GetCustomAttribute<AssemblyTitleAttribute>().Title; + var version = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; + return title + " v" + version; + } + + private static readonly string Version = CreateVersion(); private readonly IDictionary<string, IList<string>> m_headers; diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs index 7a19a90dd..3b6f61bbc 100644 --- a/crypto/src/bcpg/BcpgInputStream.cs +++ b/crypto/src/bcpg/BcpgInputStream.cs @@ -57,6 +57,21 @@ namespace Org.BouncyCastle.Bcpg return 1; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + if (!next) + return m_in.Read(buffer); + + if (nextB < 0) + return 0; + + buffer[0] = (byte)nextB; + next = false; + return 1; + } +#endif + public byte[] ReadAll() { return Streams.ReadAll(this); @@ -312,9 +327,8 @@ namespace Org.BouncyCastle.Bcpg int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; int len = m_in.Read(buffer, offset, readLen); if (len < 1) - { throw new EndOfStreamException("Premature end of stream in PartialInputStream"); - } + dataLength -= len; return len; } @@ -324,6 +338,29 @@ namespace Org.BouncyCastle.Bcpg return 0; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + do + { + if (dataLength != 0) + { + int count = buffer.Length; + int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; + int len = m_in.Read(buffer[..readLen]); + if (len < 1) + throw new EndOfStreamException("Premature end of stream in PartialInputStream"); + + dataLength -= len; + return len; + } + } + while (partial && ReadPartialDataLength() >= 0); + + return 0; + } +#endif + private int ReadPartialDataLength() { int l = m_in.ReadByte(); diff --git a/crypto/src/bcpg/BcpgOutputStream.cs b/crypto/src/bcpg/BcpgOutputStream.cs index fbdd75bff..690686d88 100644 --- a/crypto/src/bcpg/BcpgOutputStream.cs +++ b/crypto/src/bcpg/BcpgOutputStream.cs @@ -164,7 +164,7 @@ namespace Org.BouncyCastle.Bcpg if (partialBuffer != null) { - PartialFlush(true); + PartialFlushLast(); partialBuffer = null; } @@ -215,19 +215,26 @@ namespace Org.BouncyCastle.Bcpg } } - private void PartialFlush(bool isLast) + private void PartialFlush() { - if (isLast) - { - WriteNewPacketLength(partialOffset); - outStr.Write(partialBuffer, 0, partialOffset); - } - else - { - outStr.WriteByte((byte)(0xE0 | partialPower)); - outStr.Write(partialBuffer, 0, partialBufferLength); - } + outStr.WriteByte((byte)(0xE0 | partialPower)); + outStr.Write(partialBuffer, 0, partialBufferLength); + partialOffset = 0; + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void PartialFlush(ref ReadOnlySpan<byte> buffer) + { + outStr.WriteByte((byte)(0xE0 | partialPower)); + outStr.Write(buffer[..partialBufferLength]); + buffer = buffer[partialBufferLength..]; + } +#endif + private void PartialFlushLast() + { + WriteNewPacketLength(partialOffset); + outStr.Write(partialBuffer, 0, partialOffset); partialOffset = 0; } @@ -235,40 +242,71 @@ namespace Org.BouncyCastle.Bcpg { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + PartialWrite(buffer.AsSpan(offset, count)); +#else if (partialOffset == partialBufferLength) { - PartialFlush(false); + PartialFlush(); } if (count <= (partialBufferLength - partialOffset)) { Array.Copy(buffer, offset, partialBuffer, partialOffset, count); partialOffset += count; + return; } - else + + int diff = partialBufferLength - partialOffset; + Array.Copy(buffer, offset, partialBuffer, partialOffset, diff); + offset += diff; + count -= diff; + PartialFlush(); + while (count > partialBufferLength) { - int diff = partialBufferLength - partialOffset; - Array.Copy(buffer, offset, partialBuffer, partialOffset, diff); - offset += diff; - count -= diff; - PartialFlush(false); - while (count > partialBufferLength) - { - Array.Copy(buffer, offset, partialBuffer, 0, partialBufferLength); - offset += partialBufferLength; - count -= partialBufferLength; - PartialFlush(false); - } - Array.Copy(buffer, offset, partialBuffer, 0, count); - partialOffset += count; + Array.Copy(buffer, offset, partialBuffer, 0, partialBufferLength); + offset += partialBufferLength; + count -= partialBufferLength; + PartialFlush(); } + Array.Copy(buffer, offset, partialBuffer, 0, count); + partialOffset = count; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void PartialWrite(ReadOnlySpan<byte> buffer) + { + if (partialOffset == partialBufferLength) + { + PartialFlush(); + } + + if (buffer.Length <= (partialBufferLength - partialOffset)) + { + buffer.CopyTo(partialBuffer.AsSpan(partialOffset)); + partialOffset += buffer.Length; + return; + } + + int diff = partialBufferLength - partialOffset; + buffer[..diff].CopyTo(partialBuffer.AsSpan(partialOffset)); + buffer = buffer[diff..]; + PartialFlush(); + while (buffer.Length > partialBufferLength) + { + PartialFlush(ref buffer); + } + buffer.CopyTo(partialBuffer); + partialOffset = buffer.Length; + } +#endif + private void PartialWriteByte(byte value) { if (partialOffset == partialBufferLength) { - PartialFlush(false); + PartialFlush(); } partialBuffer[partialOffset++] = value; @@ -286,6 +324,20 @@ namespace Org.BouncyCastle.Bcpg } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + if (partialBuffer != null) + { + PartialWrite(buffer); + } + else + { + outStr.Write(buffer); + } + } +#endif + public override void WriteByte(byte value) { if (partialBuffer != null) @@ -370,7 +422,7 @@ namespace Org.BouncyCastle.Bcpg { if (partialBuffer != null) { - PartialFlush(true); + PartialFlushLast(); Array.Clear(partialBuffer, 0, partialBuffer.Length); partialBuffer = null; } diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs index 5b6d9460e..e43100d3a 100644 --- a/crypto/src/bcpg/ECDHPublicBCPGKey.cs +++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC; namespace Org.BouncyCastle.Bcpg @@ -51,6 +52,21 @@ namespace Org.BouncyCastle.Bcpg VerifySymmetricKeyAlgorithm(); } + public ECDHPublicBcpgKey( + DerObjectIdentifier oid, + BigInteger point, + HashAlgorithmTag hashAlgorithm, + SymmetricKeyAlgorithmTag symmetricKeyAlgorithm) + : base(oid, point) + { + reserved = 1; + hashFunctionId = hashAlgorithm; + symAlgorithmId = symmetricKeyAlgorithm; + + VerifyHashAlgorithm(); + VerifySymmetricKeyAlgorithm(); + } + public virtual byte Reserved { get { return reserved; } diff --git a/crypto/src/bcpg/ECSecretBCPGKey.cs b/crypto/src/bcpg/ECSecretBCPGKey.cs index 22e0a3473..eef632263 100644 --- a/crypto/src/bcpg/ECSecretBCPGKey.cs +++ b/crypto/src/bcpg/ECSecretBCPGKey.cs @@ -1,6 +1,5 @@ using System; -using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Bcpg @@ -9,18 +8,18 @@ namespace Org.BouncyCastle.Bcpg public class ECSecretBcpgKey : BcpgObject, IBcpgKey { - internal MPInteger x; + internal readonly MPInteger m_x; public ECSecretBcpgKey( BcpgInputStream bcpgIn) { - this.x = new MPInteger(bcpgIn); + m_x = new MPInteger(bcpgIn); } public ECSecretBcpgKey( BigInteger x) { - this.x = new MPInteger(x); + m_x = new MPInteger(x); } /// <summary>The format, as a string, always "PGP".</summary> @@ -45,12 +44,12 @@ namespace Org.BouncyCastle.Bcpg public override void Encode( BcpgOutputStream bcpgOut) { - bcpgOut.WriteObject(x); + bcpgOut.WriteObject(m_x); } public virtual BigInteger X { - get { return x.Value; } + get { return m_x.Value; } } } } diff --git a/crypto/src/bcpg/EdDsaPublicBcpgKey.cs b/crypto/src/bcpg/EdDsaPublicBcpgKey.cs new file mode 100644 index 000000000..f3250b746 --- /dev/null +++ b/crypto/src/bcpg/EdDsaPublicBcpgKey.cs @@ -0,0 +1,25 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Bcpg +{ + public sealed class EdDsaPublicBcpgKey + : ECPublicBcpgKey + { + internal EdDsaPublicBcpgKey(BcpgInputStream bcpgIn) + : base(bcpgIn) + { + } + + public EdDsaPublicBcpgKey(DerObjectIdentifier oid, ECPoint point) + : base(oid, point) + { + } + + public EdDsaPublicBcpgKey(DerObjectIdentifier oid, BigInteger encodedPoint) + : base(oid, encodedPoint) + { + } + } +} diff --git a/crypto/src/bcpg/EdSecretBcpgKey.cs b/crypto/src/bcpg/EdSecretBcpgKey.cs new file mode 100644 index 000000000..5b53f558d --- /dev/null +++ b/crypto/src/bcpg/EdSecretBcpgKey.cs @@ -0,0 +1,43 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + public sealed class EdSecretBcpgKey + : BcpgObject, IBcpgKey + { + internal readonly MPInteger m_x; + + public EdSecretBcpgKey(BcpgInputStream bcpgIn) + { + m_x = new MPInteger(bcpgIn); + } + + public EdSecretBcpgKey(BigInteger x) + { + m_x = new MPInteger(x); + } + + public string Format => "PGP"; + + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode(BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObject(m_x); + } + + public BigInteger X => m_x.Value; + } +} diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs index bbed941dc..40c696a37 100644 --- a/crypto/src/bcpg/PublicKeyPacket.cs +++ b/crypto/src/bcpg/PublicKeyPacket.cs @@ -28,30 +28,33 @@ namespace Org.BouncyCastle.Bcpg validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte(); } - algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + algorithm = (PublicKeyAlgorithmTag)bcpgIn.ReadByte(); - switch ((PublicKeyAlgorithmTag) algorithm) + switch (algorithm) { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - case PublicKeyAlgorithmTag.RsaSign: - key = new RsaPublicBcpgKey(bcpgIn); - break; - case PublicKeyAlgorithmTag.Dsa: - key = new DsaPublicBcpgKey(bcpgIn); - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - key = new ElGamalPublicBcpgKey(bcpgIn); - break; - case PublicKeyAlgorithmTag.ECDH: - key = new ECDHPublicBcpgKey(bcpgIn); - break; - case PublicKeyAlgorithmTag.ECDsa: - key = new ECDsaPublicBcpgKey(bcpgIn); - break; - default: - throw new IOException("unknown PGP public key algorithm encountered"); + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + key = new RsaPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.Dsa: + key = new DsaPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + key = new ElGamalPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.ECDH: + key = new ECDHPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.ECDsa: + key = new ECDsaPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.EdDsa: + key = new EdDsaPublicBcpgKey(bcpgIn); + break; + default: + throw new IOException("unknown PGP public key algorithm encountered"); } } diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs index dd9cc78e3..a0e8588b3 100644 --- a/crypto/src/bcpg/SignaturePacket.cs +++ b/crypto/src/bcpg/SignaturePacket.cs @@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Bcpg { /// <remarks>Generic signature packet.</remarks> public class SignaturePacket - : ContainedPacket //, PublicKeyAlgorithmTag + : ContainedPacket { private int version; private int signatureType; @@ -128,41 +128,38 @@ namespace Org.BouncyCastle.Bcpg case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaSign: MPInteger v = new MPInteger(bcpgIn); - signature = new MPInteger[]{ v }; + signature = new MPInteger[1]{ v }; break; case PublicKeyAlgorithmTag.Dsa: MPInteger r = new MPInteger(bcpgIn); MPInteger s = new MPInteger(bcpgIn); - signature = new MPInteger[]{ r, s }; + signature = new MPInteger[2]{ r, s }; break; case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes. case PublicKeyAlgorithmTag.ElGamalGeneral: MPInteger p = new MPInteger(bcpgIn); MPInteger g = new MPInteger(bcpgIn); MPInteger y = new MPInteger(bcpgIn); - signature = new MPInteger[]{ p, g, y }; + signature = new MPInteger[3]{ p, g, y }; break; case PublicKeyAlgorithmTag.ECDsa: + case PublicKeyAlgorithmTag.EdDsa: MPInteger ecR = new MPInteger(bcpgIn); MPInteger ecS = new MPInteger(bcpgIn); - signature = new MPInteger[]{ ecR, ecS }; + signature = new MPInteger[2]{ ecR, ecS }; break; default: - if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11) - { - signature = null; - MemoryStream bOut = new MemoryStream(); - int ch; - while ((ch = bcpgIn.ReadByte()) >= 0) - { - bOut.WriteByte((byte) ch); - } - signatureEncoding = bOut.ToArray(); - } - else + if (keyAlgorithm < PublicKeyAlgorithmTag.Experimental_1 || keyAlgorithm > PublicKeyAlgorithmTag.Experimental_11) + throw new IOException("unknown signature key algorithm: " + keyAlgorithm); + + signature = null; + MemoryStream bOut = new MemoryStream(); + int ch; + while ((ch = bcpgIn.ReadByte()) >= 0) { - throw new IOException("unknown signature key algorithm: " + keyAlgorithm); + bOut.WriteByte((byte) ch); } + signatureEncoding = bOut.ToArray(); break; } } @@ -268,56 +265,53 @@ namespace Org.BouncyCastle.Bcpg */ public byte[] GetSignatureTrailer() { - byte[] trailer = null; - if (version == 3) { - trailer = new byte[5]; - - long time = creationTime / 1000L; + long time = creationTime / 1000L; + byte[] trailer = new byte[5]; trailer[0] = (byte)signatureType; trailer[1] = (byte)(time >> 24); trailer[2] = (byte)(time >> 16); - trailer[3] = (byte)(time >> 8); - trailer[4] = (byte)(time); + trailer[3] = (byte)(time >> 8); + trailer[4] = (byte)(time ); + return trailer; } - else - { - MemoryStream sOut = new MemoryStream(); - sOut.WriteByte((byte)this.Version); - sOut.WriteByte((byte)this.SignatureType); - sOut.WriteByte((byte)this.KeyAlgorithm); - sOut.WriteByte((byte)this.HashAlgorithm); + MemoryStream sOut = new MemoryStream(); - MemoryStream hOut = new MemoryStream(); - SignatureSubpacket[] hashed = this.GetHashedSubPackets(); + sOut.WriteByte((byte)Version); + sOut.WriteByte((byte)SignatureType); + sOut.WriteByte((byte)KeyAlgorithm); + sOut.WriteByte((byte)HashAlgorithm); - for (int i = 0; i != hashed.Length; i++) - { - hashed[i].Encode(hOut); - } - - byte[] data = hOut.ToArray(); + // Mark position an reserve two bytes for length + long lengthPosition = sOut.Position; + sOut.WriteByte(0x00); + sOut.WriteByte(0x00); - sOut.WriteByte((byte)(data.Length >> 8)); - sOut.WriteByte((byte)data.Length); - sOut.Write(data, 0, data.Length); + SignatureSubpacket[] hashed = GetHashedSubPackets(); + for (int i = 0; i != hashed.Length; i++) + { + hashed[i].Encode(sOut); + } - byte[] hData = sOut.ToArray(); + ushort dataLength = Convert.ToUInt16(sOut.Position - lengthPosition - 2); + uint hDataLength = Convert.ToUInt32(sOut.Position); - sOut.WriteByte((byte)this.Version); - sOut.WriteByte((byte)0xff); - sOut.WriteByte((byte)(hData.Length>> 24)); - sOut.WriteByte((byte)(hData.Length >> 16)); - sOut.WriteByte((byte)(hData.Length >> 8)); - sOut.WriteByte((byte)(hData.Length)); + sOut.WriteByte((byte)Version); + sOut.WriteByte(0xff); + sOut.WriteByte((byte)(hDataLength >> 24)); + sOut.WriteByte((byte)(hDataLength >> 16)); + sOut.WriteByte((byte)(hDataLength >> 8)); + sOut.WriteByte((byte)(hDataLength )); - trailer = sOut.ToArray(); - } + // Reset position and fill in length + sOut.Position = lengthPosition; + sOut.WriteByte((byte)(dataLength >> 8)); + sOut.WriteByte((byte)(dataLength )); - return trailer; + return sOut.ToArray(); } public PublicKeyAlgorithmTag KeyAlgorithm diff --git a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs index 6c68bccd1..f6827157c 100644 --- a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs +++ b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs @@ -62,9 +62,7 @@ namespace Org.BouncyCastle.Cms Asn1Encodable asn1Params = GenerateAsn1Parameters(macOid, encKeyBytes); - ICipherParameters cipherParameters; - macAlgId = GetAlgorithmIdentifier( - macOid, encKey, asn1Params, out cipherParameters); + macAlgId = GetAlgorithmIdentifier(macOid, encKey, asn1Params, out var cipherParameters); IMac mac = MacUtilities.GetMac(macOid); // TODO Confirm no ParametersWithRandom needed @@ -72,7 +70,7 @@ namespace Org.BouncyCastle.Cms // mac.Init(cipherParameters); mac.Init(encKey); - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); Stream mOut = new TeeOutputStream(bOut, new MacSink(mac)); content.Write(mOut); @@ -97,7 +95,7 @@ namespace Org.BouncyCastle.Cms throw new CmsException("exception decoding algorithm parameters.", e); } - Asn1EncodableVector recipientInfos = new Asn1EncodableVector(); + var recipientInfos = new Asn1EncodableVector(); foreach (RecipientInfoGenerator rig in recipientInfoGenerators) { @@ -115,11 +113,11 @@ namespace Org.BouncyCastle.Cms } } - ContentInfo eci = new ContentInfo(CmsObjectIdentifiers.Data, encContent); - - ContentInfo contentInfo = new ContentInfo( - CmsObjectIdentifiers.AuthenticatedData, - new AuthenticatedData(null, new DerSet(recipientInfos), macAlgId, null, eci, null, macResult, null)); + var eci = new ContentInfo(CmsObjectIdentifiers.Data, encContent); + + var contentInfo = new ContentInfo( + CmsObjectIdentifiers.AuthenticatedData, + new AuthenticatedData(null, new DerSet(recipientInfos), macAlgId, null, eci, null, macResult, null)); return new CmsAuthenticatedData(contentInfo); } diff --git a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs index b2c5cac28..6348431a2 100644 --- a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs @@ -237,7 +237,14 @@ namespace Org.BouncyCastle.Cms macStream.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + macStream.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { macStream.WriteByte(value); } diff --git a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs index 1594500cd..3669c0b3a 100644 --- a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; @@ -118,7 +119,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs index 6a362e13f..ad356a208 100644 --- a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs @@ -240,7 +240,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSProcessableFile.cs b/crypto/src/cms/CMSProcessableFile.cs index 9444f885d..255c8432f 100644 --- a/crypto/src/cms/CMSProcessableFile.cs +++ b/crypto/src/cms/CMSProcessableFile.cs @@ -1,5 +1,3 @@ -#if !PORTABLE || DOTNET -using System; using System.IO; using Org.BouncyCastle.Utilities; @@ -42,4 +40,3 @@ namespace Org.BouncyCastle.Cms } } } -#endif diff --git a/crypto/src/cms/CMSSignedData.cs b/crypto/src/cms/CMSSignedData.cs index 3d4ce05a6..773e15be0 100644 --- a/crypto/src/cms/CMSSignedData.cs +++ b/crypto/src/cms/CMSSignedData.cs @@ -204,6 +204,11 @@ namespace Org.BouncyCastle.Cms return Helper.GetCrls(signedData.CRLs); } + public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat) + { + return Helper.GetOtherRevInfos(signedData.CRLs, otherRevInfoFormat); + } + /// <summary> /// Return the <c>DerObjectIdentifier</c> associated with the encapsulated /// content info structure carried in the signed data. @@ -308,7 +313,7 @@ namespace Org.BouncyCastle.Cms return cms; } - /** + /** * Replace the certificate and CRL information associated with this * CmsSignedData object with the new one passed in. * @@ -318,48 +323,69 @@ namespace Org.BouncyCastle.Cms * @return a new signed data object. * @exception CmsException if there is an error processing the stores */ - public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, IStore<X509Certificate> x509Certs, - IStore<X509Crl> x509Crls, IStore<X509V2AttributeCertificate> x509AttrCerts) + public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls) { - // - // copy - // - CmsSignedData cms = new CmsSignedData(signedData); + return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, null, null); + } + + public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts) + { + return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, x509AttrCerts, null); + } + + public static CmsSignedData ReplaceCertificatesAndRevocations(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts, IStore<OtherRevocationInfoFormat> otherRevocationInfos) + { + // + // copy + // + CmsSignedData cms = new CmsSignedData(signedData); // // replace the certs and crls in the SignedData object // Asn1Set certSet = null; - Asn1Set crlSet = null; + Asn1Set revocationSet = null; if (x509Certs != null || x509AttrCerts != null) { - var certs = new List<Asn1Encodable>(); - + var certificates = new List<Asn1Encodable>(); if (x509Certs != null) { - certs.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); + certificates.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); } if (x509AttrCerts != null) { - certs.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); + certificates.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); } - Asn1Set berSet = CmsUtilities.CreateBerSetFromList(certs); + Asn1Set berSet = CmsUtilities.CreateBerSetFromList(certificates); if (berSet.Count > 0) { certSet = berSet; } } - if (x509Crls != null) + if (x509Crls != null || otherRevocationInfos != null) { - var crls = CmsUtilities.GetCrlsFromStore(x509Crls); + var revocations = new List<Asn1Encodable>(); + if (x509Crls != null) + { + revocations.AddRange(CmsUtilities.GetCrlsFromStore(x509Crls)); + } + if (otherRevocationInfos != null) + { + revocations.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfos)); + } - Asn1Set berSet = CmsUtilities.CreateBerSetFromList(crls); + Asn1Set berSet = CmsUtilities.CreateBerSetFromList(revocations); if (berSet.Count > 0) { - crlSet = berSet; + revocationSet = berSet; } } @@ -371,7 +397,7 @@ namespace Org.BouncyCastle.Cms old.DigestAlgorithms, old.EncapContentInfo, certSet, - crlSet, + revocationSet, old.SignerInfos); // diff --git a/crypto/src/cms/CMSSignedDataParser.cs b/crypto/src/cms/CMSSignedDataParser.cs index 78e29e6a3..c5dc795a8 100644 --- a/crypto/src/cms/CMSSignedDataParser.cs +++ b/crypto/src/cms/CMSSignedDataParser.cs @@ -275,7 +275,14 @@ namespace Org.BouncyCastle.Cms return Helper.GetCrls(_crlSet); } - private void PopulateCertCrlSets() + public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat) + { + PopulateCertCrlSets(); + + return Helper.GetOtherRevInfos(_crlSet, otherRevInfoFormat); + } + + private void PopulateCertCrlSets() { if (_isCertCrlParsed) return; diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs index f934b9259..3f2da5f7e 100644 --- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs @@ -783,7 +783,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs index c16f6e83c..fd40de469 100644 --- a/crypto/src/cms/CMSSignedGenerator.cs +++ b/crypto/src/cms/CMSSignedGenerator.cs @@ -129,12 +129,10 @@ namespace Org.BouncyCastle.Cms m_algorithms["GOST3411WITHGOST3410-2001"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001; m_algorithms["GOST3411WITHECGOST3410-2012-256"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256; m_algorithms["GOST3411WITHECGOST3410-2012-512"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512; - m_algorithms["GOST3411WITHGOST3410-2012-256"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256; - m_algorithms["GOST3411WITHGOST3410-2012-512"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512; + m_algorithms["GOST3411-2012-256WITHECGOST3410"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256; m_algorithms["GOST3411-2012-256WITHECGOST3410-2012-256"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256; + m_algorithms["GOST3411-2012-512WITHECGOST3410"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512; m_algorithms["GOST3411-2012-512WITHECGOST3410-2012-512"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512; - m_algorithms["GOST3411-2012-256WITHGOST3410-2012-256"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256; - m_algorithms["GOST3411-2012-512WITHGOST3410-2012-512"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512; m_algorithms["SHA1WITHPLAIN-ECDSA"] = BsiObjectIdentifiers.ecdsa_plain_SHA1; m_algorithms["SHA224WITHPLAIN-ECDSA"] = BsiObjectIdentifiers.ecdsa_plain_SHA224; m_algorithms["SHA256WITHPLAIN-ECDSA"] = BsiObjectIdentifiers.ecdsa_plain_SHA256; @@ -508,6 +506,8 @@ namespace Org.BouncyCastle.Cms public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id; public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id; public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id; + public static readonly string EncryptionECGost3410_2012_256 = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256.Id; + public static readonly string EncryptionECGost3410_2012_512 = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512.Id; internal List<Asn1Encodable> _certs = new List<Asn1Encodable>(); internal List<Asn1Encodable> _crls = new List<Asn1Encodable>(); @@ -588,6 +588,23 @@ namespace Org.BouncyCastle.Cms _crls.AddRange(CmsUtilities.GetCrlsFromStore(crlStore)); } + public void AddOtherRevocationInfo(OtherRevocationInfoFormat otherRevocationInfo) + { + CmsUtilities.ValidateOtherRevocationInfo(otherRevocationInfo); + _crls.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + + public void AddOtherRevocationInfos(IStore<OtherRevocationInfoFormat> otherRevocationInfoStore) + { + _crls.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfoStore)); + } + + public void AddOtherRevocationInfos(DerObjectIdentifier otherRevInfoFormat, + IStore<Asn1Encodable> otherRevInfoStore) + { + _crls.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevInfoStore, otherRevInfoFormat)); + } + /** * Add a store of precalculated signers to the generator. * diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs index 8df9e8f01..9db39549b 100644 --- a/crypto/src/cms/CMSSignedHelper.cs +++ b/crypto/src/cms/CMSSignedHelper.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.Eac; +using Org.BouncyCastle.Asn1.Esf; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; @@ -85,8 +87,8 @@ namespace Org.BouncyCastle.Cms AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1"); AddEntries(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411", "GOST3410"); AddEntries(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411", "ECGOST3410"); - AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256, "GOST3411_2012_256", "ECGOST3410"); - AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512, "GOST3411_2012_512", "ECGOST3410"); + AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256, "GOST3411-2012-256", "ECGOST3410"); + AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512, "GOST3411-2012-512", "ECGOST3410"); m_encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA"); m_encryptionAlgs.Add(PkcsObjectIdentifiers.RsaEncryption.Id, "RSA"); @@ -119,8 +121,8 @@ namespace Org.BouncyCastle.Cms m_digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256"); m_digestAlgs.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411"); m_digestAlgs.Add("1.3.6.1.4.1.5849.1.2.1", "GOST3411"); - m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "GOST3411_2012_256"); - m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "GOST3411_2012_512"); + m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "GOST3411-2012-256"); + m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "GOST3411-2012-512"); m_digestAliases.Add("SHA1", new string[]{ "SHA-1" }); m_digestAliases.Add("SHA224", new string[]{ "SHA-224" }); @@ -261,6 +263,22 @@ namespace Org.BouncyCastle.Cms { encOID = CmsSignedGenerator.EncryptionECGost3410; } + else if (ecPrivKey.Parameters is ECGost3410Parameters ecGost3410Parameters) + { + var digestParamSet = ecGost3410Parameters.DigestParamSet; + if (digestParamSet.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256)) + { + encOID = CmsSignedGenerator.EncryptionECGost3410_2012_256; + } + else if (digestParamSet.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512)) + { + encOID = CmsSignedGenerator.EncryptionECGost3410_2012_512; + } + else + { + throw new ArgumentException("can't determine GOST3410 algorithm"); + } + } else { // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does? @@ -332,5 +350,29 @@ namespace Org.BouncyCastle.Cms } return CollectionUtilities.CreateStore(contents); } + + internal IStore<Asn1Encodable> GetOtherRevInfos(Asn1Set crlSet, DerObjectIdentifier otherRevInfoFormat) + { + var contents = new List<Asn1Encodable>(); + if (crlSet != null && otherRevInfoFormat != null) + { + foreach (Asn1Encodable ae in crlSet) + { + if (ae != null && ae.ToAsn1Object() is Asn1TaggedObject taggedObject) + { + if (taggedObject.HasContextTag(1)) + { + var otherRevocationInfo = OtherRevocationInfoFormat.GetInstance(taggedObject, false); + + if (otherRevInfoFormat.Equals(otherRevocationInfo.InfoFormat)) + { + contents.Add(otherRevocationInfo.Info); + } + } + } + } + } + return CollectionUtilities.CreateStore(contents); + } } } diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs index d4ca62256..7a66f0c74 100644 --- a/crypto/src/cms/CMSTypedStream.cs +++ b/crypto/src/cms/CMSTypedStream.cs @@ -59,13 +59,6 @@ namespace Org.BouncyCastle.Cms { } -#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public override void CopyTo(Stream destination, int bufferSize) - { - s.CopyTo(destination, bufferSize); - } -#endif - public override int Read(byte[] buf, int off, int len) { return Streams.ReadFully(s, buf, off, len); diff --git a/crypto/src/cms/CMSUtils.cs b/crypto/src/cms/CMSUtils.cs index 6800c1d2a..1a1577c4e 100644 --- a/crypto/src/cms/CMSUtils.cs +++ b/crypto/src/cms/CMSUtils.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.IO; @@ -112,12 +113,46 @@ namespace Org.BouncyCastle.Cms foreach (var crl in crlStore.EnumerateMatches(null)) { result.Add(crl.CertificateList); - } + } } return result; } - internal static Asn1Set CreateBerSetFromList(IEnumerable<Asn1Encodable> elements) + internal static List<Asn1TaggedObject> GetOtherRevocationInfosFromStore( + IStore<OtherRevocationInfoFormat> otherRevocationInfoStore) + { + var result = new List<Asn1TaggedObject>(); + if (otherRevocationInfoStore != null) + { + foreach (var otherRevocationInfo in otherRevocationInfoStore.EnumerateMatches(null)) + { + ValidateOtherRevocationInfo(otherRevocationInfo); + + result.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + } + return result; + } + + internal static List<DerTaggedObject> GetOtherRevocationInfosFromStore(IStore<Asn1Encodable> otherRevInfoStore, + DerObjectIdentifier otherRevInfoFormat) + { + var result = new List<DerTaggedObject>(); + if (otherRevInfoStore != null && otherRevInfoFormat != null) + { + foreach (var otherRevInfo in otherRevInfoStore.EnumerateMatches(null)) + { + var otherRevocationInfo = new OtherRevocationInfoFormat(otherRevInfoFormat, otherRevInfo); + + ValidateOtherRevocationInfo(otherRevocationInfo); + + result.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + } + return result; + } + + internal static Asn1Set CreateBerSetFromList(IEnumerable<Asn1Encodable> elements) { Asn1EncodableVector v = new Asn1EncodableVector(); @@ -157,5 +192,16 @@ namespace Org.BouncyCastle.Cms TbsCertificateStructure tbsCert = GetTbsCertificateStructure(cert); return new IssuerAndSerialNumber(tbsCert.Issuer, tbsCert.SerialNumber.Value); } - } + + internal static void ValidateOtherRevocationInfo(OtherRevocationInfoFormat otherRevocationInfo) + { + if (CmsObjectIdentifiers.id_ri_ocsp_response.Equals(otherRevocationInfo.InfoFormat)) + { + OcspResponse ocspResponse = OcspResponse.GetInstance(otherRevocationInfo.Info); + + if (OcspResponseStatus.Successful != ocspResponse.ResponseStatus.IntValueExact) + throw new ArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); + } + } + } } diff --git a/crypto/src/cms/OriginatorInfoGenerator.cs b/crypto/src/cms/OriginatorInfoGenerator.cs index d7d24dcc4..ec6d2d8d8 100644 --- a/crypto/src/cms/OriginatorInfoGenerator.cs +++ b/crypto/src/cms/OriginatorInfoGenerator.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; @@ -11,30 +9,63 @@ namespace Org.BouncyCastle.Cms { public class OriginatorInfoGenerator { - private readonly List<X509CertificateStructure> origCerts; - private readonly List<CertificateList> origCrls; + private readonly List<Asn1Encodable> origCerts; + private readonly List<Asn1Encodable> origCrls; public OriginatorInfoGenerator(X509Certificate origCert) { - this.origCerts = new List<X509CertificateStructure>(); + this.origCerts = new List<Asn1Encodable>{ origCert.CertificateStructure }; this.origCrls = null; - origCerts.Add(origCert.CertificateStructure); } - public OriginatorInfoGenerator(IStore<X509Certificate> origCerts) - : this(origCerts, null) + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs) + : this(x509Certs, null, null, null) { } - public OriginatorInfoGenerator(IStore<X509Certificate> origCerts, IStore<X509Crl> origCrls) + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls) + : this(x509Certs, x509Crls, null, null) { - this.origCerts = CmsUtilities.GetCertificatesFromStore(origCerts); - this.origCrls = origCrls == null ? null : CmsUtilities.GetCrlsFromStore(origCrls); } - + + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts, IStore<OtherRevocationInfoFormat> otherRevocationInfos) + { + List<Asn1Encodable> certificates = null; + if (x509Certs != null || x509AttrCerts != null) + { + certificates = new List<Asn1Encodable>(); + if (x509Certs != null) + { + certificates.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); + } + if (x509AttrCerts != null) + { + certificates.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); + } + } + + List<Asn1Encodable> revocations = null; + if (x509Crls != null || otherRevocationInfos != null) + { + revocations = new List<Asn1Encodable>(); + if (x509Crls != null) + { + revocations.AddRange(CmsUtilities.GetCrlsFromStore(x509Crls)); + } + if (otherRevocationInfos != null) + { + revocations.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfos)); + } + } + + this.origCerts = certificates; + this.origCrls = revocations; + } + public virtual OriginatorInfo Generate() { - Asn1Set certSet = CmsUtilities.CreateDerSetFromList(origCerts); + Asn1Set certSet = origCerts == null ? null : CmsUtilities.CreateDerSetFromList(origCerts); Asn1Set crlSet = origCrls == null ? null : CmsUtilities.CreateDerSetFromList(origCrls); return new OriginatorInfo(certSet, crlSet); } diff --git a/crypto/src/crypto/engines/Grain128AEADEngine.cs b/crypto/src/crypto/engines/Grain128AEADEngine.cs index 174d010f3..c05cb0115 100644 --- a/crypto/src/crypto/engines/Grain128AEADEngine.cs +++ b/crypto/src/crypto/engines/Grain128AEADEngine.cs @@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Engines */ public void Init(bool forEncryption, ICipherParameters param) { - /** + /* * Grain encryption and decryption is completely symmetrical, so the * 'forEncryption' is irrelevant. */ @@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Engines if (keyBytes.Length != 16) throw new ArgumentException("Grain-128AEAD key must be 128 bits long"); - /** + /* * Initialize variables. */ workingIV = new byte[keyBytes.Length]; @@ -238,7 +238,7 @@ namespace Org.BouncyCastle.Crypto.Engines workingKey = keyBytes; workingIV = ivBytes; - /** + /* * Load NFSR and LFSR */ Pack.LE_To_UInt32(workingKey, 0, nfsr); diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs index 1ccf68902..7c2c1e1f9 100644 --- a/crypto/src/crypto/engines/Salsa20Engine.cs +++ b/crypto/src/crypto/engines/Salsa20Engine.cs @@ -252,11 +252,12 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_LE(x, output, 0); } - internal static void SalsaCore(int rounds, uint[] input, uint[] x) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + internal static void SalsaCore(int rounds, ReadOnlySpan<uint> input, Span<uint> output) { - if (input.Length != 16) + if (input.Length < 16) throw new ArgumentException(); - if (x.Length != 16) + if (output.Length < 16) throw new ArgumentException(); if (rounds % 2 != 0) throw new ArgumentException("Number of rounds must be even"); @@ -266,7 +267,7 @@ namespace Org.BouncyCastle.Crypto.Engines { Vector128<uint> b0, b1, b2, b3; { - var I = MemoryMarshal.AsBytes(input.AsSpan(0, 16)); + var I = MemoryMarshal.AsBytes(input[..16]); var t0 = MemoryMarshal.Read<Vector128<short>>(I[0x00..0x10]); var t1 = MemoryMarshal.Read<Vector128<short>>(I[0x10..0x20]); var t2 = MemoryMarshal.Read<Vector128<short>>(I[0x20..0x30]); @@ -315,7 +316,7 @@ namespace Org.BouncyCastle.Crypto.Engines var v2 = Sse41.Blend(u0, u2, 0x0F); var v3 = Sse41.Blend(u1, u3, 0x3C); - var X = MemoryMarshal.AsBytes(x.AsSpan(0, 16)); + var X = MemoryMarshal.AsBytes(output[..16]); MemoryMarshal.Write(X[0x00..0x10], ref v0); MemoryMarshal.Write(X[0x10..0x20], ref v1); MemoryMarshal.Write(X[0x20..0x30], ref v2); @@ -355,23 +356,81 @@ namespace Org.BouncyCastle.Crypto.Engines QuarterRound(ref x15, ref x12, ref x13, ref x14); } - x[ 0] = x00 + input[ 0]; - x[ 1] = x01 + input[ 1]; - x[ 2] = x02 + input[ 2]; - x[ 3] = x03 + input[ 3]; - x[ 4] = x04 + input[ 4]; - x[ 5] = x05 + input[ 5]; - x[ 6] = x06 + input[ 6]; - x[ 7] = x07 + input[ 7]; - x[ 8] = x08 + input[ 8]; - x[ 9] = x09 + input[ 9]; - x[10] = x10 + input[10]; - x[11] = x11 + input[11]; - x[12] = x12 + input[12]; - x[13] = x13 + input[13]; - x[14] = x14 + input[14]; - x[15] = x15 + input[15]; + output[ 0] = x00 + input[ 0]; + output[ 1] = x01 + input[ 1]; + output[ 2] = x02 + input[ 2]; + output[ 3] = x03 + input[ 3]; + output[ 4] = x04 + input[ 4]; + output[ 5] = x05 + input[ 5]; + output[ 6] = x06 + input[ 6]; + output[ 7] = x07 + input[ 7]; + output[ 8] = x08 + input[ 8]; + output[ 9] = x09 + input[ 9]; + output[10] = x10 + input[10]; + output[11] = x11 + input[11]; + output[12] = x12 + input[12]; + output[13] = x13 + input[13]; + output[14] = x14 + input[14]; + output[15] = x15 + input[15]; } +#else + internal static void SalsaCore(int rounds, uint[] input, uint[] output) + { + if (input.Length < 16) + throw new ArgumentException(); + if (output.Length < 16) + throw new ArgumentException(); + if (rounds % 2 != 0) + throw new ArgumentException("Number of rounds must be even"); + + uint x00 = input[ 0]; + uint x01 = input[ 1]; + uint x02 = input[ 2]; + uint x03 = input[ 3]; + uint x04 = input[ 4]; + uint x05 = input[ 5]; + uint x06 = input[ 6]; + uint x07 = input[ 7]; + uint x08 = input[ 8]; + uint x09 = input[ 9]; + uint x10 = input[10]; + uint x11 = input[11]; + uint x12 = input[12]; + uint x13 = input[13]; + uint x14 = input[14]; + uint x15 = input[15]; + + for (int i = rounds; i > 0; i -= 2) + { + QuarterRound(ref x00, ref x04, ref x08, ref x12); + QuarterRound(ref x05, ref x09, ref x13, ref x01); + QuarterRound(ref x10, ref x14, ref x02, ref x06); + QuarterRound(ref x15, ref x03, ref x07, ref x11); + + QuarterRound(ref x00, ref x01, ref x02, ref x03); + QuarterRound(ref x05, ref x06, ref x07, ref x04); + QuarterRound(ref x10, ref x11, ref x08, ref x09); + QuarterRound(ref x15, ref x12, ref x13, ref x14); + } + + output[ 0] = x00 + input[ 0]; + output[ 1] = x01 + input[ 1]; + output[ 2] = x02 + input[ 2]; + output[ 3] = x03 + input[ 3]; + output[ 4] = x04 + input[ 4]; + output[ 5] = x05 + input[ 5]; + output[ 6] = x06 + input[ 6]; + output[ 7] = x07 + input[ 7]; + output[ 8] = x08 + input[ 8]; + output[ 9] = x09 + input[ 9]; + output[10] = x10 + input[10]; + output[11] = x11 + input[11]; + output[12] = x12 + input[12]; + output[13] = x13 + input[13]; + output[14] = x14 + input[14]; + output[15] = x15 + input[15]; + } +#endif internal void ResetLimitCounter() { diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs index bec459215..47f714a64 100644 --- a/crypto/src/crypto/engines/SerpentEngine.cs +++ b/crypto/src/crypto/engines/SerpentEngine.cs @@ -26,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.Engines * @param key The user-key bytes (multiples of 4) to use. * @exception ArgumentException */ - protected override int[] MakeWorkingKey(byte[] key) + internal override int[] MakeWorkingKey(byte[] key) { // // pad key to 256 bits @@ -151,7 +151,7 @@ namespace Org.BouncyCastle.Crypto.Engines } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - protected override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + internal override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { X0 = (int)Pack.LE_To_UInt32(input); X1 = (int)Pack.LE_To_UInt32(input[4..]); @@ -197,7 +197,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_LE((uint)(wKey[131] ^ X3), output[12..]); } - protected override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + internal override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { X0 = wKey[128] ^ (int)Pack.LE_To_UInt32(input); X1 = wKey[129] ^ (int)Pack.LE_To_UInt32(input[4..]); @@ -274,7 +274,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_LE((uint)(X3 ^ wKey[3]), output[12..]); } #else - protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff) + internal override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff) { X0 = (int)Pack.LE_To_UInt32(input, inOff); X1 = (int)Pack.LE_To_UInt32(input, inOff + 4); @@ -320,7 +320,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_LE((uint)(wKey[131] ^ X3), output, outOff + 12); } - protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff) + internal override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff) { X0 = wKey[128] ^ (int)Pack.LE_To_UInt32(input, inOff); X1 = wKey[129] ^ (int)Pack.LE_To_UInt32(input, inOff + 4); diff --git a/crypto/src/crypto/engines/SerpentEngineBase.cs b/crypto/src/crypto/engines/SerpentEngineBase.cs index 0ce3a0e4f..44020f06f 100644 --- a/crypto/src/crypto/engines/SerpentEngineBase.cs +++ b/crypto/src/crypto/engines/SerpentEngineBase.cs @@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Crypto.Engines protected int X0, X1, X2, X3; // registers - protected SerpentEngineBase() + internal SerpentEngineBase() { } @@ -474,14 +474,14 @@ namespace Org.BouncyCastle.Crypto.Engines X0 = Integers.RotateRight(x0, 13); } - protected abstract int[] MakeWorkingKey(byte[] key); + internal abstract int[] MakeWorkingKey(byte[] key); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - protected abstract void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output); - protected abstract void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output); + internal abstract void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output); + internal abstract void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output); #else - protected abstract void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff); - protected abstract void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff); + internal abstract void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff); + internal abstract void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff); #endif } } diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs index 4a5355963..c6a3e458e 100644 --- a/crypto/src/crypto/engines/SkipjackEngine.cs +++ b/crypto/src/crypto/engines/SkipjackEngine.cs @@ -8,12 +8,12 @@ namespace Org.BouncyCastle.Crypto.Engines /** * a class that provides a basic SKIPJACK engine. */ - public class SkipjackEngine + public sealed class SkipjackEngine : IBlockCipher { - const int BLOCK_SIZE = 8; + private const int BLOCK_SIZE = 8; - static readonly short [] ftable = + private static readonly short[] ftable = { 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9, 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28, @@ -44,14 +44,12 @@ namespace Org.BouncyCastle.Crypto.Engines * @exception ArgumentException if the parameters argument is * inappropriate. */ - public virtual void Init( - bool forEncryption, - ICipherParameters parameters) + public void Init(bool forEncryption, ICipherParameters parameters) { - if (!(parameters is KeyParameter)) + if (!(parameters is KeyParameter keyParameter)) throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + Platform.GetTypeName(parameters)); - byte[] keyBytes = ((KeyParameter)parameters).GetKey(); + byte[] keyBytes = keyParameter.GetKey(); this.encrypting = forEncryption; this.key0 = new int[32]; @@ -63,26 +61,26 @@ namespace Org.BouncyCastle.Crypto.Engines // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply // and an addition). // - for (int i = 0; i < 32; i ++) + for (int i = 0; i < 32; i++) { - key0[i] = keyBytes[(i * 4) % 10] & 0xff; - key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff; - key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff; - key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff; + key0[i] = keyBytes[(i * 4 + 0) % 10]; + key1[i] = keyBytes[(i * 4 + 1) % 10]; + key2[i] = keyBytes[(i * 4 + 2) % 10]; + key3[i] = keyBytes[(i * 4 + 3) % 10]; } } - public virtual string AlgorithmName + public string AlgorithmName { get { return "SKIPJACK"; } } - public virtual int GetBlockSize() + public int GetBlockSize() { return BLOCK_SIZE; } - public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) + public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { if (key1 == null) throw new InvalidOperationException("SKIPJACK engine not initialised"); @@ -114,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Engines } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output) + public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output) { if (key1 == null) throw new InvalidOperationException("SKIPJACK engine not initialised"); @@ -156,7 +154,7 @@ namespace Org.BouncyCastle.Crypto.Engines } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public virtual int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { int w1 = (input[0] << 8) + (input[1] & 0xff); int w2 = (input[2] << 8) + (input[3] & 0xff); @@ -200,7 +198,7 @@ namespace Org.BouncyCastle.Crypto.Engines return BLOCK_SIZE; } - public virtual int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { int w2 = (input[0] << 8) + (input[1] & 0xff); int w1 = (input[2] << 8) + (input[3] & 0xff); @@ -245,7 +243,7 @@ namespace Org.BouncyCastle.Crypto.Engines } #else - public virtual int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) + private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff); int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff); @@ -289,7 +287,7 @@ namespace Org.BouncyCastle.Crypto.Engines return BLOCK_SIZE; } - public virtual int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) + private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff); int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff); diff --git a/crypto/src/crypto/engines/TnepresEngine.cs b/crypto/src/crypto/engines/TnepresEngine.cs index 50f5a58c4..7751e20bc 100644 --- a/crypto/src/crypto/engines/TnepresEngine.cs +++ b/crypto/src/crypto/engines/TnepresEngine.cs @@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Crypto.Engines * @param key The user-key bytes (multiples of 4) to use. * @exception ArgumentException */ - protected override int[] MakeWorkingKey(byte[] key) + internal override int[] MakeWorkingKey(byte[] key) { // // pad key to 256 bits @@ -158,7 +158,7 @@ namespace Org.BouncyCastle.Crypto.Engines } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - protected override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + internal override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { X3 = (int)Pack.BE_To_UInt32(input); X2 = (int)Pack.BE_To_UInt32(input[4..]); @@ -204,7 +204,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_BE((uint)(wKey[128] ^ X0), output[12..]); } - protected override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + internal override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { X3 = wKey[131] ^ (int)Pack.BE_To_UInt32(input); X2 = wKey[130] ^ (int)Pack.BE_To_UInt32(input[4..]); @@ -281,7 +281,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_BE((uint)(X0 ^ wKey[0]), output[12..]); } #else - protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff) + internal override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff) { X3 = (int)Pack.BE_To_UInt32(input, inOff); X2 = (int)Pack.BE_To_UInt32(input, inOff + 4); @@ -327,7 +327,7 @@ namespace Org.BouncyCastle.Crypto.Engines Pack.UInt32_To_BE((uint)(wKey[128] ^ X0), output, outOff + 12); } - protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff) + internal override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff) { X3 = wKey[131] ^ (int)Pack.BE_To_UInt32(input, inOff); X2 = wKey[130] ^ (int)Pack.BE_To_UInt32(input, inOff + 4); diff --git a/crypto/src/crypto/generators/HKdfBytesGenerator.cs b/crypto/src/crypto/generators/HkdfBytesGenerator.cs index 43cd66525..43cd66525 100644 --- a/crypto/src/crypto/generators/HKdfBytesGenerator.cs +++ b/crypto/src/crypto/generators/HkdfBytesGenerator.cs diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs index 1a8d4a003..fef842be2 100644 --- a/crypto/src/crypto/generators/SCrypt.cs +++ b/crypto/src/crypto/generators/SCrypt.cs @@ -102,7 +102,76 @@ namespace Org.BouncyCastle.Crypto.Generators return key.GetKey(); } - private static void SMix(uint[] B, int BOff, int N, int d, int r) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private static void SMix(uint[] B, int BOff, int N, int d, int r) + { + int powN = Integers.NumberOfTrailingZeros(N); + int blocksPerChunk = N >> d; + int chunkCount = 1 << d, chunkMask = blocksPerChunk - 1, chunkPow = powN - d; + + int BCount = r * 32; + + uint[] blockY = new uint[BCount]; + + uint[][] VV = new uint[chunkCount][]; + + try + { + var X = B.AsSpan(BOff, BCount); + + for (int c = 0; c < chunkCount; ++c) + { + uint[] V = new uint[blocksPerChunk * BCount]; + VV[c] = V; + + Nat.Copy(BCount, X, V); + int off = 0; + for (int i = 1; i < blocksPerChunk; ++i) + { + BlockMix(V.AsSpan(off, BCount), V.AsSpan(off + BCount)); + off += BCount; + } + BlockMix(V.AsSpan()[^BCount..], X); + } + + uint mask = (uint)N - 1; + for (int i = 0; i < N; ++i) + { + int j = (int)(X[BCount - 16] & mask); + uint[] V = VV[j >> chunkPow]; + int VOff = (j & chunkMask) * BCount; + Nat.Xor(BCount, V.AsSpan(VOff), X, blockY); + BlockMix(blockY, X); + } + } + finally + { + ClearAll(VV); + Clear(blockY); + } + } + + private static void BlockMix(Span<uint> B, Span<uint> Y) + { + int BCount = B.Length; + int half = BCount >> 1; + var y1 = B[^16..]; + + for (int pos = 0; pos < BCount; pos += 32) + { + var b0 = B[pos..]; + var y0 = Y[(pos >> 1)..]; + Nat512.Xor(y1, b0, y0); + Salsa20Engine.SalsaCore(8, y0, y0); + + var b1 = b0[16..]; + y1 = y0[half..]; + Nat512.Xor(y0, b1, y1); + Salsa20Engine.SalsaCore(8, y1, y1); + } + } +#else + private static void SMix(uint[] B, int BOff, int N, int d, int r) { int powN = Integers.NumberOfTrailingZeros(N); int blocksPerChunk = N >> d; @@ -111,7 +180,6 @@ namespace Org.BouncyCastle.Crypto.Generators int BCount = r * 32; uint[] blockX1 = new uint[16]; - uint[] blockX2 = new uint[16]; uint[] blockY = new uint[BCount]; uint[] X = new uint[BCount]; @@ -131,10 +199,10 @@ namespace Org.BouncyCastle.Crypto.Generators { Array.Copy(X, 0, V, off, BCount); off += BCount; - BlockMix(X, blockX1, blockX2, blockY, r); + BlockMix(X, blockX1, blockY, r); Array.Copy(blockY, 0, V, off, BCount); off += BCount; - BlockMix(blockY, blockX1, blockX2, X, r); + BlockMix(blockY, blockX1, X, r); } } @@ -146,7 +214,7 @@ namespace Org.BouncyCastle.Crypto.Generators int VOff = (j & chunkMask) * BCount; Nat.Xor(BCount, V, VOff, X, 0, blockY, 0); - BlockMix(blockY, blockX1, blockX2, X, r); + BlockMix(blockY, blockX1, X, r); } Array.Copy(X, 0, B, BOff, BCount); @@ -154,29 +222,30 @@ namespace Org.BouncyCastle.Crypto.Generators finally { ClearAll(VV); - ClearAll(X, blockX1, blockX2, blockY); + ClearAll(X, blockX1, blockY); } } - private static void BlockMix(uint[] B, uint[] X1, uint[] X2, uint[] Y, int r) + private static void BlockMix(uint[] B, uint[] X1, uint[] Y, int r) { - Array.Copy(B, B.Length - 16, X1, 0, 16); + Array.Copy(B, B.Length - 16, X1, 0, 16); - int BOff = 0, YOff = 0, halfLen = B.Length >> 1; + int BOff = 0, YOff = 0, halfLen = B.Length >> 1; - for (int i = 2 * r; i > 0; --i) - { - Nat512.Xor(X1, 0, B, BOff, X2, 0); + for (int i = 2 * r; i > 0; --i) + { + Nat512.XorTo(B, BOff, X1, 0); - Salsa20Engine.SalsaCore(8, X2, X1); - Array.Copy(X1, 0, Y, YOff, 16); + Salsa20Engine.SalsaCore(8, X1, X1); + Array.Copy(X1, 0, Y, YOff, 16); - YOff = halfLen + BOff - YOff; - BOff += 16; - } - } + YOff = halfLen + BOff - YOff; + BOff += 16; + } + } +#endif - private static void Clear(Array array) + private static void Clear(Array array) { if (array != null) { diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs index abcdca959..7bce9843f 100644 --- a/crypto/src/crypto/modes/CfbBlockCipher.cs +++ b/crypto/src/crypto/modes/CfbBlockCipher.cs @@ -129,7 +129,7 @@ namespace Org.BouncyCastle.Crypto.Modes #endif #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { Check.DataLength(input, blockSize, "input buffer too short"); Check.OutputLength(output, blockSize, "output buffer too short"); @@ -150,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Modes return blockSize; } - public int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) + private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output) { Check.DataLength(input, blockSize, "input buffer too short"); Check.OutputLength(output, blockSize, "output buffer too short"); @@ -171,7 +171,7 @@ namespace Org.BouncyCastle.Crypto.Modes return blockSize; } #else - public int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) + private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { Check.DataLength(input, inOff, blockSize, "input buffer too short"); Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short"); @@ -192,7 +192,7 @@ namespace Org.BouncyCastle.Crypto.Modes return blockSize; } - public int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) + private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { Check.DataLength(input, inOff, blockSize, "input buffer too short"); Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short"); diff --git a/crypto/src/crypto/modes/ChaCha20Poly1305.cs b/crypto/src/crypto/modes/ChaCha20Poly1305.cs index 299387cdf..2fce81e22 100644 --- a/crypto/src/crypto/modes/ChaCha20Poly1305.cs +++ b/crypto/src/crypto/modes/ChaCha20Poly1305.cs @@ -763,6 +763,18 @@ namespace Org.BouncyCastle.Crypto.Modes private void InitMac() { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span<byte> firstBlock = stackalloc byte[64]; + try + { + mChacha20.ProcessBytes(firstBlock, firstBlock); + mPoly1305.Init(new KeyParameter(firstBlock[..32])); + } + finally + { + firstBlock.Fill(0x00); + } +#else byte[] firstBlock = new byte[64]; try { @@ -773,6 +785,7 @@ namespace Org.BouncyCastle.Crypto.Modes { Array.Clear(firstBlock, 0, 64); } +#endif } private void PadMac(ulong count) diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs index 8cc701cca..e67b4e9af 100644 --- a/crypto/src/crypto/modes/OCBBlockCipher.cs +++ b/crypto/src/crypto/modes/OCBBlockCipher.cs @@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Crypto.Modes /// <para>https://mailarchive.ietf.org/arch/msg/cfrg/qLTveWOdTJcLn4HP3ev-vrj05Vg/</para> /// Text reproduced below: /// <para> - /// Phillip Rogaway<rogaway@cs.ucdavis.edu&rt; Sat, 27 February 2021 02:46 UTC + /// Phillip Rogaway<rogaway@cs.ucdavis.edu> Sat, 27 February 2021 02:46 UTC /// /// I can confirm that I have abandoned all OCB patents and placed into the public domain all OCB-related IP of /// mine. While I have been telling people this for quite some time, I don't think I ever made a proper announcement diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs index db2d0759e..ea8d28771 100644 --- a/crypto/src/crypto/operators/Asn1Signature.cs +++ b/crypto/src/crypto/operators/Asn1Signature.cs @@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Rosstandart; using Org.BouncyCastle.Asn1.TeleTrust; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; @@ -92,12 +93,16 @@ namespace Org.BouncyCastle.Crypto.Operators m_algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); m_algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); m_algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); - - // - // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. - // The parameters field SHALL be NULL for RSA based signature algorithms. - // - noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); + m_algorithms.Add("GOST3411-2012-256WITHECGOST3410", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256); + m_algorithms.Add("GOST3411-2012-256WITHECGOST3410-2012-256", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256); + m_algorithms.Add("GOST3411-2012-512WITHECGOST3410", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512); + m_algorithms.Add("GOST3411-2012-512WITHECGOST3410-2012-512", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224); noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256); noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384); @@ -189,6 +194,14 @@ namespace Org.BouncyCastle.Crypto.Operators { return "GOST3411"; } + else if (RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Equals(digestAlgOID)) + { + return "GOST3411-2012-256"; + } + else if (RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Equals(digestAlgOID)) + { + return "GOST3411-2012-512"; + } else { return digestAlgOID.Id; diff --git a/crypto/src/crypto/parameters/HKdfParameters.cs b/crypto/src/crypto/parameters/HkdfParameters.cs index 6d1465e4c..6d1465e4c 100644 --- a/crypto/src/crypto/parameters/HKdfParameters.cs +++ b/crypto/src/crypto/parameters/HkdfParameters.cs diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs index 44a9c261f..dcd3baa1c 100644 --- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs +++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs @@ -7,7 +7,7 @@ namespace Org.BouncyCastle.Crypto.Prng /// Uses RandomNumberGenerator.Create() to get randomness generator /// </summary> public sealed class CryptoApiRandomGenerator - : IRandomGenerator + : IRandomGenerator, IDisposable { private readonly RandomNumberGenerator m_randomNumberGenerator; @@ -18,7 +18,8 @@ namespace Org.BouncyCastle.Crypto.Prng public CryptoApiRandomGenerator(RandomNumberGenerator randomNumberGenerator) { - m_randomNumberGenerator = randomNumberGenerator; + m_randomNumberGenerator = randomNumberGenerator ?? + throw new ArgumentNullException(nameof(randomNumberGenerator)); } #region IRandomGenerator Members @@ -76,5 +77,14 @@ namespace Org.BouncyCastle.Crypto.Prng #endif #endregion + + #region IDisposable Members + + public void Dispose() + { + m_randomNumberGenerator.Dispose(); + } + + #endregion } } diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs index 330708088..3afc843cd 100644 --- a/crypto/src/math/ec/ECFieldElement.cs +++ b/crypto/src/math/ec/ECFieldElement.cs @@ -785,9 +785,9 @@ namespace Org.BouncyCastle.Math.EC LongArray ab = ax.Multiply(bx, m, ks); LongArray xy = xx.Multiply(yx, m, ks); - if (ab == ax || ab == bx) + if (LongArray.AreAliased(ref ab, ref ax) || LongArray.AreAliased(ref ab, ref bx)) { - ab = (LongArray)ab.Copy(); + ab = ab.Copy(); } ab.AddShiftedByWords(xy, 0); @@ -827,9 +827,9 @@ namespace Org.BouncyCastle.Math.EC LongArray aa = ax.Square(m, ks); LongArray xy = xx.Multiply(yx, m, ks); - if (aa == ax) + if (LongArray.AreAliased(ref aa, ref ax)) { - aa = (LongArray)aa.Copy(); + aa = aa.Copy(); } aa.AddShiftedByWords(xy, 0); diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs index 90ca49c77..aa36de215 100644 --- a/crypto/src/math/ec/LongArray.cs +++ b/crypto/src/math/ec/LongArray.cs @@ -1,27 +1,32 @@ using System; using System.Text; - +using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Math.EC { - internal sealed class LongArray + internal struct LongArray { + internal static bool AreAliased(ref LongArray a, ref LongArray b) + { + return a.m_data == b.m_data; + } + // TODO make m fixed for the LongArray, and hence compute T once and for all private ulong[] m_data; - public LongArray(int intLen) + internal LongArray(int intLen) { m_data = new ulong[intLen]; } - public LongArray(ulong[] data) + internal LongArray(ulong[] data) { m_data = data; } - public LongArray(ulong[] data, int off, int len) + internal LongArray(ulong[] data, int off, int len) { if (off == 0 && len == data.Length) { @@ -34,16 +39,14 @@ namespace Org.BouncyCastle.Math.EC } } - public LongArray(BigInteger bigInt) + internal LongArray(BigInteger bigInt) { if (bigInt == null || bigInt.SignValue < 0) - { - throw new ArgumentException("invalid F2m field value", "bigInt"); - } + throw new ArgumentException("invalid F2m field value", nameof(bigInt)); if (bigInt.SignValue == 0) { - m_data = new ulong[]{ 0UL }; + m_data = new ulong[1]{ 0UL }; return; } @@ -93,51 +96,44 @@ namespace Org.BouncyCastle.Math.EC Array.Copy(m_data, 0, z, zOff, m_data.Length); } - public bool IsOne() + internal bool IsOne() { ulong[] a = m_data; int aLen = a.Length; if (aLen < 1 || a[0] != 1UL) - { return false; - } + for (int i = 1; i < aLen; ++i) { if (a[i] != 0UL) - { return false; - } } return true; } - public bool IsZero() + internal bool IsZero() { ulong[] a = m_data; for (int i = 0; i < a.Length; ++i) { if (a[i] != 0UL) - { return false; - } } return true; } - public int GetUsedLength() + internal int GetUsedLength() { return GetUsedLengthFrom(m_data.Length); } - public int GetUsedLengthFrom(int from) + internal int GetUsedLengthFrom(int from) { ulong[] a = m_data; from = System.Math.Min(from, a.Length); if (from < 1) - { return 0; - } // Check if first element will act as sentinel if (a[0] != 0UL) @@ -160,16 +156,15 @@ namespace Org.BouncyCastle.Math.EC return 0; } - public int Degree() + internal int Degree() { int i = m_data.Length; ulong w; do { if (i == 0) - { return 0; - } + w = m_data[--i]; } while (w == 0UL); @@ -184,9 +179,8 @@ namespace Org.BouncyCastle.Math.EC do { if (i == 0) - { return 0; - } + w = m_data[--i]; } while (w == 0); @@ -206,13 +200,11 @@ namespace Org.BouncyCastle.Math.EC return newInts; } - public BigInteger ToBigInteger() + internal BigInteger ToBigInteger() { int usedLen = GetUsedLength(); if (usedLen == 0) - { return BigInteger.Zero; - } ulong highestInt = m_data[usedLen - 1]; byte[] temp = new byte[8]; @@ -273,12 +265,10 @@ namespace Org.BouncyCastle.Math.EC return prev; } - public LongArray AddOne() + internal LongArray AddOne() { if (m_data.Length == 0) - { - return new LongArray(new ulong[]{ 1UL }); - } + return new LongArray(new ulong[1]{ 1UL }); int resultLen = System.Math.Max(1, GetUsedLength()); ulong[] data = ResizedData(resultLen); @@ -333,13 +323,11 @@ namespace Org.BouncyCastle.Math.EC return prev; } - public void AddShiftedByWords(LongArray other, int words) + internal void AddShiftedByWords(LongArray other, int words) { int otherUsedLen = other.GetUsedLength(); if (otherUsedLen == 0) - { return; - } int minLen = otherUsedLen + words; if (minLen > m_data.Length) @@ -352,18 +340,12 @@ namespace Org.BouncyCastle.Math.EC private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, int count) { - for (int i = 0; i < count; ++i) - { - x[xOff + i] ^= y[yOff + i]; - } + Nat.XorTo64(count, y, yOff, x, xOff); } private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff, int count) { - for (int i = 0; i < count; ++i) - { - z[zOff + i] = x[xOff + i] ^ y[yOff + i]; - } + Nat.Xor64(count, x, xOff, y, yOff, z, zOff); } private static void AddBoth(ulong[] x, int xOff, ulong[] y1, int y1Off, ulong[] y2, int y2Off, int count) @@ -393,7 +375,7 @@ namespace Org.BouncyCastle.Math.EC } } - public bool TestBitZero() + internal bool TestBitZero() { return m_data.Length > 0 && (m_data[0] & 1UL) != 0; } @@ -439,21 +421,18 @@ namespace Org.BouncyCastle.Math.EC } } - public LongArray ModMultiplyLD(LongArray other, int m, int[] ks) + internal LongArray ModMultiplyLD(LongArray other, int m, int[] ks) { /* * Find out the degree of each argument and handle the zero cases */ int aDeg = Degree(); if (aDeg == 0) - { return this; - } + int bDeg = other.Degree(); if (bDeg == 0) - { return other; - } /* * Swap if necessary so that A is the smaller argument @@ -476,9 +455,7 @@ namespace Org.BouncyCastle.Math.EC { ulong a0 = A.m_data[0]; if (a0 == 1UL) - { return B; - } /* * Fast path for small A, with performance dependent only on the number of set bits @@ -571,21 +548,18 @@ namespace Org.BouncyCastle.Math.EC return ReduceResult(c, 0, cLen, m, ks); } - public LongArray ModMultiply(LongArray other, int m, int[] ks) + internal LongArray ModMultiply(LongArray other, int m, int[] ks) { /* * Find out the degree of each argument and handle the zero cases */ int aDeg = Degree(); if (aDeg == 0) - { return this; - } + int bDeg = other.Degree(); if (bDeg == 0) - { return other; - } /* * Swap if necessary so that A is the smaller argument @@ -608,9 +582,7 @@ namespace Org.BouncyCastle.Math.EC { ulong a0 = A.m_data[0]; if (a0 == 1UL) - { return B; - } /* * Fast path for small A, with performance dependent only on the number of set bits @@ -681,9 +653,8 @@ namespace Org.BouncyCastle.Math.EC uint v = (uint)aVal & MASK; aVal >>= 4; AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); if (aVal == 0UL) - { break; - } + cOff += cLen; } } @@ -702,28 +673,25 @@ namespace Org.BouncyCastle.Math.EC return ReduceResult(c, 0, cLen, m, ks); } - //public LongArray ModReduce(int m, int[] ks) + //internal LongArray ModReduce(int m, int[] ks) //{ // ulong[] buf = Arrays.Clone(m_data); // int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); // return new LongArray(buf, 0, rLen); //} - public LongArray Multiply(LongArray other, int m, int[] ks) + internal LongArray Multiply(LongArray other, int m, int[] ks) { /* * Find out the degree of each argument and handle the zero cases */ int aDeg = Degree(); if (aDeg == 0) - { return this; - } + int bDeg = other.Degree(); if (bDeg == 0) - { return other; - } /* * Swap if necessary so that A is the smaller argument @@ -746,9 +714,7 @@ namespace Org.BouncyCastle.Math.EC { ulong a0 = A.m_data[0]; if (a0 == 1UL) - { return B; - } /* * Fast path for small A, with performance dependent only on the number of set bits @@ -820,9 +786,8 @@ namespace Org.BouncyCastle.Math.EC uint v = (uint)aVal & MASK; aVal >>= 4; AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); if (aVal == 0UL) - { break; - } + cOff += cLen; } } @@ -842,7 +807,7 @@ namespace Org.BouncyCastle.Math.EC return new LongArray(c, 0, cLen); } - public void Reduce(int m, int[] ks) + internal void Reduce(int m, int[] ks) { ulong[] buf = m_data; int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); @@ -863,9 +828,7 @@ namespace Org.BouncyCastle.Math.EC { int mLen = (m + 63) >> 6; if (len < mLen) - { return len; - } int numBits = System.Math.Min(len << 6, (m << 1) - 1); // TODO use actual degree? int excessBits = (len << 6) - numBits; @@ -994,19 +957,19 @@ namespace Org.BouncyCastle.Math.EC } } - public LongArray ModSquare(int m, int[] ks) + internal LongArray ModSquare(int m, int[] ks) { int len = GetUsedLength(); if (len == 0) return this; ulong[] r = new ulong[len << 1]; - Raw.Interleave.Expand64To128(m_data, 0, len, r, 0); + Interleave.Expand64To128(m_data, 0, len, r, 0); return new LongArray(r, 0, ReduceInPlace(r, 0, r.Length, m, ks)); } - public LongArray ModSquareN(int n, int m, int[] ks) + internal LongArray ModSquareN(int n, int m, int[] ks) { int len = GetUsedLength(); if (len == 0) @@ -1018,21 +981,21 @@ namespace Org.BouncyCastle.Math.EC while (--n >= 0) { - Raw.Interleave.Expand64To128(r, 0, len, r, 0); + Interleave.Expand64To128(r, 0, len, r, 0); len = ReduceInPlace(r, 0, r.Length, m, ks); } return new LongArray(r, 0, len); } - public LongArray Square(int m, int[] ks) + internal LongArray Square(int m, int[] ks) { int len = GetUsedLength(); if (len == 0) return this; ulong[] r = new ulong[len << 1]; - Raw.Interleave.Expand64To128(m_data, 0, len, r, 0); + Interleave.Expand64To128(m_data, 0, len, r, 0); return new LongArray(r, 0, r.Length); } @@ -1147,7 +1110,7 @@ namespace Org.BouncyCastle.Math.EC // return t4.ModMultiply(t1, m, ks); // } - public LongArray ModInverse(int m, int[] ks) + internal LongArray ModInverse(int m, int[] ks) { /* * Fermat's Little Theorem @@ -1188,16 +1151,13 @@ namespace Org.BouncyCastle.Math.EC */ int uzDegree = Degree(); if (uzDegree == 0) - { throw new InvalidOperationException(); - } + if (uzDegree == 1) - { return this; - } // u(z) := a(z) - LongArray uz = (LongArray)Copy(); + LongArray uz = Copy(); int t = (m + 63) >> 6; @@ -1237,9 +1197,7 @@ namespace Org.BouncyCastle.Math.EC int duv2 = uv[b].DegreeFrom(duv1); if (duv2 == 0) - { return gg[1 - b]; - } { int dgg2 = ggDeg[1 - b]; @@ -1263,26 +1221,25 @@ namespace Org.BouncyCastle.Math.EC public override bool Equals(object obj) { - return Equals(obj as LongArray); + if (obj is LongArray longArray) + return Equals(ref longArray); + + return false; } - public bool Equals(LongArray other) + internal bool Equals(ref LongArray other) { - if (this == other) + if (AreAliased(ref this, ref other)) return true; - if (null == other) - return false; + int usedLen = GetUsedLength(); if (other.GetUsedLength() != usedLen) - { return false; - } + for (int i = 0; i < usedLen; i++) { if (m_data[i] != other.m_data[i]) - { return false; - } } return true; } @@ -1311,9 +1268,7 @@ namespace Org.BouncyCastle.Math.EC { int i = GetUsedLength(); if (i == 0) - { return "0"; - } StringBuilder sb = new StringBuilder(i * 64); sb.Append(Convert.ToString((long)m_data[--i], 2)); diff --git a/crypto/src/ocsp/RevokedStatus.cs b/crypto/src/ocsp/RevokedStatus.cs index 903e50ef5..a37bdade9 100644 --- a/crypto/src/ocsp/RevokedStatus.cs +++ b/crypto/src/ocsp/RevokedStatus.cs @@ -6,52 +6,49 @@ using Org.BouncyCastle.Asn1.X509; namespace Org.BouncyCastle.Ocsp { - /** - * wrapper for the RevokedInfo object - */ - public class RevokedStatus + /// <summary>Wrapper for the RevokedInfo object</summary> + public class RevokedStatus : CertificateStatus { - internal readonly RevokedInfo info; + private readonly RevokedInfo m_revokedInfo; - public RevokedStatus( - RevokedInfo info) + public RevokedStatus(RevokedInfo revokedInfo) { - this.info = info; + m_revokedInfo = revokedInfo; } - public RevokedStatus( - DateTime revocationDate, - int reason) + public RevokedStatus(DateTime revocationDate) { - this.info = new RevokedInfo(new Asn1GeneralizedTime(revocationDate), new CrlReason(reason)); + m_revokedInfo = new RevokedInfo(new Asn1GeneralizedTime(revocationDate)); + } + + public RevokedStatus(DateTime revocationDate, int reason) + { + m_revokedInfo = new RevokedInfo(new Asn1GeneralizedTime(revocationDate), new CrlReason(reason)); } public DateTime RevocationTime { - get { return info.RevocationTime.ToDateTime(); } + get { return m_revokedInfo.RevocationTime.ToDateTime(); } } public bool HasRevocationReason { - get { return (info.RevocationReason != null); } + get { return m_revokedInfo.RevocationReason != null; } } - /** - * return the revocation reason. Note: this field is optional, test for it - * with hasRevocationReason() first. - * @exception InvalidOperationException if a reason is asked for and none is avaliable - */ - public int RevocationReason + /// <summary>Return the revocation reason, if there is one.</summary> + /// <remarks>This field is optional; test for it with <see cref="HasRevocationReason"/> first.</remarks> + /// <returns>The revocation reason, if available.</returns> + /// <exception cref="InvalidOperationException">If no revocation reason is available.</exception> + public int RevocationReason { get { - if (info.RevocationReason == null) - { + if (m_revokedInfo.RevocationReason == null) throw new InvalidOperationException("attempt to get a reason where none is available"); - } - return info.RevocationReason.IntValueExact; + return m_revokedInfo.RevocationReason.IntValueExact; } } } diff --git a/crypto/src/openpgp/EdDsaSigner.cs b/crypto/src/openpgp/EdDsaSigner.cs new file mode 100644 index 000000000..0e15ac609 --- /dev/null +++ b/crypto/src/openpgp/EdDsaSigner.cs @@ -0,0 +1,72 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + internal sealed class EdDsaSigner + : ISigner + { + private readonly ISigner m_signer; + private readonly IDigest m_digest; + private readonly byte[] m_digBuf; + + internal EdDsaSigner(ISigner signer, IDigest digest) + { + m_signer = signer; + m_digest = digest; + m_digBuf = new byte[digest.GetDigestSize()]; + } + + public string AlgorithmName => m_signer.AlgorithmName; + + public void Init(bool forSigning, ICipherParameters cipherParameters) + { + m_signer.Init(forSigning, cipherParameters); + m_digest.Reset(); + } + + public void Update(byte b) + { + m_digest.Update(b); + } + + public void BlockUpdate(byte[] input, int inOff, int inLen) + { + m_digest.BlockUpdate(input, inOff, inLen); + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan<byte> input) + { + m_digest.BlockUpdate(input); + } +#endif + + public byte[] GenerateSignature() + { + m_digest.DoFinal(m_digBuf, 0); + + m_signer.BlockUpdate(m_digBuf, 0, m_digBuf.Length); + + return m_signer.GenerateSignature(); + } + + public bool VerifySignature(byte[] signature) + { + m_digest.DoFinal(m_digBuf, 0); + + m_signer.BlockUpdate(m_digBuf, 0, m_digBuf.Length); + + return m_signer.VerifySignature(signature); + } + + public void Reset() + { + Arrays.Clear(m_digBuf); + m_signer.Reset(); + m_digest.Reset(); + } + } +} diff --git a/crypto/src/openpgp/PgpEncryptedData.cs b/crypto/src/openpgp/PgpEncryptedData.cs index 5cdc0d533..bad4cb8cd 100644 --- a/crypto/src/openpgp/PgpEncryptedData.cs +++ b/crypto/src/openpgp/PgpEncryptedData.cs @@ -54,6 +54,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else int avail = bufEnd - bufStart; int pos = offset; @@ -73,8 +76,34 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp bufStart += count; return pos + count - offset; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + int avail = bufEnd - bufStart; + + int pos = 0, count = buffer.Length; + while (count > avail) + { + lookAhead.AsSpan(bufStart, avail).CopyTo(buffer[pos..]); + + bufStart += avail; + pos += avail; + count -= avail; + + if ((avail = FillBuffer()) < 1) + return pos; + } + + lookAhead.AsSpan(bufStart, count).CopyTo(buffer[pos..]); + bufStart += count; + + return pos + count; + } +#endif + public override int ReadByte() { if (bufStart < bufEnd) diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs index 589895522..69e0d5dbc 100644 --- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs +++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs @@ -2,17 +2,21 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; - +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; -using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Bcpg.OpenPgp { - /// <remarks>Generator for encrypted objects.</remarks> + /// <remarks>Generator for encrypted objects.</remarks> public class PgpEncryptedDataGenerator : IStreamGenerator { @@ -99,54 +103,108 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random) { + var cryptoPublicKey = pubKey.GetKey(); + if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH) { IBufferedCipher c; switch (pubKey.Algorithm) { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); - break; - case PublicKeyAlgorithmTag.Dsa: - throw new PgpException("Can't use DSA for encryption."); - case PublicKeyAlgorithmTag.ECDsa: - throw new PgpException("Can't use ECDSA for encryption."); - default: - throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.Dsa: + throw new PgpException("Can't use DSA for encryption."); + case PublicKeyAlgorithmTag.ECDsa: + throw new PgpException("Can't use ECDSA for encryption."); + case PublicKeyAlgorithmTag.EdDsa: + throw new PgpException("Can't use EdDSA for encryption."); + default: + throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); } - AsymmetricKeyParameter akp = pubKey.GetKey(); - c.Init(true, new ParametersWithRandom(akp, random)); + c.Init(true, new ParametersWithRandom(cryptoPublicKey, random)); return c.DoFinal(sessionInfo); } - ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key; + ECDHPublicBcpgKey ecPubKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key; + var curveOid = ecPubKey.CurveOid; + + if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) + { + X25519KeyPairGenerator gen = new X25519KeyPairGenerator(); + gen.Init(new X25519KeyGenerationParameters(random)); + + AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair(); + + X25519Agreement agreement = new X25519Agreement(); + agreement.Init(ephKp.Private); + + byte[] secret = new byte[agreement.AgreementSize]; + agreement.CalculateAgreement(cryptoPublicKey, secret, 0); + + byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KeySize]; + ephPubEncoding[0] = 0x40; + ((X25519PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding, 1); + + return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random); + } + else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + X448KeyPairGenerator gen = new X448KeyPairGenerator(); + gen.Init(new X448KeyGenerationParameters(random)); + + AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair(); + + X448Agreement agreement = new X448Agreement(); + agreement.Init(ephKp.Private); + + byte[] secret = new byte[agreement.AgreementSize]; + agreement.CalculateAgreement(cryptoPublicKey, secret, 0); - // Generate the ephemeral key pair - IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH"); - gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random)); + byte[] ephPubEncoding = new byte[1 + X448PublicKeyParameters.KeySize]; + ephPubEncoding[0] = 0x40; + ((X448PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding, 1); - AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair(); - ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private; - ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public; + return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random); + } + else + { + // Generate the ephemeral key pair + ECDomainParameters ecParams = ((ECPublicKeyParameters)cryptoPublicKey).Parameters; + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.Init(new ECKeyGenerationParameters(ecParams, random)); - ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey(); - ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize(); + AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair(); - KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S)); + ECDHBasicAgreement agreement = new ECDHBasicAgreement(); + agreement.Init(ephKp.Private); + BigInteger S = agreement.CalculateAgreement(cryptoPublicKey); + byte[] secret = BigIntegers.AsUnsignedByteArray(agreement.GetFieldSize(), S); + + byte[] ephPubEncoding = ((ECPublicKeyParameters)ephKp.Public).Q.GetEncoded(false); + return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random); + } + } + + private byte[] EncryptSessionInfo(ECDHPublicBcpgKey ecPubKey, byte[] sessionInfo, byte[] secret, + byte[] ephPubEncoding, SecureRandom random) + { + var key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, secret)); - IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm); + IWrapper w = PgpUtilities.CreateWrapper(ecPubKey.SymmetricKeyAlgorithm); w.Init(true, new ParametersWithRandom(key, random)); byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo, sessionKeyObfuscation); byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length); - byte[] VB = new MPInteger(MPInteger.ToMpiBigInteger(ephPub.Q)).GetEncoded(); + byte[] VB = new MPInteger(new BigInteger(1, ephPubEncoding)).GetEncoded(); byte[] rv = new byte[VB.Length + 1 + C.Length]; @@ -165,7 +223,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaGeneral: - data = new byte[][] { ConvertToEncodedMpi(encryptedSessionInfo) }; + data = new byte[1][] { ConvertToEncodedMpi(encryptedSessionInfo) }; break; case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: @@ -176,13 +234,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp Array.Copy(encryptedSessionInfo, 0, b1, 0, halfLength); Array.Copy(encryptedSessionInfo, halfLength, b2, 0, halfLength); - data = new byte[][] { + data = new byte[2][] { ConvertToEncodedMpi(b1), ConvertToEncodedMpi(b2), }; break; case PublicKeyAlgorithmTag.ECDH: - data = new byte[][]{ encryptedSessionInfo }; + data = new byte[1][]{ encryptedSessionInfo }; break; default: throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); @@ -489,8 +547,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp if (withIntegrityPacket) { - string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); - IDigest digest = DigestUtilities.GetDigest(digestName); + IDigest digest = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); myOut = digestOut = new DigestStream(myOut, null, digest); } diff --git a/crypto/src/openpgp/PgpKdfParameters.cs b/crypto/src/openpgp/PgpKdfParameters.cs new file mode 100644 index 000000000..c78448939 --- /dev/null +++ b/crypto/src/openpgp/PgpKdfParameters.cs @@ -0,0 +1,21 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + internal sealed class PgpKdfParameters + //: IPgpAlgorithmParameters + { + private readonly HashAlgorithmTag m_hashAlgorithm; + private readonly SymmetricKeyAlgorithmTag m_symmetricWrapAlgorithm; + + public PgpKdfParameters(HashAlgorithmTag hashAlgorithm, SymmetricKeyAlgorithmTag symmetricWrapAlgorithm) + { + m_hashAlgorithm = hashAlgorithm; + m_symmetricWrapAlgorithm = symmetricWrapAlgorithm; + } + + public HashAlgorithmTag HashAlgorithm => m_hashAlgorithm; + + public SymmetricKeyAlgorithmTag SymmetricWrapAlgorithm => m_symmetricWrapAlgorithm; + } +} diff --git a/crypto/src/openpgp/PgpLiteralDataGenerator.cs b/crypto/src/openpgp/PgpLiteralDataGenerator.cs index 7672659ca..f9a9e7cad 100644 --- a/crypto/src/openpgp/PgpLiteralDataGenerator.cs +++ b/crypto/src/openpgp/PgpLiteralDataGenerator.cs @@ -141,7 +141,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return new WrappedGeneratorStream(this, pkOut); } -#if !PORTABLE || DOTNET /// <summary> /// <p> /// Open a literal data packet for the passed in <c>FileInfo</c> object, returning @@ -163,7 +162,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { return Open(outStr, format, file.Name, file.Length, file.LastWriteTime); } -#endif /// <summary> /// Close the literal data packet - this is equivalent to calling Close() diff --git a/crypto/src/openpgp/PgpObjectFactory.cs b/crypto/src/openpgp/PgpObjectFactory.cs index f7bf89507..068b85154 100644 --- a/crypto/src/openpgp/PgpObjectFactory.cs +++ b/crypto/src/openpgp/PgpObjectFactory.cs @@ -72,9 +72,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } case PacketTag.PublicKey: return new PgpPublicKeyRing(bcpgIn); - // TODO Make PgpPublicKey a PgpObject or return a PgpPublicKeyRing - //case PacketTag.PublicSubkey: - // return PgpPublicKeyRing.ReadSubkey(bcpgIn); + case PacketTag.PublicSubkey: + return PgpPublicKeyRing.ReadSubkey(bcpgIn); case PacketTag.CompressedData: return new PgpCompressedData(bcpgIn); case PacketTag.LiteralData: diff --git a/crypto/src/openpgp/PgpOnePassSignature.cs b/crypto/src/openpgp/PgpOnePassSignature.cs index 2fab5137e..c14e72bf7 100644 --- a/crypto/src/openpgp/PgpOnePassSignature.cs +++ b/crypto/src/openpgp/PgpOnePassSignature.cs @@ -2,7 +2,9 @@ using System; using System.IO; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Bcpg.OpenPgp { @@ -11,10 +13,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { private static OnePassSignaturePacket Cast(Packet packet) { - if (!(packet is OnePassSignaturePacket)) - throw new IOException("unexpected packet in stream: " + packet); + if (packet is OnePassSignaturePacket onePassSignaturePacket) + return onePassSignaturePacket; - return (OnePassSignaturePacket)packet; + throw new IOException("unexpected packet in stream: " + packet); } private readonly OnePassSignaturePacket sigPack; @@ -36,15 +38,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } /// <summary>Initialise the signature object for verification.</summary> - public void InitVerify( - PgpPublicKey pubKey) + public void InitVerify(PgpPublicKey pubKey) { lastb = 0; + AsymmetricKeyParameter key = pubKey.GetKey(); - try + try { - sig = SignerUtilities.GetSigner( - PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm)); + sig = PgpUtilities.CreateSigner(sigPack.KeyAlgorithm, sigPack.HashAlgorithm, key); } catch (Exception e) { @@ -53,7 +54,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp try { - sig.Init(false, pubKey.GetKey()); + sig.Init(false, key); } catch (InvalidKeyException e) { @@ -61,12 +62,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - public void Update( - byte b) + public void Update(byte b) { if (signatureType == PgpSignature.CanonicalTextDocument) { - doCanonicalUpdateByte(b); + DoCanonicalUpdateByte(b); } else { @@ -74,18 +74,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private void doCanonicalUpdateByte( - byte b) + private void DoCanonicalUpdateByte(byte b) { if (b == '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } else if (b == '\n') { if (lastb != '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } } else @@ -96,51 +95,57 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp lastb = b; } - private void doUpdateCRLF() + private void DoUpdateCRLF() { sig.Update((byte)'\r'); sig.Update((byte)'\n'); } - public void Update( - byte[] bytes) + public void Update(params byte[] bytes) + { + Update(bytes, 0, bytes.Length); + } + + public void Update(byte[] bytes, int off, int length) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Update(bytes.AsSpan(off, length)); +#else if (signatureType == PgpSignature.CanonicalTextDocument) { - for (int i = 0; i != bytes.Length; i++) + int finish = off + length; + + for (int i = off; i != finish; i++) { - doCanonicalUpdateByte(bytes[i]); + DoCanonicalUpdateByte(bytes[i]); } } else { - sig.BlockUpdate(bytes, 0, bytes.Length); + sig.BlockUpdate(bytes, off, length); } +#endif } - public void Update( - byte[] bytes, - int off, - int length) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) { if (signatureType == PgpSignature.CanonicalTextDocument) { - int finish = off + length; - - for (int i = off; i != finish; i++) + for (int i = 0; i < input.Length; ++i) { - doCanonicalUpdateByte(bytes[i]); + DoCanonicalUpdateByte(input[i]); } } else { - sig.BlockUpdate(bytes, off, length); + sig.BlockUpdate(input); } } +#endif - /// <summary>Verify the calculated signature against the passed in PgpSignature.</summary> - public bool Verify( - PgpSignature pgpSig) + /// <summary>Verify the calculated signature against the passed in PgpSignature.</summary> + public bool Verify(PgpSignature pgpSig) { byte[] trailer = pgpSig.GetSignatureTrailer(); @@ -171,15 +176,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public byte[] GetEncoded() { - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); Encode(bOut); return bOut.ToArray(); } - public void Encode( - Stream outStr) + public void Encode(Stream outStr) { BcpgOutputStream.Wrap(outStr).WritePacket(sigPack); } diff --git a/crypto/src/openpgp/PgpPbeEncryptedData.cs b/crypto/src/openpgp/PgpPbeEncryptedData.cs index f43f2f512..7920f54ea 100644 --- a/crypto/src/openpgp/PgpPbeEncryptedData.cs +++ b/crypto/src/openpgp/PgpPbeEncryptedData.cs @@ -97,10 +97,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { truncStream = new TruncatedStream(encStream); - string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); - IDigest digest = DigestUtilities.GetDigest(digestName); + IDigest digest = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); - encStream = new DigestStream(truncStream, digest, null); + encStream = new DigestStream(truncStream, digest, null); } if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length) diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs index cdb8efd36..400cda071 100644 --- a/crypto/src/openpgp/PgpPublicKey.cs +++ b/crypto/src/openpgp/PgpPublicKey.cs @@ -3,13 +3,18 @@ using System.Collections.Generic; using System.IO; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Gnu; +using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Math.EC.Rfc7748; +using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; @@ -18,7 +23,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { /// <remarks>General class to handle a PGP public key object.</remarks> public class PgpPublicKey + : PgpObject { + // We default to these as they are specified as mandatory in RFC 6631. + private static readonly PgpKdfParameters DefaultKdfParameters = new PgpKdfParameters(HashAlgorithmTag.Sha256, + SymmetricKeyAlgorithmTag.Aes128); + public static byte[] CalculateFingerprint(PublicKeyPacket publicPk) { IBcpgKey key = publicPk.Key; @@ -30,7 +40,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp try { - digest = DigestUtilities.GetDigest("MD5"); + digest = PgpUtilities.CreateDigest(HashAlgorithmTag.MD5); + UpdateDigest(digest, rK.Modulus); UpdateDigest(digest, rK.PublicExponent); } @@ -45,7 +56,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { byte[] kBytes = publicPk.GetEncodedContents(); - digest = DigestUtilities.GetDigest("SHA1"); + digest = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); digest.Update(0x99); digest.Update((byte)(kBytes.Length >> 8)); @@ -124,27 +135,38 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength; } - else if (key is ECPublicBcpgKey) + else if (key is EdDsaPublicBcpgKey eddsaK) { - DerObjectIdentifier curveOid = ((ECPublicBcpgKey)key).CurveOid; - if (GnuObjectIdentifiers.Ed25519.Equals(curveOid) - //|| CryptlibObjectIdentifiers.curvey25519.Equals(curveOid) - ) + var curveOid = eddsaK.CurveOid; + if (EdECObjectIdentifiers.id_Ed25519.Equals(curveOid) || + GnuObjectIdentifiers.Ed25519.Equals(curveOid) || + EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) { this.keyStrength = 256; } + else if (EdECObjectIdentifiers.id_Ed448.Equals(curveOid) || + EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + this.keyStrength = 448; + } else { - X9ECParametersHolder ecParameters = ECKeyPairGenerator.FindECCurveByOidLazy(curveOid); - - if (ecParameters != null) - { - this.keyStrength = ecParameters.Curve.FieldSize; - } - else - { - this.keyStrength = -1; // unknown - } + this.keyStrength = -1; // unknown + } + } + else if (key is ECPublicBcpgKey ecK) + { + var curveOid = ecK.CurveOid; + X9ECParametersHolder ecParameters = ECKeyPairGenerator.FindECCurveByOidLazy(curveOid); + + if (ecParameters != null) + { + this.keyStrength = ecParameters.Curve.FieldSize; + } + else + { + this.keyStrength = -1; // unknown } } } @@ -165,7 +187,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public PgpPublicKey(PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, DateTime time) { if (pubKey.IsPrivate) - throw new ArgumentException("Expected a public key", "pubKey"); + throw new ArgumentException("Expected a public key", nameof(pubKey)); IBcpgKey bcpgKey; if (pubKey is RsaKeyParameters rK) @@ -178,6 +200,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y); } + else if (pubKey is ElGamalPublicKeyParameters eK) + { + ElGamalParameters eS = eK.Parameters; + + bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y); + } else if (pubKey is ECPublicKeyParameters ecK) { if (algorithm == PublicKeyAlgorithmTag.ECDH) @@ -194,11 +222,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp throw new PgpException("unknown EC algorithm"); } } - else if (pubKey is ElGamalPublicKeyParameters eK) + else if (pubKey is Ed25519PublicKeyParameters ed25519PubKey) { - ElGamalParameters eS = eK.Parameters; + byte[] pointEnc = new byte[1 + Ed25519PublicKeyParameters.KeySize]; + pointEnc[0] = 0x40; + ed25519PubKey.Encode(pointEnc, 1); + bcpgKey = new EdDsaPublicBcpgKey(GnuObjectIdentifiers.Ed25519, new BigInteger(1, pointEnc)); + } + else if (pubKey is Ed448PublicKeyParameters ed448PubKey) + { + byte[] pointEnc = new byte[Ed448PublicKeyParameters.KeySize]; + ed448PubKey.Encode(pointEnc, 0); + bcpgKey = new EdDsaPublicBcpgKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, pointEnc)); + } + else if (pubKey is X25519PublicKeyParameters x25519PubKey) + { + byte[] pointEnc = new byte[1 + X25519PublicKeyParameters.KeySize]; + pointEnc[0] = 0x40; + x25519PubKey.Encode(pointEnc, 1); - bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y); + PgpKdfParameters kdfParams = DefaultKdfParameters; + + bcpgKey = new ECDHPublicBcpgKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, pointEnc), + kdfParams.HashAlgorithm, kdfParams.SymmetricWrapAlgorithm); + } + else if (pubKey is X448PublicKeyParameters x448PubKey) + { + byte[] pointEnc = new byte[X448PublicKeyParameters.KeySize]; + x448PubKey.Encode(pointEnc, 0); + + PgpKdfParameters kdfParams = DefaultKdfParameters; + + bcpgKey = new ECDHPublicBcpgKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, pointEnc), + kdfParams.HashAlgorithm, kdfParams.SymmetricWrapAlgorithm); } else { @@ -473,24 +529,89 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { switch (publicPk.Algorithm) { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - case PublicKeyAlgorithmTag.RsaSign: - RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key; - return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); - case PublicKeyAlgorithmTag.Dsa: - DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key; - return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); - case PublicKeyAlgorithmTag.ECDsa: - return GetECKey("ECDSA"); - case PublicKeyAlgorithmTag.ECDH: - return GetECKey("ECDH"); - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key; - return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); - default: - throw new PgpException("unknown public key algorithm encountered"); + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key; + return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); + case PublicKeyAlgorithmTag.Dsa: + DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key; + return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); + case PublicKeyAlgorithmTag.ECDsa: + ECDsaPublicBcpgKey ecdsaK = (ECDsaPublicBcpgKey)publicPk.Key; + return GetECKey("ECDSA", ecdsaK); + case PublicKeyAlgorithmTag.ECDH: + { + ECDHPublicBcpgKey ecdhK = (ECDHPublicBcpgKey)publicPk.Key; + var curveOid = ecdhK.CurveOid; + + if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) + { + byte[] pEnc = BigIntegers.AsUnsignedByteArray(1 + X25519.PointSize, ecdhK.EncodedPoint); + if (pEnc[0] != 0x40) + throw new ArgumentException("Invalid X25519 public key"); + + return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo( + new AlgorithmIdentifier(curveOid), + // TODO Span variant + Arrays.CopyOfRange(pEnc, 1, pEnc.Length))); + } + else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + byte[] pEnc = BigIntegers.AsUnsignedByteArray(1 + X448.PointSize, ecdhK.EncodedPoint); + if (pEnc[0] != 0x40) + throw new ArgumentException("Invalid X448 public key"); + + return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo( + new AlgorithmIdentifier(curveOid), + // TODO Span variant + Arrays.CopyOfRange(pEnc, 1, pEnc.Length))); + } + else + { + return GetECKey("ECDH", ecdhK); + } + } + case PublicKeyAlgorithmTag.EdDsa: + { + EdDsaPublicBcpgKey eddsaK = (EdDsaPublicBcpgKey)publicPk.Key; + var curveOid = eddsaK.CurveOid; + + if (EdECObjectIdentifiers.id_Ed25519.Equals(curveOid) || + GnuObjectIdentifiers.Ed25519.Equals(curveOid)) + { + byte[] pEnc = BigIntegers.AsUnsignedByteArray(1 + Ed25519.PublicKeySize, eddsaK.EncodedPoint); + if (pEnc[0] != 0x40) + throw new ArgumentException("Invalid Ed25519 public key"); + + return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo( + new AlgorithmIdentifier(curveOid), + // TODO Span variant + Arrays.CopyOfRange(pEnc, 1, pEnc.Length))); + } + else if (EdECObjectIdentifiers.id_Ed448.Equals(curveOid)) + { + byte[] pEnc = BigIntegers.AsUnsignedByteArray(1 + Ed448.PublicKeySize, eddsaK.EncodedPoint); + if (pEnc[0] != 0x40) + throw new ArgumentException("Invalid Ed448 public key"); + + return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo( + new AlgorithmIdentifier(curveOid), + // TODO Span variant + Arrays.CopyOfRange(pEnc, 1, pEnc.Length))); + } + else + { + throw new InvalidOperationException(); + } + } + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key; + return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); + default: + throw new PgpException("unknown public key algorithm encountered"); } } catch (PgpException e) @@ -503,9 +624,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private ECPublicKeyParameters GetECKey(string algorithm) + private ECPublicKeyParameters GetECKey(string algorithm, ECPublicBcpgKey ecK) { - ECPublicBcpgKey ecK = (ECPublicBcpgKey)publicPk.Key; X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(ecK.CurveOid); BigInteger encodedPoint = ecK.EncodedPoint; @@ -563,7 +683,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public IEnumerable<PgpSignature> GetSignaturesForId(string id) { if (id == null) - throw new ArgumentNullException("id"); + throw new ArgumentNullException(nameof(id)); var result = new List<PgpSignature>(); bool userIdFound = false; @@ -580,13 +700,48 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return userIdFound ? CollectionUtilities.Proxy(result) : null; } + private IEnumerable<PgpSignature> GetSignaturesForID(UserIdPacket id) + { + var signatures = new List<PgpSignature>(); + bool userIdFound = false; + + for (int i = 0; i != ids.Count; i++) + { + if (id.Equals(ids[i])) + { + userIdFound = true; + signatures.AddRange(idSigs[i]); + } + } + + return userIdFound ? signatures : null; + } + + /// <summary>Return any signatures associated with the passed in key identifier keyID.</summary> + /// <param name="keyID">the key id to be matched.</param> + /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects issued by the key with keyID.</returns> + public IEnumerable<PgpSignature> GetSignaturesForKeyID(long keyID) + { + var sigs = new List<PgpSignature>(); + + foreach (var sig in GetSignatures()) + { + if (sig.KeyId == keyID) + { + sigs.Add(sig); + } + } + + return CollectionUtilities.Proxy(sigs); + } + /// <summary>Allows enumeration of signatures associated with the passed in user attributes.</summary> /// <param name="userAttributes">The vector of user attributes to be matched.</param> /// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns> public IEnumerable<PgpSignature> GetSignaturesForUserAttribute(PgpUserAttributeSubpacketVector userAttributes) { if (userAttributes == null) - throw new ArgumentNullException("userAttributes"); + throw new ArgumentNullException(nameof(userAttributes)); var result = new List<PgpSignature>(); bool attributeFound = false; @@ -648,11 +803,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp */ public IEnumerable<PgpSignature> GetKeySignatures() { - var result = subSigs; - if (result == null) - { - result = new List<PgpSignature>(keySigs); - } + var result = subSigs ?? new List<PgpSignature>(keySigs); return CollectionUtilities.Proxy(result); } @@ -947,56 +1098,38 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <param name="key">The key the certifications are to be removed from.</param> /// <param name="certification">The certfication to be removed.</param> /// <returns>The modified key, null if the certification was not found.</returns> - public static PgpPublicKey RemoveCertification( - PgpPublicKey key, - PgpSignature certification) + public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpSignature certification) { - PgpPublicKey returnKey = new PgpPublicKey(key); - var sigs = returnKey.subSigs != null - ? returnKey.subSigs - : returnKey.keySigs; + var returnKey = new PgpPublicKey(key); + var sigs = returnKey.subSigs ?? returnKey.keySigs; -// bool found = sigs.Remove(certification); - int pos = sigs.IndexOf(certification); - bool found = pos >= 0; + if (sigs.Remove(certification)) + return returnKey; - if (found) + // TODO Java uses getRawUserIDs + foreach (string id in key.GetUserIds()) { - sigs.RemoveAt(pos); + if (ContainsSignature(key.GetSignaturesForId(id), certification)) + return RemoveCertification(returnKey, id, certification); } - else - { - foreach (string id in key.GetUserIds()) - { - foreach (object sig in key.GetSignaturesForId(id)) - { - // TODO Is this the right type of equality test? - if (certification == sig) - { - found = true; - returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification); - } - } - } - if (!found) - { - foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes()) - { - foreach (object sig in key.GetSignaturesForUserAttribute(id)) - { - // TODO Is this the right type of equality test? - if (certification == sig) - { - found = true; - returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification); - } - } - } - } + foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes()) + { + if (ContainsSignature(key.GetSignaturesForUserAttribute(id), certification)) + return RemoveCertification(returnKey, id, certification); } return returnKey; } + + private static bool ContainsSignature(IEnumerable<PgpSignature> signatures, PgpSignature signature) + { + foreach (PgpSignature candidate in signatures) + { + if (signature == candidate) + return true; + } + return false; + } } } diff --git a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs index 04fe3ad37..8c6fcda53 100644 --- a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs +++ b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs @@ -1,19 +1,20 @@ using System; using System.IO; -using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Asn1.Cryptlib; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; -using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; -using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Asn1.EdEC; namespace Org.BouncyCastle.Bcpg.OpenPgp { - /// <remarks>A public key encrypted data object.</remarks> + /// <remarks>A public key encrypted data object.</remarks> public class PgpPublicKeyEncryptedData : PgpEncryptedData { @@ -139,10 +140,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { truncStream = new TruncatedStream(encStream); - string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); - IDigest digest = DigestUtilities.GetDigest(digestName); + IDigest digest = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); - encStream = new DigestStream(truncStream, digest, null); + encStream = new DigestStream(truncStream, digest, null); } if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length) @@ -189,76 +189,114 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { byte[][] secKeyData = keyData.GetEncSessionKey(); - if (keyData.Algorithm == PublicKeyAlgorithmTag.ECDH) + if (keyData.Algorithm != PublicKeyAlgorithmTag.ECDH) { - ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key; - X9ECParameters x9Params = ECKeyPairGenerator.FindECCurveByOid(ecKey.CurveOid); + IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm); + + try + { + cipher.Init(false, privKey.Key); + } + catch (InvalidKeyException e) + { + throw new PgpException("error setting asymmetric cipher", e); + } + + if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt + || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral) + { + byte[] bi = secKeyData[0]; + + cipher.ProcessBytes(bi, 2, bi.Length - 2); + } + else + { + ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key; + int size = (k.Parameters.P.BitLength + 7) / 8; + + ProcessEncodedMpi(cipher, size, secKeyData[0]); + ProcessEncodedMpi(cipher, size, secKeyData[1]); + } + + try + { + return cipher.DoFinal(); + } + catch (Exception e) + { + throw new PgpException("exception decrypting secret key", e); + } + } - byte[] enc = secKeyData[0]; + ECDHPublicBcpgKey ecPubKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key; + byte[] enc = secKeyData[0]; - int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8; - if ((2 + pLen + 1) > enc.Length) - throw new PgpException("encoded length out of range"); + int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8; + if ((2 + pLen + 1) > enc.Length) + throw new PgpException("encoded length out of range"); - byte[] pEnc = new byte[pLen]; - Array.Copy(enc, 2, pEnc, 0, pLen); + byte[] pEnc = new byte[pLen]; + Array.Copy(enc, 2, pEnc, 0, pLen); - int keyLen = enc[pLen + 2]; - if ((2 + pLen + 1 + keyLen) > enc.Length) - throw new PgpException("encoded length out of range"); + int keyLen = enc[pLen + 2]; + if ((2 + pLen + 1 + keyLen) > enc.Length) + throw new PgpException("encoded length out of range"); - byte[] keyEnc = new byte[keyLen]; - Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length); + byte[] keyEnc = new byte[keyLen]; + Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length); - ECPoint publicPoint = x9Params.Curve.DecodePoint(pEnc); + var curveOid = ecPubKey.CurveOid; + byte[] secret; - ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters)privKey.Key; - ECPoint S = publicPoint.Multiply(privKeyParams.D).Normalize(); + if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) + { + // skip the 0x40 header byte. + if (pEnc.Length != (1 + X25519PublicKeyParameters.KeySize) || 0x40 != pEnc[0]) + throw new ArgumentException("Invalid X25519 public key"); - KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, S)); + X25519PublicKeyParameters ephPub = new X25519PublicKeyParameters(pEnc, 1); - IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm); - w.Init(false, key); + X25519Agreement agreement = new X25519Agreement(); + agreement.Init(privKey.Key); - return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length)); + secret = new byte[agreement.AgreementSize]; + agreement.CalculateAgreement(ephPub, secret, 0); } + else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + // skip the 0x40 header byte. + if (pEnc.Length != (1 + X448PublicKeyParameters.KeySize) || 0x40 != pEnc[0]) + throw new ArgumentException("Invalid X448 public key"); - IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm); + X448PublicKeyParameters ephPub = new X448PublicKeyParameters(pEnc, 1); - try - { - cipher.Init(false, privKey.Key); - } - catch (InvalidKeyException e) - { - throw new PgpException("error setting asymmetric cipher", e); - } + X448Agreement agreement = new X448Agreement(); + agreement.Init(privKey.Key); - if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt - || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral) - { - byte[] bi = secKeyData[0]; + secret = new byte[agreement.AgreementSize]; + agreement.CalculateAgreement(ephPub, secret, 0); + } + else + { + ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey.Key).Parameters; - cipher.ProcessBytes(bi, 2, bi.Length - 2); - } - else - { - ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key; - int size = (k.Parameters.P.BitLength + 7) / 8; + ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.Curve.DecodePoint(pEnc), + ecParameters); - ProcessEncodedMpi(cipher, size, secKeyData[0]); - ProcessEncodedMpi(cipher, size, secKeyData[1]); - } + ECDHBasicAgreement agreement = new ECDHBasicAgreement(); + agreement.Init(privKey.Key); + BigInteger S = agreement.CalculateAgreement(ephPub); + secret = BigIntegers.AsUnsignedByteArray(agreement.GetFieldSize(), S); + } - try - { - return cipher.DoFinal(); - } - catch (Exception e) - { - throw new PgpException("exception decrypting secret key", e); - } - } + KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, secret)); + + IWrapper w = PgpUtilities.CreateWrapper(ecPubKey.SymmetricKeyAlgorithm); + w.Init(false, key); + + return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length)); + } private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc) { diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs index 4aa15384c..ebbb95634 100644 --- a/crypto/src/openpgp/PgpPublicKeyRing.cs +++ b/crypto/src/openpgp/PgpPublicKeyRing.cs @@ -68,19 +68,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <summary>Return the first public key in the ring.</summary> public virtual PgpPublicKey GetPublicKey() { - return (PgpPublicKey) keys[0]; + return keys[0]; } /// <summary>Return the public key referred to by the passed in key ID if it is present.</summary> - public virtual PgpPublicKey GetPublicKey( - long keyId) + public virtual PgpPublicKey GetPublicKey(long keyId) { foreach (PgpPublicKey k in keys) { if (keyId == k.KeyId) - { return k; - } } return null; @@ -168,23 +165,24 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns> public static PgpPublicKeyRing RemovePublicKey(PgpPublicKeyRing pubRing, PgpPublicKey pubKey) { - var keys = new List<PgpPublicKey>(pubRing.keys); + int count = pubRing.keys.Count; + long keyID = pubKey.KeyId; + + var result = new List<PgpPublicKey>(count); bool found = false; - // TODO Is there supposed to be at most a single match? - int pos = keys.Count; - while (--pos >= 0) + foreach (var key in pubRing.keys) { - PgpPublicKey key = keys[pos]; - - if (key.KeyId == pubKey.KeyId) + if (key.KeyId == keyID) { found = true; - keys.RemoveAt(pos); + continue; } + + result.Add(key); } - return found ? new PgpPublicKeyRing(keys) : null; + return found ? new PgpPublicKeyRing(result) : null; } internal static PublicKeyPacket ReadPublicKeyPacket(BcpgInputStream bcpgInput) diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs index 51a45703a..0103cc187 100644 --- a/crypto/src/openpgp/PgpSecretKey.cs +++ b/crypto/src/openpgp/PgpSecretKey.cs @@ -2,10 +2,17 @@ using System; using System.Collections.Generic; using System.IO; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; +using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Gnu; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -13,6 +20,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { /// <remarks>General class to handle a PGP secret key object.</remarks> public class PgpSecretKey + : PgpObject { private readonly SecretKeyPacket secret; private readonly PgpPublicKey pub; @@ -52,10 +60,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp secKey = new DsaSecretBcpgKey(dsK.X); break; case PublicKeyAlgorithmTag.ECDH: + { + if (privKey.Key is ECPrivateKeyParameters ecdhK) + { + secKey = new ECSecretBcpgKey(ecdhK.D); + } + else + { + // 'reverse' because the native format for X25519 private keys is little-endian + X25519PrivateKeyParameters xK = (X25519PrivateKeyParameters)privKey.Key; + secKey = new ECSecretBcpgKey(new BigInteger(1, Arrays.ReverseInPlace(xK.GetEncoded()))); + } + break; + } case PublicKeyAlgorithmTag.ECDsa: ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key; secKey = new ECSecretBcpgKey(ecK.D); break; + case PublicKeyAlgorithmTag.EdDsa: + { + if (privKey.Key is Ed25519PrivateKeyParameters ed25519K) + { + secKey = new EdSecretBcpgKey(new BigInteger(1, ed25519K.GetEncoded())); + } + else if (privKey.Key is Ed448PrivateKeyParameters ed448K) + { + secKey = new EdSecretBcpgKey(new BigInteger(1, ed448K.GetEncoded())); + } + else + { + throw new PgpException("unknown EdDSA key class"); + } + break; + } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key; @@ -625,6 +662,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return null; PublicKeyPacket pubPk = secret.PublicKeyPacket; + try { byte[] data = ExtractKeyData(rawPassPhrase, clearPassPhrase); @@ -655,11 +693,65 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); break; case PublicKeyAlgorithmTag.ECDH: - privateKey = GetECKey("ECDH", bcpgIn); + { + ECDHPublicBcpgKey ecdhPub = (ECDHPublicBcpgKey)pubPk.Key; + ECSecretBcpgKey ecdhPriv = new ECSecretBcpgKey(bcpgIn); + var curveOid = ecdhPub.CurveOid; + + if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) + { + // 'reverse' because the native format for X25519 private keys is little-endian + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(ecdhPriv.X))))); + } + else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + // 'reverse' because the native format for X448 private keys is little-endian + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(ecdhPriv.X))))); + } + else + { + privateKey = new ECPrivateKeyParameters("ECDH", ecdhPriv.X, ecdhPub.CurveOid); + } break; + } case PublicKeyAlgorithmTag.ECDsa: - privateKey = GetECKey("ECDSA", bcpgIn); + { + ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)pubPk.Key; + ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn); + + privateKey = new ECPrivateKeyParameters("ECDSA", ecdsaPriv.X, ecdsaPub.CurveOid); break; + } + case PublicKeyAlgorithmTag.EdDsa: + { + EdDsaPublicBcpgKey eddsaPub = (EdDsaPublicBcpgKey)pubPk.Key; + EdSecretBcpgKey ecdsaPriv = new EdSecretBcpgKey(bcpgIn); + + var curveOid = eddsaPub.CurveOid; + if (EdECObjectIdentifiers.id_Ed25519.Equals(curveOid) || + GnuObjectIdentifiers.Ed25519.Equals(curveOid)) + { + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed25519.SecretKeySize, ecdsaPriv.X)))); + } + else if (EdECObjectIdentifiers.id_Ed448.Equals(curveOid)) + { + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed448.SecretKeySize, ecdsaPriv.X)))); + } + else + { + throw new InvalidOperationException(); + } + break; + } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; @@ -683,13 +775,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn) - { - ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key; - ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn); - return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid); - } - private static byte[] Checksum( bool useSha1, byte[] bytes, @@ -699,7 +784,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { try { - IDigest dig = DigestUtilities.GetDigest("SHA1"); + IDigest dig = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); dig.BlockUpdate(bytes, 0, length); return DigestUtilities.DoFinal(dig); } diff --git a/crypto/src/openpgp/PgpSecretKeyRing.cs b/crypto/src/openpgp/PgpSecretKeyRing.cs index 637cb45f8..a070aa132 100644 --- a/crypto/src/openpgp/PgpSecretKeyRing.cs +++ b/crypto/src/openpgp/PgpSecretKeyRing.cs @@ -71,11 +71,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp // revocation and direct signatures var keySigs = ReadSignaturesAndTrust(bcpgInput); - IList<object> ids; - IList<TrustPacket> idTrusts; - IList<IList<PgpSignature>> idSigs; - - ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); + ReadUserIDs(bcpgInput, out var ids, out var idTrusts, out var idSigs); keys.Add(new PgpSecretKey(secret, new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs))); @@ -119,6 +115,43 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return keys[0].PublicKey; } + /** + * Return any keys carrying a signature issued by the key represented by keyID. + * + * @param keyID the key id to be matched against. + * @return an iterator (possibly empty) of PGPPublicKey objects carrying signatures from keyID. + */ + public IEnumerable<PgpPublicKey> GetKeysWithSignaturesBy(long keyID) + { + var keysWithSigs = new List<PgpPublicKey>(); + + foreach (var k in GetPublicKeys()) + { + var sigIt = k.GetSignaturesForKeyID(keyID).GetEnumerator(); + + if (sigIt.MoveNext()) + { + keysWithSigs.Add(k); + } + } + + return CollectionUtilities.Proxy(keysWithSigs); + } + + public IEnumerable<PgpPublicKey> GetPublicKeys() + { + var pubKeys = new List<PgpPublicKey>(); + + foreach (var secretKey in keys) + { + pubKeys.Add(secretKey.PublicKey); + } + + pubKeys.AddRange(extraPubKeys); + + return CollectionUtilities.Proxy(pubKeys); + } + /// <summary>Return the master private key.</summary> public PgpSecretKey GetSecretKey() { @@ -156,7 +189,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public byte[] GetEncoded() { - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); Encode(bOut); return bOut.ToArray(); } @@ -165,7 +198,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp Stream outStr) { if (outStr == null) - throw new ArgumentNullException("outStr"); + throw new ArgumentNullException(nameof(outStr)); foreach (PgpSecretKey key in keys) { diff --git a/crypto/src/openpgp/PgpSignature.cs b/crypto/src/openpgp/PgpSignature.cs index da00d43eb..9b596f279 100644 --- a/crypto/src/openpgp/PgpSignature.cs +++ b/crypto/src/openpgp/PgpSignature.cs @@ -3,6 +3,8 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Date; @@ -14,10 +16,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { private static SignaturePacket Cast(Packet packet) { - if (!(packet is SignaturePacket)) - throw new IOException("unexpected packet in stream: " + packet); + if (packet is SignaturePacket signaturePacket) + return signaturePacket; - return (SignaturePacket)packet; + throw new IOException("unexpected packet in stream: " + packet); } public const int BinaryDocument = 0x00; @@ -56,24 +58,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { } - internal PgpSignature( - SignaturePacket sigPacket, - TrustPacket trustPacket) + internal PgpSignature(SignaturePacket sigPacket, TrustPacket trustPacket) { - if (sigPacket == null) - throw new ArgumentNullException("sigPacket"); - - this.sigPck = sigPacket; + this.sigPck = sigPacket ?? throw new ArgumentNullException(nameof(sigPacket)); this.signatureType = sigPck.SignatureType; this.trustPck = trustPacket; } - private void GetSig() - { - this.sig = SignerUtilities.GetSigner( - PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm)); - } - /// <summary>The OpenPGP version number for this signature.</summary> public int Version { @@ -98,17 +89,19 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return IsCertification(SignatureType); } - public void InitVerify( - PgpPublicKey pubKey) + public void InitVerify(PgpPublicKey pubKey) { lastb = 0; + AsymmetricKeyParameter key = pubKey.GetKey(); + if (sig == null) - { - GetSig(); + { + this.sig = PgpUtilities.CreateSigner(sigPck.KeyAlgorithm, sigPck.HashAlgorithm, key); } + try { - sig.Init(false, pubKey.GetKey()); + sig.Init(false, key); } catch (InvalidKeyException e) { @@ -116,12 +109,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - public void Update( - byte b) + public void Update(byte b) { if (signatureType == CanonicalTextDocument) { - doCanonicalUpdateByte(b); + DoCanonicalUpdateByte(b); } else { @@ -129,18 +121,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private void doCanonicalUpdateByte( - byte b) + private void DoCanonicalUpdateByte(byte b) { if (b == '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } else if (b == '\n') { if (lastb != '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } } else @@ -151,39 +142,56 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp lastb = b; } - private void doUpdateCRLF() + private void DoUpdateCRLF() { sig.Update((byte)'\r'); sig.Update((byte)'\n'); } - public void Update( - params byte[] bytes) + public void Update(params byte[] bytes) { Update(bytes, 0, bytes.Length); } - public void Update( - byte[] bytes, - int off, - int length) + public void Update(byte[] bytes, int off, int length) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Update(bytes.AsSpan(off, length)); +#else if (signatureType == CanonicalTextDocument) { int finish = off + length; for (int i = off; i != finish; i++) { - doCanonicalUpdateByte(bytes[i]); + DoCanonicalUpdateByte(bytes[i]); } } else { sig.BlockUpdate(bytes, off, length); } +#endif } - public bool Verify() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + if (signatureType == CanonicalTextDocument) + { + for (int i = 0; i < input.Length; ++i) + { + DoCanonicalUpdateByte(input[i]); + } + } + else + { + sig.BlockUpdate(input); + } + } +#endif + + public bool Verify() { byte[] trailer = GetSignatureTrailer(); sig.BlockUpdate(trailer, 0, trailer.Length); @@ -234,7 +242,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp // try { - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) { packet.Encode(bOut); @@ -248,7 +256,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp this.Update(sigPck.GetSignatureTrailer()); - return sig.VerifySignature(this.GetSignature()); + return sig.VerifySignature(GetSignature()); } /// <summary> @@ -345,15 +353,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public PgpSignatureSubpacketVector GetHashedSubPackets() { - return createSubpacketVector(sigPck.GetHashedSubPackets()); + return CreateSubpacketVector(sigPck.GetHashedSubPackets()); } public PgpSignatureSubpacketVector GetUnhashedSubPackets() { - return createSubpacketVector(sigPck.GetUnhashedSubPackets()); + return CreateSubpacketVector(sigPck.GetUnhashedSubPackets()); } - private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks) + private static PgpSignatureSubpacketVector CreateSubpacketVector(SignatureSubpacket[] pcks) { return pcks == null ? null : new PgpSignatureSubpacketVector(pcks); } @@ -369,10 +377,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { signature = sigValues[0].Value.ToByteArrayUnsigned(); } - else - { - try + else if (KeyAlgorithm == PublicKeyAlgorithmTag.EdDsa) + { + if (sigValues.Length != 2) + throw new InvalidOperationException(); + + BigInteger v0 = sigValues[0].Value; + BigInteger v1 = sigValues[1].Value; + + if (v0.BitLength == 918 && + v1.Equals(BigInteger.Zero) && + v0.ShiftRight(912).Equals(BigInteger.ValueOf(0x40))) + { + signature = new byte[Ed448.SignatureSize]; + BigIntegers.AsUnsignedByteArray(v0.ClearBit(918), signature, 0, signature.Length); + } + else if (v0.BitLength <= 256 && v1.BitLength <= 256) + { + signature = new byte[Ed25519.SignatureSize]; + BigIntegers.AsUnsignedByteArray(sigValues[0].Value, signature, 0, 32); + BigIntegers.AsUnsignedByteArray(sigValues[1].Value, signature, 32, 32); + } + else { + throw new InvalidOperationException(); + } + } + else + { + if (sigValues.Length != 2) + throw new InvalidOperationException(); + + try + { signature = new DerSequence( new DerInteger(sigValues[0].Value), new DerInteger(sigValues[1].Value)).GetEncoded(); @@ -394,17 +431,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp // TODO Handle the encoding stuff by subclassing BcpgObject? public byte[] GetEncoded() { - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); Encode(bOut); return bOut.ToArray(); } - public void Encode( - Stream outStream) + public void Encode(Stream outStream) { - BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream); + var bcpgOut = BcpgOutputStream.Wrap(outStream); bcpgOut.WritePacket(sigPck); @@ -414,8 +450,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private byte[] GetEncodedPublicKey( - PgpPublicKey pubKey) + private static byte[] GetEncodedPublicKey(PgpPublicKey pubKey) { try { @@ -436,13 +471,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { switch (signatureType) { - case DefaultCertification: - case NoCertification: - case CasualCertification: - case PositiveCertification: - return true; - default: - return false; + case DefaultCertification: + case NoCertification: + case CasualCertification: + case PositiveCertification: + return true; + default: + return false; } } } diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs index c5309689f..12edf9f89 100644 --- a/crypto/src/openpgp/PgpSignatureGenerator.cs +++ b/crypto/src/openpgp/PgpSignatureGenerator.cs @@ -5,19 +5,20 @@ using Org.BouncyCastle.Bcpg.Sig; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Bcpg.OpenPgp { /// <remarks>Generator for PGP signatures.</remarks> - // TODO Should be able to implement ISigner? public class PgpSignatureGenerator { private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0]; - private PublicKeyAlgorithmTag keyAlgorithm; - private HashAlgorithmTag hashAlgorithm; + private readonly PublicKeyAlgorithmTag keyAlgorithm; + private readonly HashAlgorithmTag hashAlgorithm; + private PgpPrivateKey privKey; private ISigner sig; private IDigest dig; @@ -35,33 +36,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp this.keyAlgorithm = keyAlgorithm; this.hashAlgorithm = hashAlgorithm; - dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm)); - sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm)); + dig = PgpUtilities.CreateDigest(hashAlgorithm); } /// <summary>Initialise the generator for signing.</summary> public void InitSign( int sigType, - PgpPrivateKey key) + PgpPrivateKey privKey) { - InitSign(sigType, key, null); + InitSign(sigType, privKey, null); } /// <summary>Initialise the generator for signing.</summary> public void InitSign( int sigType, - PgpPrivateKey key, + PgpPrivateKey privKey, SecureRandom random) { - this.privKey = key; + this.privKey = privKey; this.signatureType = sigType; - try + AsymmetricKeyParameter key = privKey.Key; + + if (sig == null) { - ICipherParameters cp = key.Key; + this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key); + } + + try + { + ICipherParameters cp = key; if (random != null) { - cp = new ParametersWithRandom(key.Key, random); + cp = new ParametersWithRandom(cp, random); } sig.Init(true, cp); @@ -75,72 +82,68 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp lastb = 0; } - public void Update( - byte b) + public void Update(byte b) { if (signatureType == PgpSignature.CanonicalTextDocument) { - doCanonicalUpdateByte(b); + DoCanonicalUpdateByte(b); } else { - doUpdateByte(b); + DoUpdateByte(b); } } - private void doCanonicalUpdateByte( - byte b) + private void DoCanonicalUpdateByte(byte b) { if (b == '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } else if (b == '\n') { if (lastb != '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } } else { - doUpdateByte(b); + DoUpdateByte(b); } lastb = b; } - private void doUpdateCRLF() + private void DoUpdateCRLF() { - doUpdateByte((byte)'\r'); - doUpdateByte((byte)'\n'); + DoUpdateByte((byte)'\r'); + DoUpdateByte((byte)'\n'); } - private void doUpdateByte( - byte b) + private void DoUpdateByte(byte b) { sig.Update(b); dig.Update(b); } - public void Update( - params byte[] b) + public void Update(params byte[] b) { Update(b, 0, b.Length); } - public void Update( - byte[] b, - int off, - int len) + public void Update(byte[] b, int off, int len) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Update(b.AsSpan(off, len)); +#else if (signatureType == PgpSignature.CanonicalTextDocument) { int finish = off + len; for (int i = off; i != finish; i++) { - doCanonicalUpdateByte(b[i]); + DoCanonicalUpdateByte(b[i]); } } else @@ -148,9 +151,28 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp sig.BlockUpdate(b, off, len); dig.BlockUpdate(b, off, len); } +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + for (int i = 0; i < input.Length; ++i) + { + DoCanonicalUpdateByte(input[i]); + } + } + else + { + sig.BlockUpdate(input); + dig.BlockUpdate(input); + } } +#endif - public void SetHashedSubpackets( + public void SetHashedSubpackets( PgpSignatureSubpacketVector hashedPackets) { hashed = hashedPackets == null @@ -180,15 +202,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed; - if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime)) + if (!IsPacketPresent(hashed, SignatureSubpacketTag.CreationTime)) { - hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow)); + hPkts = InsertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow)); } - if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId) - && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId)) + if (!IsPacketPresent(hashed, SignatureSubpacketTag.IssuerKeyId) + && !IsPacketPresent(unhashed, SignatureSubpacketTag.IssuerKeyId)) { - unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId)); + unhPkts = InsertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId)); } int version = 4; @@ -239,17 +261,41 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp byte[] sigBytes = sig.GenerateSignature(); byte[] digest = DigestUtilities.DoFinal(dig); - byte[] fingerPrint = new byte[] { digest[0], digest[1] }; + byte[] fingerPrint = new byte[2]{ digest[0], digest[1] }; - // an RSA signature - bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign - || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral; - - MPInteger[] sigValues = isRsa - ? PgpUtilities.RsaSigToMpi(sigBytes) - : PgpUtilities.DsaSigToMpi(sigBytes); + MPInteger[] sigValues; + if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa) + { + int sigLen = sigBytes.Length; + if (sigLen == Ed25519.SignatureSize) + { + sigValues = new MPInteger[2]{ + new MPInteger(new BigInteger(1, sigBytes, 0, 32)), + new MPInteger(new BigInteger(1, sigBytes, 32, 32)) + }; + } + else if (sigLen == Ed448.SignatureSize) + { + sigValues = new MPInteger[2]{ + new MPInteger(new BigInteger(1, Arrays.Prepend(sigBytes, 0x40))), + new MPInteger(BigInteger.Zero) + }; + } + else + { + throw new InvalidOperationException(); + } + } + else if (keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) + { + sigValues = PgpUtilities.RsaSigToMpi(sigBytes); + } + else + { + sigValues = PgpUtilities.DsaSigToMpi(sigBytes); + } - return new PgpSignature( + return new PgpSignature( new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues)); } @@ -258,9 +304,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <param name="id">The ID we are certifying against the public key.</param> /// <param name="pubKey">The key we are certifying against the ID.</param> /// <returns>The certification.</returns> - public PgpSignature GenerateCertification( - string id, - PgpPublicKey pubKey) + public PgpSignature GenerateCertification(string id, PgpPublicKey pubKey) { UpdateWithPublicKey(pubKey); @@ -276,9 +320,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <param name="userAttributes">The ID we are certifying against the public key.</param> /// <param name="pubKey">The key we are certifying against the ID.</param> /// <returns>The certification.</returns> - public PgpSignature GenerateCertification( - PgpUserAttributeSubpacketVector userAttributes, - PgpPublicKey pubKey) + public PgpSignature GenerateCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey pubKey) { UpdateWithPublicKey(pubKey); @@ -287,7 +329,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp // try { - MemoryStream bOut = new MemoryStream(); + var bOut = new MemoryStream(); foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) { packet.Encode(bOut); @@ -299,16 +341,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp throw new PgpException("cannot encode subpacket array", e); } - return this.Generate(); + return Generate(); } /// <summary>Generate a certification for the passed in key against the passed in master key.</summary> /// <param name="masterKey">The key we are certifying against.</param> /// <param name="pubKey">The key we are certifying.</param> /// <returns>The certification.</returns> - public PgpSignature GenerateCertification( - PgpPublicKey masterKey, - PgpPublicKey pubKey) + public PgpSignature GenerateCertification(PgpPublicKey masterKey, PgpPublicKey pubKey) { UpdateWithPublicKey(masterKey); UpdateWithPublicKey(pubKey); @@ -319,16 +359,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp /// <summary>Generate a certification, such as a revocation, for the passed in key.</summary> /// <param name="pubKey">The key we are certifying.</param> /// <returns>The certification.</returns> - public PgpSignature GenerateCertification( - PgpPublicKey pubKey) + public PgpSignature GenerateCertification(PgpPublicKey pubKey) { UpdateWithPublicKey(pubKey); return Generate(); } - private byte[] GetEncodedPublicKey( - PgpPublicKey pubKey) + private static byte[] GetEncodedPublicKey(PgpPublicKey pubKey) { try { @@ -340,42 +378,31 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private bool packetPresent( - SignatureSubpacket[] packets, - SignatureSubpacketTag type) + private static bool IsPacketPresent(SignatureSubpacket[] packets, SignatureSubpacketTag type) { for (int i = 0; i != packets.Length; i++) { if (packets[i].SubpacketType == type) - { return true; - } } return false; } - private SignatureSubpacket[] insertSubpacket( - SignatureSubpacket[] packets, - SignatureSubpacket subpacket) + private static SignatureSubpacket[] InsertSubpacket(SignatureSubpacket[] packets, SignatureSubpacket subpacket) { - SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1]; - tmp[0] = subpacket; - packets.CopyTo(tmp, 1); - return tmp; + return Arrays.Prepend(packets, subpacket); } - private void UpdateWithIdData( - int header, - byte[] idBytes) + private void UpdateWithIdData(int header, byte[] idBytes) { - this.Update( + Update( (byte) header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)(idBytes.Length)); - this.Update(idBytes); + Update(idBytes); } private void UpdateWithPublicKey( @@ -383,11 +410,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { byte[] keyBytes = GetEncodedPublicKey(key); - this.Update( - (byte) 0x99, + Update( + 0x99, (byte)(keyBytes.Length >> 8), (byte)(keyBytes.Length)); - this.Update(keyBytes); + Update(keyBytes); } } } diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs index f33969ea8..2642f3497 100644 --- a/crypto/src/openpgp/PgpUtilities.cs +++ b/crypto/src/openpgp/PgpUtilities.cs @@ -9,7 +9,9 @@ using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pqc.Crypto.SphincsPlus; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; @@ -114,7 +116,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp if (NameToHashID.TryGetValue(name, out var hashAlgorithmTag)) return (int)hashAlgorithmTag; - throw new ArgumentException("unable to map " + name + " to a hash id", "name"); + throw new ArgumentException("unable to map " + name + " to a hash id", nameof(name)); } /** @@ -152,6 +154,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp case PublicKeyAlgorithmTag.ECDsa: encAlg = "ECDSA"; break; + case PublicKeyAlgorithmTag.EdDsa: + encAlg = "EdDSA"; + break; case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases. case PublicKeyAlgorithmTag.ElGamalGeneral: encAlg = "ElGamal"; @@ -163,7 +168,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return GetDigestName(hashAlgorithm) + "with" + encAlg; } - public static string GetSymmetricCipherName( + public static string GetSymmetricCipherName( SymmetricKeyAlgorithmTag algorithm) { switch (algorithm) @@ -301,11 +306,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp IDigest digest; if (s2k != null) { - string digestName = GetDigestName(s2k.HashAlgorithm); - try { - digest = DigestUtilities.GetDigest(digestName); + digest = CreateDigest(s2k.HashAlgorithm); } catch (Exception e) { @@ -368,7 +371,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { try { - digest = DigestUtilities.GetDigest("MD5"); + digest = CreateDigest(HashAlgorithmTag.MD5); for (int i = 0; i != loopCount; i++) { @@ -407,7 +410,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return MakeKey(algorithm, keyBytes); } -#if !PORTABLE || DOTNET /// <summary>Write out the passed in file as a literal data packet.</summary> public static void WriteFileToLiteralData( Stream output, @@ -452,12 +454,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp Platform.Dispose(inputStream); } } -#endif private const int ReadAhead = 60; - private static bool IsPossiblyBase64( - int ch) + private static bool IsPossiblyBase64(int ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/') @@ -473,7 +473,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { // TODO Remove this restriction? if (!inputStream.CanSeek) - throw new ArgumentException("inputStream must be seek-able", "inputStream"); + throw new ArgumentException("inputStream must be seek-able", nameof(inputStream)); long markedPos = inputStream.Position; @@ -552,6 +552,41 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + internal static IDigest CreateDigest(HashAlgorithmTag hashAlgorithm) + { + return DigestUtilities.GetDigest(GetDigestName(hashAlgorithm)); + } + + internal static ISigner CreateSigner(PublicKeyAlgorithmTag publicKeyAlgorithm, HashAlgorithmTag hashAlgorithm, + AsymmetricKeyParameter key) + { + switch (publicKeyAlgorithm) + { + case PublicKeyAlgorithmTag.EdDsa: + { + ISigner signer; + if (key is Ed25519PrivateKeyParameters || key is Ed25519PublicKeyParameters) + { + signer = new Ed25519Signer(); + } + else if (key is Ed448PrivateKeyParameters || key is Ed448PublicKeyParameters) + { + signer = new Ed448Signer(Arrays.EmptyBytes); + } + else + { + throw new InvalidOperationException(); + } + + return new EdDsaSigner(signer, CreateDigest(hashAlgorithm)); + } + default: + { + return SignerUtilities.GetSigner(GetSignatureName(publicKeyAlgorithm, hashAlgorithm)); + } + } + } + internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm) { switch (encAlgorithm) diff --git a/crypto/src/openpgp/PgpV3SignatureGenerator.cs b/crypto/src/openpgp/PgpV3SignatureGenerator.cs index c7113e0ae..324dbd768 100644 --- a/crypto/src/openpgp/PgpV3SignatureGenerator.cs +++ b/crypto/src/openpgp/PgpV3SignatureGenerator.cs @@ -1,3 +1,5 @@ +using System; + using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; @@ -6,11 +8,11 @@ using Org.BouncyCastle.Utilities.Date; namespace Org.BouncyCastle.Bcpg.OpenPgp { /// <remarks>Generator for old style PGP V3 Signatures.</remarks> - // TODO Should be able to implement ISigner? public class PgpV3SignatureGenerator { - private PublicKeyAlgorithmTag keyAlgorithm; - private HashAlgorithmTag hashAlgorithm; + private readonly PublicKeyAlgorithmTag keyAlgorithm; + private readonly HashAlgorithmTag hashAlgorithm; + private PgpPrivateKey privKey; private ISigner sig; private IDigest dig; @@ -22,36 +24,40 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm) { + if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa) + throw new ArgumentException("Invalid algorithm for V3 signature", nameof(keyAlgorithm)); + this.keyAlgorithm = keyAlgorithm; this.hashAlgorithm = hashAlgorithm; - dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm)); - sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm)); + dig = PgpUtilities.CreateDigest(hashAlgorithm); } /// <summary>Initialise the generator for signing.</summary> - public void InitSign( - int sigType, - PgpPrivateKey key) + public void InitSign(int sigType, PgpPrivateKey privKey) { - InitSign(sigType, key, null); + InitSign(sigType, privKey, null); } /// <summary>Initialise the generator for signing.</summary> - public void InitSign( - int sigType, - PgpPrivateKey key, - SecureRandom random) + public void InitSign(int sigType, PgpPrivateKey privKey, SecureRandom random) { - this.privKey = key; + this.privKey = privKey; this.signatureType = sigType; - try + AsymmetricKeyParameter key = privKey.Key; + + if (sig == null) { - ICipherParameters cp = key.Key; + this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key); + } + + try + { + ICipherParameters cp = key; if (random != null) { - cp = new ParametersWithRandom(key.Key, random); + cp = new ParametersWithRandom(cp, random); } sig.Init(true, cp); @@ -65,93 +71,98 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp lastb = 0; } - public void Update( - byte b) + public void Update(byte b) { if (signatureType == PgpSignature.CanonicalTextDocument) { - doCanonicalUpdateByte(b); + DoCanonicalUpdateByte(b); } else { - doUpdateByte(b); + DoUpdateByte(b); } } - private void doCanonicalUpdateByte( - byte b) + private void DoCanonicalUpdateByte(byte b) { if (b == '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } else if (b == '\n') { if (lastb != '\r') { - doUpdateCRLF(); + DoUpdateCRLF(); } } else { - doUpdateByte(b); + DoUpdateByte(b); } lastb = b; } - private void doUpdateCRLF() + private void DoUpdateCRLF() { - doUpdateByte((byte)'\r'); - doUpdateByte((byte)'\n'); + DoUpdateByte((byte)'\r'); + DoUpdateByte((byte)'\n'); } - private void doUpdateByte( + private void DoUpdateByte( byte b) { sig.Update(b); dig.Update(b); } - public void Update( - byte[] b) + public void Update(params byte[] b) + { + Update(b, 0, b.Length); + } + + public void Update(byte[] b, int off, int len) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Update(b.AsSpan(off, len)); +#else if (signatureType == PgpSignature.CanonicalTextDocument) { - for (int i = 0; i != b.Length; i++) + int finish = off + len; + + for (int i = off; i != finish; i++) { - doCanonicalUpdateByte(b[i]); + DoCanonicalUpdateByte(b[i]); } } else { - sig.BlockUpdate(b, 0, b.Length); - dig.BlockUpdate(b, 0, b.Length); + sig.BlockUpdate(b, off, len); + dig.BlockUpdate(b, off, len); } +#endif } - public void Update( - byte[] b, - int off, - int len) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) { if (signatureType == PgpSignature.CanonicalTextDocument) { - int finish = off + len; - - for (int i = off; i != finish; i++) + for (int i = 0; i < input.Length; ++i) { - doCanonicalUpdateByte(b[i]); + DoCanonicalUpdateByte(input[i]); } } else { - sig.BlockUpdate(b, off, len); - dig.BlockUpdate(b, off, len); + sig.BlockUpdate(input); + dig.BlockUpdate(input); } } +#endif - /// <summary>Return the one pass header associated with the current signature.</summary> + /// <summary>Return the one pass header associated with the current signature.</summary> public PgpOnePassSignature GenerateOnePassVersion( bool isNested) { diff --git a/crypto/src/openpgp/Rfc6637Utilities.cs b/crypto/src/openpgp/Rfc6637Utilities.cs index 5d992ec51..e1405f481 100644 --- a/crypto/src/openpgp/Rfc6637Utilities.cs +++ b/crypto/src/openpgp/Rfc6637Utilities.cs @@ -69,11 +69,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s) { + return CreateKey(pubKeyData, s.AffineXCoord.GetEncoded()); + } + + public static byte[] CreateKey(PublicKeyPacket pubKeyData, byte[] secret) + { byte[] userKeyingMaterial = CreateUserKeyingMaterial(pubKeyData); ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key; - return Kdf(ecKey.HashAlgorithm, s, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial); + return Kdf(ecKey.HashAlgorithm, secret, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial); } // RFC 6637 - Section 8 @@ -116,12 +121,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp // ZB = x; // MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param ); // return oBits leftmost bits of MB. - private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters) + private static byte[] Kdf(HashAlgorithmTag digestAlg, byte[] ZB, int keyLen, byte[] parameters) { - byte[] ZB = s.XCoord.GetEncoded(); - - string digestName = PgpUtilities.GetDigestName(digestAlg); - IDigest digest = DigestUtilities.GetDigest(digestName); + IDigest digest = PgpUtilities.CreateDigest(digestAlg); digest.Update(0x00); digest.Update(0x00); diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs index c54ee0b3b..6f96dc9b8 100644 --- a/crypto/src/openpgp/WrappedGeneratorStream.cs +++ b/crypto/src/openpgp/WrappedGeneratorStream.cs @@ -13,10 +13,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp internal WrappedGeneratorStream(IStreamGenerator generator, Stream s) : base(s) { - if (generator == null) - throw new ArgumentNullException(nameof(generator)); - - m_generator = generator; + m_generator = generator ?? throw new ArgumentNullException(nameof(generator)); } protected override void Dispose(bool disposing) diff --git a/crypto/src/pqc/crypto/cmce/CmceEngine.cs b/crypto/src/pqc/crypto/cmce/CmceEngine.cs index 10b08e708..96595ecc0 100644 --- a/crypto/src/pqc/crypto/cmce/CmceEngine.cs +++ b/crypto/src/pqc/crypto/cmce/CmceEngine.cs @@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce { buf[i] = perm[i]; buf[i] <<= 31; - buf[i] |= i; + buf[i] |= (uint)i; buf[i] &= 0x7fffffffffffffffL; // getting rid of signed longs } Sort64(buf, 0, buf.Length); @@ -1162,7 +1162,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce { for (x = 0; x < n; ++x) { - temp[(int)x] = ((GetQShort(temp, (int)(qIndex + x)) ^ 1) << 16) | GetQShort(temp, (int)((qIndex) + (x ^ 1))); + ushort t0 = (ushort)GetQShort(temp, (int)(qIndex + x)); + ushort t1 = (ushort)GetQShort(temp, (int)(qIndex + (x ^ 1))); + temp[(int)x] = ((t0 ^ 1) << 16) | t1; } } Sort32(temp, 0, (int)n); /* A = (id<<16)+pibar */ @@ -1181,7 +1183,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce for (x = 0; x < n; ++x) { - temp[(int)x] = (int)((temp[(int)x] << 16) | x); /* A = (pibar<<16)+id */ + temp[(int)x] = (int)((uint)(temp[(int)x] << 16) | x); /* A = (pibar<<16)+id */ } Sort32(temp, 0, (int)n); /* A = (id<<16)+pibar^-1 */ @@ -1204,7 +1206,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce for (x = 0; x < n; ++x) { - temp[(int)x] = (int)(((temp[(int)(n + x)] & ~0x3ff) << 6) | x); /* A = (p<<16)+id */ + temp[(int)x] = (int)(((uint)(temp[(int)(n + x)] & ~0x3ff) << 6) | x); /* A = (p<<16)+id */ } Sort32(temp, 0, (int)n); /* A = (id<<16)+p^{-1} */ @@ -1241,7 +1243,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce /* B = (p<<16)+c */ for (x = 0; x < n; ++x) { - temp[(int)x] = (int)((temp[(int)(n + x)] & ~0xffff) | x); + temp[(int)x] = (int)((uint)(temp[(int)(n + x)] & ~0xffff) | x); } Sort32(temp, 0, (int)n); /* A = (id<<16)+p^(-1) */ for (x = 0; x < n; ++x) @@ -1375,7 +1377,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce { buf[i] = perm[i]; buf[i] <<= 31; - buf[i] |= i; + buf[i] |= (uint)i; // buf[i] &= 0x7fffffffffffffffL; // getting rid of signed longs } // Sort32 the buffer diff --git a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs index facbc1f33..315ce6ab0 100644 --- a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs +++ b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs @@ -2,21 +2,20 @@ { internal class PolyVecK { - public Poly[] Vec; - private DilithiumEngine Engine; - private int Mode; - private int PolyVecBytes; - private int K; - private int L; + public readonly Poly[] Vec; + private readonly DilithiumEngine Engine; + //private readonly int Mode; + private readonly int K; + //private readonly int L; public PolyVecK(DilithiumEngine Engine) { this.Engine = Engine; - Mode = Engine.Mode; + //Mode = Engine.Mode; K = Engine.K; - L = Engine.L; + //L = Engine.L; Vec = new Poly[K]; - + for (int i = 0; i < K; i++) { Vec[i] = new Poly(Engine); @@ -25,9 +24,8 @@ public void UniformEta(byte[] seed, ushort nonce) { - int i; ushort n = nonce; - for (i = 0; i < K; i++) + for (int i = 0; i < K; i++) { Vec[i].UniformEta(seed, n++); } @@ -99,8 +97,7 @@ public void PackW1(byte[] r) { - int i; - for (i = 0; i < K; i++) + for (int i = 0; i < K; i++) { Vec[i].PackW1(r, i * Engine.PolyW1PackedBytes); } @@ -119,21 +116,18 @@ for (int i = 0; i < K; ++i) { if (Vec[i].CheckNorm(bound)) - { return true; - } } return false; } public int MakeHint(PolyVecK v0, PolyVecK v1) { - int i, s = 0; - for (i = 0; i < K; ++i) + int s = 0; + for (int i = 0; i < K; ++i) { s += Vec[i].PolyMakeHint(v0.Vec[i], v1.Vec[i]); } - return s; } @@ -152,6 +146,5 @@ Vec[i].ShiftLeft(); } } - } } diff --git a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs index 58c286768..0a87c2070 100644 --- a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs +++ b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs @@ -2,17 +2,16 @@ { internal class PolyVecL { - public Poly[] Vec; - private DilithiumEngine Engine; - private int Mode; - private int PolyVecBytes; - private int L; - private int K; + public readonly Poly[] Vec; + //private DilithiumEngine Engine; + //private int Mode; + private readonly int L; + private readonly int K; public PolyVecL(DilithiumEngine Engine) { - this.Engine = Engine; - Mode = Engine.Mode; + //this.Engine = Engine; + //Mode = Engine.Mode; L = Engine.L; K = Engine.K; Vec = new Poly[L]; @@ -24,8 +23,7 @@ public void UniformEta(byte[] seed, ushort nonce) { - int i; - for (i = 0; i < L; i++) + for (int i = 0; i < L; i++) { Vec[i].UniformEta(seed, nonce++); } diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs index bf9d5ee3c..e30115a95 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs @@ -138,7 +138,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber internal void KemDecrypt(byte[] sharedSecret, byte[] cipherText, byte[] secretKey) { - int i; byte[] buf = new byte[2 * SymBytes], kr = new byte[2 * SymBytes], cmp = new byte[CipherTextBytes]; byte[] pk = Arrays.CopyOfRange(secretKey, IndCpaSecretKeyBytes, secretKey.Length); m_indCpa.Decrypt(buf, cipherText, secretKey); @@ -161,7 +160,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber private void CMov(byte[] r, byte[] x, int len, bool b) { - int i; if (b) { Array.Copy(x, 0, r, 0, len); diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs index b3be4770d..9400b776e 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs @@ -138,7 +138,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber private void PackPublicKey(out byte[] pk, PolyVec pkpv, byte[] seed) { - int i; pk = new byte[m_engine.IndCpaPublicKeyBytes]; pkpv.ToBytes(pk); Array.Copy(seed, 0, pk, m_engine.PolyVecBytes, KyberEngine.SymBytes); @@ -146,7 +145,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber private void UnpackPublicKey(PolyVec pkpv, byte[] seed, byte[] pk) { - int i; pkpv.FromBytes(pk); Array.Copy(pk, m_engine.PolyVecBytes, seed, 0, KyberEngine.SymBytes); } diff --git a/crypto/src/pqc/crypto/falcon/FalconKeyPairGenerator.cs b/crypto/src/pqc/crypto/falcon/FalconKeyPairGenerator.cs index eafd1a9eb..68f90c97f 100644 --- a/crypto/src/pqc/crypto/falcon/FalconKeyPairGenerator.cs +++ b/crypto/src/pqc/crypto/falcon/FalconKeyPairGenerator.cs @@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon { private FalconKeyGenerationParameters parameters; private SecureRandom random; - private FalconNIST nist; + private FalconNist nist; private uint logn; private uint noncelen; @@ -18,32 +18,31 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon { this.parameters = (FalconKeyGenerationParameters)param; this.random = param.Random; - this.logn = ((FalconKeyGenerationParameters)param).Parameters.LogN; - this.noncelen = ((FalconKeyGenerationParameters)param).Parameters.NonceLength; - this.nist = new FalconNIST(random, logn, noncelen); + this.logn = (uint)((FalconKeyGenerationParameters)param).Parameters.LogN; + this.noncelen = (uint)((FalconKeyGenerationParameters)param).Parameters.NonceLength; + this.nist = new FalconNist(random, logn, noncelen); int n = 1 << (int)this.logn; - int sk_coeff_size = 8; - if (n == 1024) - { - sk_coeff_size = 5; - } - else if (n == 256 || n == 512) - { - sk_coeff_size = 6; - } - else if (n == 64 || n == 128) - { - sk_coeff_size = 7; - } + //int sk_coeff_size = 8; + //if (n == 1024) + //{ + // sk_coeff_size = 5; + //} + //else if (n == 256 || n == 512) + //{ + // sk_coeff_size = 6; + //} + //else if (n == 64 || n == 128) + //{ + // sk_coeff_size = 7; + //} this.pk_size = 1 + (14 * n / 8); } public AsymmetricCipherKeyPair GenerateKeyPair() { - byte[] pk, sk, f, g, F; - nist.crypto_sign_keypair(out pk, out f, out g, out F); - FalconParameters p = ((FalconKeyGenerationParameters)this.parameters).Parameters; + nist.crypto_sign_keypair(out byte[] pk, out byte[] f, out byte[] g, out byte[] F); + FalconParameters p = this.parameters.Parameters; FalconPrivateKeyParameters privk = new FalconPrivateKeyParameters(p, f, g, F, pk); FalconPublicKeyParameters pubk = new FalconPublicKeyParameters(p, pk); return new AsymmetricCipherKeyPair(pubk, privk); diff --git a/crypto/src/pqc/crypto/falcon/FalconKeyParameters.cs b/crypto/src/pqc/crypto/falcon/FalconKeyParameters.cs index 95a546994..bb1252706 100644 --- a/crypto/src/pqc/crypto/falcon/FalconKeyParameters.cs +++ b/crypto/src/pqc/crypto/falcon/FalconKeyParameters.cs @@ -3,7 +3,7 @@ using Org.BouncyCastle.Crypto; namespace Org.BouncyCastle.Pqc.Crypto.Falcon { - public class FalconKeyParameters + public abstract class FalconKeyParameters : AsymmetricKeyParameter { private FalconParameters parameters; diff --git a/crypto/src/pqc/crypto/falcon/FalconNIST.cs b/crypto/src/pqc/crypto/falcon/FalconNIST.cs index cce790734..0d2ba46e0 100644 --- a/crypto/src/pqc/crypto/falcon/FalconNIST.cs +++ b/crypto/src/pqc/crypto/falcon/FalconNIST.cs @@ -1,10 +1,11 @@ using System; + using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Falcon { - class FalconNIST + internal class FalconNist { private FalconCodec codec; private FalconVrfy vrfy; @@ -26,7 +27,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon return this.CRYPTO_BYTES; } - internal FalconNIST(SecureRandom random, uint logn, uint noncelen) { + internal FalconNist(SecureRandom random, uint logn, uint noncelen) { this.logn = logn; this.codec = new FalconCodec(); this.common = new FalconCommon(); diff --git a/crypto/src/pqc/crypto/falcon/FalconParameters.cs b/crypto/src/pqc/crypto/falcon/FalconParameters.cs index 4a9bc598f..10d22a241 100644 --- a/crypto/src/pqc/crypto/falcon/FalconParameters.cs +++ b/crypto/src/pqc/crypto/falcon/FalconParameters.cs @@ -1,16 +1,17 @@ using Org.BouncyCastle.Crypto; +using System; namespace Org.BouncyCastle.Pqc.Crypto.Falcon { public sealed class FalconParameters : ICipherParameters { - public static FalconParameters falcon_512 = new FalconParameters("falcon512", 9, 40); - public static FalconParameters falcon_1024 = new FalconParameters("falcon1024", 10, 40); + public static readonly FalconParameters falcon_512 = new FalconParameters("falcon512", 9, 40); + public static readonly FalconParameters falcon_1024 = new FalconParameters("falcon1024", 10, 40); - private string name; - private uint logn; - private uint nonce_length; + private readonly string name; + private readonly uint logn; + private readonly uint nonce_length; private FalconParameters(string name, uint logn, uint nonce_length) { @@ -19,9 +20,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon this.nonce_length = nonce_length; } - public uint LogN => logn; + public int LogN => Convert.ToInt32(logn); - public uint NonceLength => nonce_length; + public int NonceLength => Convert.ToInt32(nonce_length); public string Name => name; } diff --git a/crypto/src/pqc/crypto/falcon/FalconPrivateKeyParameters.cs b/crypto/src/pqc/crypto/falcon/FalconPrivateKeyParameters.cs index c912a222c..12b055add 100644 --- a/crypto/src/pqc/crypto/falcon/FalconPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/falcon/FalconPrivateKeyParameters.cs @@ -3,13 +3,13 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Falcon { - public class FalconPrivateKeyParameters + public sealed class FalconPrivateKeyParameters : FalconKeyParameters { - private byte[] pk; - private byte[] f; - private byte[] g; - private byte[] F; + private readonly byte[] pk; + private readonly byte[] f; + private readonly byte[] g; + private readonly byte[] F; public FalconPrivateKeyParameters(FalconParameters parameters, byte[] f, byte[] g, byte[] F, byte[] pk_encoded) : base(true, parameters) @@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon return Arrays.Clone(pk); } - public byte[] GetSpolyf() + public byte[] GetSpolyLittleF() { return Arrays.Clone(f); } @@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon return Arrays.Clone(g); } - public byte[] GetSpolyF() + public byte[] GetSpolyBigF() { return Arrays.Clone(F); } diff --git a/crypto/src/pqc/crypto/falcon/FalconPublicKeyParameters.cs b/crypto/src/pqc/crypto/falcon/FalconPublicKeyParameters.cs index 72bb11948..fa6b627ab 100644 --- a/crypto/src/pqc/crypto/falcon/FalconPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/falcon/FalconPublicKeyParameters.cs @@ -2,10 +2,10 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Falcon { - public class FalconPublicKeyParameters + public sealed class FalconPublicKeyParameters : FalconKeyParameters { - private byte[] publicKey; + private readonly byte[] publicKey; public FalconPublicKeyParameters(FalconParameters parameters, byte[] h) : base(false, parameters) diff --git a/crypto/src/pqc/crypto/falcon/FalconSigner.cs b/crypto/src/pqc/crypto/falcon/FalconSigner.cs index f581386ee..e77e84102 100644 --- a/crypto/src/pqc/crypto/falcon/FalconSigner.cs +++ b/crypto/src/pqc/crypto/falcon/FalconSigner.cs @@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon : IMessageSigner { private byte[] encodedkey; - private FalconNIST nist; + private FalconNist nist; public void Init(bool forSigning, ICipherParameters param) { @@ -19,29 +19,29 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon { FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)withRandom.Parameters; encodedkey = skparam.GetEncoded(); - nist = new FalconNIST( + nist = new FalconNist( withRandom.Random, - skparam.Parameters.LogN, - skparam.Parameters.NonceLength); + (uint)skparam.Parameters.LogN, + (uint)skparam.Parameters.NonceLength); } else { FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)param; encodedkey = ((FalconPrivateKeyParameters)param).GetEncoded(); - nist = new FalconNIST( + nist = new FalconNist( CryptoServicesRegistrar.GetSecureRandom(), - skparam.Parameters.LogN, - skparam.Parameters.NonceLength); + (uint)skparam.Parameters.LogN, + (uint)skparam.Parameters.NonceLength); } } else { FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)param; encodedkey = pkparam.GetEncoded(); - nist = new FalconNIST( + nist = new FalconNist( CryptoServicesRegistrar.GetSecureRandom(), - pkparam.Parameters.LogN, - pkparam.Parameters.NonceLength); + (uint)pkparam.Parameters.LogN, + (uint)pkparam.Parameters.NonceLength); } } diff --git a/crypto/src/pqc/crypto/hqc/ReedSolomon.cs b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs index 8e7fc664d..25a8c7997 100644 --- a/crypto/src/pqc/crypto/hqc/ReedSolomon.cs +++ b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs @@ -28,7 +28,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc for (int j = 0; j < paramG; j++) { tmp[j] = GFCalculator.mult(gateValue, rsPoly[j]); - int n = 1; } for (int j = n1 - paramK - 1; j > 0; j--) diff --git a/crypto/src/pqc/crypto/lms/Composer.cs b/crypto/src/pqc/crypto/lms/Composer.cs index b897f4b68..6ad044e34 100644 --- a/crypto/src/pqc/crypto/lms/Composer.cs +++ b/crypto/src/pqc/crypto/lms/Composer.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using Org.BouncyCastle.Utilities; @@ -38,7 +37,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return this; } - public Composer U16Str(uint n) + public Composer U16Str(int n) { n &= 0xFFFF; bos.WriteByte((byte)(n >> 8)); @@ -72,7 +71,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return this; } - public Composer Bytes(byte[][] arrays) + public Composer Bytes2(byte[][] arrays) { foreach (byte[] array in arrays) { @@ -81,7 +80,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return this; } - public Composer Bytes(byte[][] arrays, int start, int end) + public Composer Bytes2(byte[][] arrays, int start, int end) { int j = start; while (j != end) diff --git a/crypto/src/pqc/crypto/lms/HSS.cs b/crypto/src/pqc/crypto/lms/HSS.cs index 9c21198e4..4634088c7 100644 --- a/crypto/src/pqc/crypto/lms/HSS.cs +++ b/crypto/src/pqc/crypto/lms/HSS.cs @@ -39,17 +39,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms 0, I, 1 << lms.LMSigParameters.H, - rootSeed); + rootSeed, + isPlaceholder: false); } else { - keys[t] = new PlaceholderLMSPrivateKey( + keys[t] = new LmsPrivateKeyParameters( lms.LMSigParameters, lms.LMOtsParameters, -1, zero, 1 << lms.LMSigParameters.H, - zero); + zero, + isPlaceholder: true); } hssKeyMaxIndex <<= lms.LMSigParameters.H; } @@ -161,7 +163,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms public static bool VerifySignature(HssPublicKeyParameters publicKey, HssSignature signature, byte[] message) { - int Nspk = signature.GetlMinus1(); + int Nspk = signature.GetLMinus1(); if (Nspk + 1 != publicKey.L) return false; @@ -196,25 +198,5 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } return Lms.VerifySignature(key, sigList[Nspk], message); } - - private class PlaceholderLMSPrivateKey - : LmsPrivateKeyParameters - { - internal PlaceholderLMSPrivateKey(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, - byte[] I, int maxQ, byte[] masterSecret) - : base(lmsParameter, otsParameters, q, I, maxQ, masterSecret) - { - } - - internal override LMOtsPrivateKey GetNextOtsPrivateKey() - { - throw new Exception("placeholder only"); - } - - public override LmsPublicKeyParameters GetPublicKey() - { - throw new Exception("placeholder only"); - } - } } } diff --git a/crypto/src/pqc/crypto/lms/HSSSignature.cs b/crypto/src/pqc/crypto/lms/HSSSignature.cs index 7c4599835..21f0397c8 100644 --- a/crypto/src/pqc/crypto/lms/HSSSignature.cs +++ b/crypto/src/pqc/crypto/lms/HSSSignature.cs @@ -9,15 +9,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms public sealed class HssSignature : IEncodable { - private int lMinus1; - private LmsSignedPubKey[] signedPubKey; - private LmsSignature signature; + private readonly int m_lMinus1; + private readonly LmsSignedPubKey[] m_signedPubKey; + private readonly LmsSignature m_signature; public HssSignature(int lMinus1, LmsSignedPubKey[] signedPubKey, LmsSignature signature) { - this.lMinus1 = lMinus1; - this.signedPubKey = signedPubKey; - this.signature = signature; + m_lMinus1 = lMinus1; + m_signedPubKey = signedPubKey; + m_signature = signature; } /** @@ -73,81 +73,63 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms throw new ArgumentException($"cannot parse {src}"); } - // FIXME - public int GetlMinus1() + public int GetLMinus1() { - return lMinus1; + return m_lMinus1; } + // FIXME public LmsSignedPubKey[] GetSignedPubKeys() { - return signedPubKey; + return m_signedPubKey; } - public LmsSignature Signature => signature; + public LmsSignature Signature => m_signature; - public override bool Equals(Object o) + public override bool Equals(object other) { - if (this == o) - { + if (this == other) return true; - } - - if (o == null || GetType() != o.GetType()) - { + if (!(other is HssSignature that)) return false; - } - HssSignature signature1 = (HssSignature) o; - - if (lMinus1 != signature1.lMinus1) - { + if (this.m_lMinus1 != that.m_lMinus1) return false; - } - - // FIXME - // Probably incorrect - comparing Object[] arrays with Arrays.equals - if (signedPubKey.Length != signature1.signedPubKey.Length) - { + if (this.m_signedPubKey.Length != that.m_signedPubKey.Length) return false; - } - for (int t = 0; t < signedPubKey.Length; t++) + for (int t = 0; t < m_signedPubKey.Length; t++) { - if (!signedPubKey[t].Equals(signature1.signedPubKey[t])) - { + if (!this.m_signedPubKey[t].Equals(that.m_signedPubKey[t])) return false; - } } - return signature != null ? signature.Equals(signature1.signature) : signature1.signature == null; + return Equals(this.m_signature, that.m_signature); } public override int GetHashCode() { - int result = lMinus1; - result = 31 * result + signedPubKey.GetHashCode(); - result = 31 * result + (signature != null ? signature.GetHashCode() : 0); + int result = m_lMinus1; + result = 31 * result + m_signedPubKey.GetHashCode(); + result = 31 * result + (m_signature != null ? m_signature.GetHashCode() : 0); return result; } public byte[] GetEncoded() { Composer composer = Composer.Compose(); - composer.U32Str(lMinus1); - if (signedPubKey != null) + composer.U32Str(m_lMinus1); + if (m_signedPubKey != null) { - foreach (LmsSignedPubKey sigPub in signedPubKey) + foreach (LmsSignedPubKey sigPub in m_signedPubKey) { composer.Bytes(sigPub); } } - composer.Bytes(signature); + composer.Bytes(m_signature); return composer.Build(); - } - } } diff --git a/crypto/src/pqc/crypto/lms/LMOtsParameters.cs b/crypto/src/pqc/crypto/lms/LMOtsParameters.cs index e05b1650a..60bf28d50 100644 --- a/crypto/src/pqc/crypto/lms/LMOtsParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMOtsParameters.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Org.BouncyCastle.Asn1; @@ -53,7 +54,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms public int Ls => m_ls; - public uint SigLen => m_sigLen; + public int SigLen => Convert.ToInt32(m_sigLen); public DerObjectIdentifier DigestOid => m_digestOid; diff --git a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs index e9df6fbfd..20b717af6 100644 --- a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs +++ b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs @@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms LmsUtilities.ByteArray(m_I, ctx); LmsUtilities.U32Str(m_q, ctx); - LmsUtilities.U16Str(LMOts.D_MESG, ctx); + LmsUtilities.U16Str((short)LMOts.D_MESG, ctx); LmsUtilities.ByteArray(C, ctx); return new LmsContext(this, sigParams, ctx, C, path); diff --git a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs index 09e8b2951..ef3d4aced 100644 --- a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs +++ b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs @@ -109,7 +109,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms LmsUtilities.ByteArray(m_I, ctx); LmsUtilities.U32Str(m_q, ctx); - LmsUtilities.U16Str(LMOts.D_MESG, ctx); + LmsUtilities.U16Str((short)LMOts.D_MESG, ctx); LmsUtilities.ByteArray(signature.C, ctx); return new LmsContext(this, signature, ctx); @@ -121,7 +121,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms LmsUtilities.ByteArray(m_I, ctx); LmsUtilities.U32Str(m_q, ctx); - LmsUtilities.U16Str(LMOts.D_MESG, ctx); + LmsUtilities.U16Str((short)LMOts.D_MESG, ctx); LmsUtilities.ByteArray(signature.OtsSignature.C, ctx); return new LmsContext(this, signature, ctx); diff --git a/crypto/src/pqc/crypto/lms/LMS.cs b/crypto/src/pqc/crypto/lms/LMS.cs index 3c17b0a1e..6174d3889 100644 --- a/crypto/src/pqc/crypto/lms/LMS.cs +++ b/crypto/src/pqc/crypto/lms/LMS.cs @@ -100,7 +100,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms H.BlockUpdate(I, 0, I.Length); LmsUtilities.U32Str(node_num, H); - LmsUtilities.U16Str(D_LEAF, H); + LmsUtilities.U16Str((short)D_LEAF, H); H.BlockUpdate(Kc, 0, Kc.Length); H.DoFinal(tmp, 0); @@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms // is odd H.BlockUpdate(I, 0, I.Length); LmsUtilities.U32Str(node_num / 2, H); - LmsUtilities.U16Str(D_INTR, H); + LmsUtilities.U16Str((short)D_INTR, H); H.BlockUpdate(path[i], 0, path[i].Length); H.BlockUpdate(tmp, 0, tmp.Length); H.DoFinal(tmp, 0); @@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms { H.BlockUpdate(I, 0, I.Length); LmsUtilities.U32Str(node_num / 2, H); - LmsUtilities.U16Str(D_INTR, H); + LmsUtilities.U16Str((short)D_INTR, H); H.BlockUpdate(tmp, 0, tmp.Length); H.BlockUpdate(path[i], 0, path[i].Length); H.DoFinal(tmp, 0); diff --git a/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs index b35ba36c4..aaddfb823 100644 --- a/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs @@ -6,7 +6,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms public abstract class LmsKeyParameters : AsymmetricKeyParameter, IEncodable { - protected LmsKeyParameters(bool isPrivateKey) + internal LmsKeyParameters(bool isPrivateKey) : base(isPrivateKey) { } diff --git a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs index 25ca81938..278cbb04b 100644 --- a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs @@ -9,7 +9,7 @@ using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Pqc.Crypto.Lms { - public class LmsPrivateKeyParameters + public sealed class LmsPrivateKeyParameters : LmsKeyParameters, ILmsContextBasedSigner { private static CacheKey T1 = new CacheKey(1); @@ -34,6 +34,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms private IDigest tDigest; private int q; + private readonly bool m_isPlaceholder; // // These are not final because they can be generated. @@ -41,9 +42,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms // private LmsPublicKeyParameters publicKey; - public LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, int maxQ, byte[] masterSecret) + : this(lmsParameter, otsParameters, q, I, maxQ, masterSecret, false) + { + } + + internal LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, + int maxQ, byte[] masterSecret, bool isPlaceholder) : base(true) { this.parameters = lmsParameter; @@ -55,6 +61,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms this.maxCacheR = 1 << (parameters.H + 1); this.tCache = new Dictionary<CacheKey, byte[]>(); this.tDigest = DigestUtilities.GetDigest(lmsParameter.DigestOid); + this.m_isPlaceholder = isPlaceholder; } private LmsPrivateKeyParameters(LmsPrivateKeyParameters parent, int q, int maxQ) @@ -203,8 +210,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } } - internal virtual LMOtsPrivateKey GetNextOtsPrivateKey() + internal LMOtsPrivateKey GetNextOtsPrivateKey() { + if (m_isPlaceholder) + throw new Exception("placeholder only"); + lock (this) { if (q >= maxQ) @@ -264,8 +274,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return maxQ - q; } - public virtual LmsPublicKeyParameters GetPublicKey() + public LmsPublicKeyParameters GetPublicKey() { + if (m_isPlaceholder) + throw new Exception("placeholder only"); + lock (this) { if (publicKey == null) @@ -276,7 +289,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } } - byte[] FindT(int r) + internal byte[] FindT(int r) { if (r < maxCacheR) { @@ -290,14 +303,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms { lock (tCache) { - byte[] t; - if (!tCache.TryGetValue(key, out t)) - { - t = CalcT(key.index); - tCache[key] = t; - } + if (tCache.TryGetValue(key, out byte[] t)) + return t; - return t; + return tCache[key] = CalcT(key.index); } } @@ -315,7 +324,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms { LmsUtilities.ByteArray(this.GetI(), tDigest); LmsUtilities.U32Str(r, tDigest); - LmsUtilities.U16Str(Lms.D_LEAF, tDigest); + LmsUtilities.U16Str((short)Lms.D_LEAF, tDigest); // // These can be pre generated at the time of key generation and held within the private key. // However it will cost memory to have them stick around. @@ -334,7 +343,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms LmsUtilities.ByteArray(this.GetI(), tDigest); LmsUtilities.U32Str(r, tDigest); - LmsUtilities.U16Str(Lms.D_INTR, tDigest); + LmsUtilities.U16Str((short)Lms.D_INTR, tDigest); LmsUtilities.ByteArray(t2r, tDigest); LmsUtilities.ByteArray(t2rPlus1, tDigest); T = new byte[tDigest.GetDigestSize()]; diff --git a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs index fa12b47c3..f8d0970af 100644 --- a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Pqc.Crypto.Lms { - public class LmsPublicKeyParameters + public sealed class LmsPublicKeyParameters : LmsKeyParameters, ILmsContextBasedVerifier { private LMSigParameters parameterSet; diff --git a/crypto/src/pqc/crypto/lms/LMSSignature.cs b/crypto/src/pqc/crypto/lms/LMSSignature.cs index f5d355297..a1ae475c1 100644 --- a/crypto/src/pqc/crypto/lms/LMSSignature.cs +++ b/crypto/src/pqc/crypto/lms/LMSSignature.cs @@ -123,7 +123,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms .U32Str(q) .Bytes(otsSignature.GetEncoded()) .U32Str(parameter.ID) - .Bytes(y) + .Bytes2(y) .Build(); } diff --git a/crypto/src/pqc/crypto/lms/LM_OTS.cs b/crypto/src/pqc/crypto/lms/LM_OTS.cs index c3cd3da90..0aa5c580e 100644 --- a/crypto/src/pqc/crypto/lms/LM_OTS.cs +++ b/crypto/src/pqc/crypto/lms/LM_OTS.cs @@ -220,7 +220,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms IDigest finalContext = DigestUtilities.GetDigest(parameter.DigestOid); LmsUtilities.ByteArray(I, finalContext); LmsUtilities.U32Str(q, finalContext); - LmsUtilities.U16Str(D_PBLC, finalContext); + LmsUtilities.U16Str((short)D_PBLC, finalContext); byte[] tmp = Composer.Compose() .Bytes(I) diff --git a/crypto/src/pqc/crypto/lms/LmsUtils.cs b/crypto/src/pqc/crypto/lms/LmsUtils.cs index da3f457d2..e99dfe585 100644 --- a/crypto/src/pqc/crypto/lms/LmsUtils.cs +++ b/crypto/src/pqc/crypto/lms/LmsUtils.cs @@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms d.Update((byte)(n)); } - public static void U16Str(ushort n, IDigest d) + public static void U16Str(short n, IDigest d) { d.Update((byte)(n >> 8)); d.Update((byte)(n)); diff --git a/crypto/src/pqc/crypto/picnic/KMatrices.cs b/crypto/src/pqc/crypto/picnic/KMatrices.cs index 64e6be00a..a6d280985 100644 --- a/crypto/src/pqc/crypto/picnic/KMatrices.cs +++ b/crypto/src/pqc/crypto/picnic/KMatrices.cs @@ -1,5 +1,3 @@ -using Org.BouncyCastle.Utilities; - namespace Org.BouncyCastle.Pqc.Crypto.Picnic { internal class KMatrices @@ -9,36 +7,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic private int columns; private uint[] data; - public KMatrices(int nmatrices, int rows, int columns, uint[] data) + internal KMatrices(int nmatrices, int rows, int columns, uint[] data) { this.nmatrices = nmatrices; this.rows = rows; this.columns = columns; this.data = data; } - - public int GetNmatrices() + internal int GetNmatrices() { return nmatrices; } - public int GetSize() + internal int GetSize() { return rows * columns; } - public int GetRows() + internal int GetRows() { return rows; } - public int GetColumns() + internal int GetColumns() { return columns; } - public uint[] GetData() + internal uint[] GetData() { return data; } @@ -48,20 +45,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic : KMatrices { private int matrixPointer; - public int GetMatrixPointer() + + internal int GetMatrixPointer() { return matrixPointer; } - public void SetMatrixPointer(int matrixPointer) + internal void SetMatrixPointer(int matrixPointer) { this.matrixPointer = matrixPointer; } - public KMatricesWithPointer(KMatrices m) + internal KMatricesWithPointer(KMatrices m) : base(m.GetNmatrices(), m.GetRows(), m.GetColumns(), m.GetData()) { this.matrixPointer = 0; } } -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/picnic/Msg.cs b/crypto/src/pqc/crypto/picnic/Msg.cs index 4a8c145e7..a9a13b383 100644 --- a/crypto/src/pqc/crypto/picnic/Msg.cs +++ b/crypto/src/pqc/crypto/picnic/Msg.cs @@ -1,12 +1,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - public class Msg + internal class Msg { internal byte[][] msgs; // One for each player internal int pos; internal int unopened; // Index of the unopened party, or -1 if all parties opened (when signing) - public Msg(PicnicEngine engine) + internal Msg(PicnicEngine engine) { msgs = new byte[engine.numMPCParties][]; // engine.andSizeBytes for (int i = 0; i < engine.numMPCParties; i++) @@ -17,4 +17,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic unopened = -1; } } -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/picnic/PicnicEngine.cs b/crypto/src/pqc/crypto/picnic/PicnicEngine.cs index 0e2a4b54f..5557ddcff 100644 --- a/crypto/src/pqc/crypto/picnic/PicnicEngine.cs +++ b/crypto/src/pqc/crypto/picnic/PicnicEngine.cs @@ -8,17 +8,17 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - public class PicnicEngine + internal sealed class PicnicEngine { // same for all parameter sets - protected internal static readonly int saltSizeBytes = 32; + internal static readonly int saltSizeBytes = 32; private static readonly uint MAX_DIGEST_SIZE = 64; private static readonly int WORD_SIZE_BITS = 32; // the word size for the implementation. Not a LowMC parameter private static readonly uint LOWMC_MAX_STATE_SIZE = 64; - protected internal static readonly uint LOWMC_MAX_WORDS = (LOWMC_MAX_STATE_SIZE / 4); - protected internal static readonly uint LOWMC_MAX_KEY_BITS = 256; - protected internal static readonly uint LOWMC_MAX_AND_GATES = (3 * 38 * 10 + 4); /* Rounded to nearest byte */ + internal static readonly uint LOWMC_MAX_WORDS = (LOWMC_MAX_STATE_SIZE / 4); + internal static readonly uint LOWMC_MAX_KEY_BITS = 256; + internal static readonly uint LOWMC_MAX_AND_GATES = (3 * 38 * 10 + 4); /* Rounded to nearest byte */ private static readonly uint MAX_AUX_BYTES = ((LOWMC_MAX_AND_GATES + LOWMC_MAX_KEY_BITS) / 8 + 1); /* Maximum lengths in bytes */ @@ -28,8 +28,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic /** Largest serialized public key size, in bytes */ private static readonly uint PICNIC_MAX_PRIVATEKEY_SIZE = (3 * PICNIC_MAX_LOWMC_BLOCK_SIZE + 2); - /** Largest serialized private key size, in bytes */ - private static readonly uint PICNIC_MAX_SIGNATURE_SIZE = 209522; + //private static readonly uint PICNIC_MAX_SIGNATURE_SIZE = 209522; /** Largest signature size, in bytes */ @@ -47,45 +46,45 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic // varies between parameter sets - protected internal int numRounds; + internal int numRounds; private int numSboxes; - protected internal int stateSizeBits; - protected internal int stateSizeBytes; - protected internal int stateSizeWords; - protected internal int andSizeBytes; + internal int stateSizeBits; + internal int stateSizeBytes; + internal int stateSizeWords; + internal int andSizeBytes; private int UnruhGWithoutInputBytes; - protected internal int UnruhGWithInputBytes; - protected internal int numMPCRounds; // T - protected internal int numOpenedRounds; // u - protected internal int numMPCParties; // N - protected internal int seedSizeBytes; - protected internal int digestSizeBytes; - protected internal int pqSecurityLevel; + internal int UnruhGWithInputBytes; + internal int numMPCRounds; // T + internal int numOpenedRounds; // u + internal int numMPCParties; // N + internal int seedSizeBytes; + internal int digestSizeBytes; + internal int pqSecurityLevel; /// private uint transform; private int parameters; - protected internal IXof digest; + internal IXof digest; private int signatureLength; - public int GetSecretKeySize() + internal int GetSecretKeySize() { return CRYPTO_SECRETKEYBYTES; } - public int GetPublicKeySize() + internal int GetPublicKeySize() { return CRYPTO_PUBLICKEYBYTES; } - public int GetSignatureSize(int messageLength) + internal int GetSignatureSize(int messageLength) { return CRYPTO_BYTES + messageLength; } //todo dont do this - public int GetTrueSignatureSize() + internal int GetTrueSignatureSize() { return signatureLength + 4; } @@ -95,174 +94,174 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic parameters = picnicParams; switch (parameters) { - case 1: - case 2: - /*Picnic_L1_FS - Picnic_L1_UR*/ - pqSecurityLevel = 64; - stateSizeBits = 128; - numMPCRounds = 219; - numMPCParties = 3; - numSboxes = 10; - numRounds = 20; - digestSizeBytes = 32; - break; - case 3: - case 4: - /* Picnic_L3_FS - Picnic_L3_UR*/ - pqSecurityLevel = 96; - stateSizeBits = 192; - numMPCRounds = 329; - numMPCParties = 3; - numSboxes = 10; - numRounds = 30; - digestSizeBytes = 48; - break; - case 5: - case 6: - /* Picnic_L5_FS - Picnic_L5_UR*/ - pqSecurityLevel = 128; - stateSizeBits = 256; - numMPCRounds = 438; - numMPCParties = 3; - numSboxes = 10; - numRounds = 38; - digestSizeBytes = 64; - break; - case 7: - /*Picnic3_L1*/ - pqSecurityLevel = 64; - stateSizeBits = 129; - numMPCRounds = 250; - numOpenedRounds = 36; - numMPCParties = 16; - numSboxes = 43; - numRounds = 4; - digestSizeBytes = 32; - break; - case 8: - /*Picnic3_L3*/ - pqSecurityLevel = 96; - stateSizeBits = 192; - numMPCRounds = 419; - numOpenedRounds = 52; - numMPCParties = 16; - numSboxes = 64; - numRounds = 4; - digestSizeBytes = 48; - break; - case 9: - /*Picnic3_L5*/ - pqSecurityLevel = 128; - stateSizeBits = 255; - numMPCRounds = 601; - numOpenedRounds = 68; - numMPCParties = 16; - numSboxes = 85; - numRounds = 4; - digestSizeBytes = 64; - break; - case 10: - /*Picnic_L1_full*/ - pqSecurityLevel = 64; - stateSizeBits = 129; - numMPCRounds = 219; - numMPCParties = 3; - numSboxes = 43; - numRounds = 4; - digestSizeBytes = 32; - break; - case 11: - /*Picnic_L3_full*/ - pqSecurityLevel = 96; - stateSizeBits = 192; - numMPCRounds = 329; - numMPCParties = 3; - numSboxes = 64; - numRounds = 4; - digestSizeBytes = 48; - break; - case 12: - /*Picnic_L5_full*/ - pqSecurityLevel = 128; - stateSizeBits = 255; - numMPCRounds = 438; - numMPCParties = 3; - numSboxes = 85; - numRounds = 4; - digestSizeBytes = 64; - break; + case 1: + case 2: + /*Picnic_L1_FS + Picnic_L1_UR*/ + pqSecurityLevel = 64; + stateSizeBits = 128; + numMPCRounds = 219; + numMPCParties = 3; + numSboxes = 10; + numRounds = 20; + digestSizeBytes = 32; + break; + case 3: + case 4: + /* Picnic_L3_FS + Picnic_L3_UR*/ + pqSecurityLevel = 96; + stateSizeBits = 192; + numMPCRounds = 329; + numMPCParties = 3; + numSboxes = 10; + numRounds = 30; + digestSizeBytes = 48; + break; + case 5: + case 6: + /* Picnic_L5_FS + Picnic_L5_UR*/ + pqSecurityLevel = 128; + stateSizeBits = 256; + numMPCRounds = 438; + numMPCParties = 3; + numSboxes = 10; + numRounds = 38; + digestSizeBytes = 64; + break; + case 7: + /*Picnic3_L1*/ + pqSecurityLevel = 64; + stateSizeBits = 129; + numMPCRounds = 250; + numOpenedRounds = 36; + numMPCParties = 16; + numSboxes = 43; + numRounds = 4; + digestSizeBytes = 32; + break; + case 8: + /*Picnic3_L3*/ + pqSecurityLevel = 96; + stateSizeBits = 192; + numMPCRounds = 419; + numOpenedRounds = 52; + numMPCParties = 16; + numSboxes = 64; + numRounds = 4; + digestSizeBytes = 48; + break; + case 9: + /*Picnic3_L5*/ + pqSecurityLevel = 128; + stateSizeBits = 255; + numMPCRounds = 601; + numOpenedRounds = 68; + numMPCParties = 16; + numSboxes = 85; + numRounds = 4; + digestSizeBytes = 64; + break; + case 10: + /*Picnic_L1_full*/ + pqSecurityLevel = 64; + stateSizeBits = 129; + numMPCRounds = 219; + numMPCParties = 3; + numSboxes = 43; + numRounds = 4; + digestSizeBytes = 32; + break; + case 11: + /*Picnic_L3_full*/ + pqSecurityLevel = 96; + stateSizeBits = 192; + numMPCRounds = 329; + numMPCParties = 3; + numSboxes = 64; + numRounds = 4; + digestSizeBytes = 48; + break; + case 12: + /*Picnic_L5_full*/ + pqSecurityLevel = 128; + stateSizeBits = 255; + numMPCRounds = 438; + numMPCParties = 3; + numSboxes = 85; + numRounds = 4; + digestSizeBytes = 64; + break; } switch (parameters) { - case 1: /*Picnic_L1_FS*/ - CRYPTO_SECRETKEYBYTES = 49; - CRYPTO_PUBLICKEYBYTES = 33; - CRYPTO_BYTES = 34036; - break; - case 2: /* Picnic_L1_UR*/ - CRYPTO_SECRETKEYBYTES = 49; - CRYPTO_PUBLICKEYBYTES = 33; - CRYPTO_BYTES = 53965; - break; - case 3: /*Picnic_L3_FS*/ - CRYPTO_SECRETKEYBYTES = 73; - CRYPTO_PUBLICKEYBYTES = 49; - CRYPTO_BYTES = 76784; - break; - case 4: /*Picnic_L3_UR*/ - CRYPTO_SECRETKEYBYTES = 73; - CRYPTO_PUBLICKEYBYTES = 49; - CRYPTO_BYTES = 121857; - break; - case 5: /*Picnic_L5_FS*/ - CRYPTO_SECRETKEYBYTES = 97; - CRYPTO_PUBLICKEYBYTES = 65; - CRYPTO_BYTES = 132876; - break; - case 6: /*Picnic_L5_UR*/ - CRYPTO_SECRETKEYBYTES = 97; - CRYPTO_PUBLICKEYBYTES = 65; - CRYPTO_BYTES = 209526; - break; - case 7: /*Picnic3_L1*/ - CRYPTO_SECRETKEYBYTES = 52; - CRYPTO_PUBLICKEYBYTES = 35; - CRYPTO_BYTES = 14612; - break; - case 8: /*Picnic3_L3*/ - CRYPTO_SECRETKEYBYTES = 73; - CRYPTO_PUBLICKEYBYTES = 49; - CRYPTO_BYTES = 35028; - break; - case 9: /*Picnic3_L5*/ - CRYPTO_SECRETKEYBYTES = 97; - CRYPTO_PUBLICKEYBYTES = 65; - CRYPTO_BYTES = 61028; - break; - case 10: /*Picnic_L1_full*/ - CRYPTO_SECRETKEYBYTES = 52; - CRYPTO_PUBLICKEYBYTES = 35; - CRYPTO_BYTES = 32061; - break; - case 11: /*Picnic_L3_full*/ - CRYPTO_SECRETKEYBYTES = 73; - CRYPTO_PUBLICKEYBYTES = 49; - CRYPTO_BYTES = 71179; - break; - case 12: /*Picnic_L5_full*/ - CRYPTO_SECRETKEYBYTES = 97; - CRYPTO_PUBLICKEYBYTES = 65; - CRYPTO_BYTES = 126286; - break; - default: - CRYPTO_SECRETKEYBYTES = -1; - CRYPTO_PUBLICKEYBYTES = -1; - CRYPTO_BYTES = -1; - break; + case 1: /*Picnic_L1_FS*/ + CRYPTO_SECRETKEYBYTES = 49; + CRYPTO_PUBLICKEYBYTES = 33; + CRYPTO_BYTES = 34036; + break; + case 2: /* Picnic_L1_UR*/ + CRYPTO_SECRETKEYBYTES = 49; + CRYPTO_PUBLICKEYBYTES = 33; + CRYPTO_BYTES = 53965; + break; + case 3: /*Picnic_L3_FS*/ + CRYPTO_SECRETKEYBYTES = 73; + CRYPTO_PUBLICKEYBYTES = 49; + CRYPTO_BYTES = 76784; + break; + case 4: /*Picnic_L3_UR*/ + CRYPTO_SECRETKEYBYTES = 73; + CRYPTO_PUBLICKEYBYTES = 49; + CRYPTO_BYTES = 121857; + break; + case 5: /*Picnic_L5_FS*/ + CRYPTO_SECRETKEYBYTES = 97; + CRYPTO_PUBLICKEYBYTES = 65; + CRYPTO_BYTES = 132876; + break; + case 6: /*Picnic_L5_UR*/ + CRYPTO_SECRETKEYBYTES = 97; + CRYPTO_PUBLICKEYBYTES = 65; + CRYPTO_BYTES = 209526; + break; + case 7: /*Picnic3_L1*/ + CRYPTO_SECRETKEYBYTES = 52; + CRYPTO_PUBLICKEYBYTES = 35; + CRYPTO_BYTES = 14612; + break; + case 8: /*Picnic3_L3*/ + CRYPTO_SECRETKEYBYTES = 73; + CRYPTO_PUBLICKEYBYTES = 49; + CRYPTO_BYTES = 35028; + break; + case 9: /*Picnic3_L5*/ + CRYPTO_SECRETKEYBYTES = 97; + CRYPTO_PUBLICKEYBYTES = 65; + CRYPTO_BYTES = 61028; + break; + case 10: /*Picnic_L1_full*/ + CRYPTO_SECRETKEYBYTES = 52; + CRYPTO_PUBLICKEYBYTES = 35; + CRYPTO_BYTES = 32061; + break; + case 11: /*Picnic_L3_full*/ + CRYPTO_SECRETKEYBYTES = 73; + CRYPTO_PUBLICKEYBYTES = 49; + CRYPTO_BYTES = 71179; + break; + case 12: /*Picnic_L5_full*/ + CRYPTO_SECRETKEYBYTES = 97; + CRYPTO_PUBLICKEYBYTES = 65; + CRYPTO_BYTES = 126286; + break; + default: + CRYPTO_SECRETKEYBYTES = -1; + CRYPTO_PUBLICKEYBYTES = -1; + CRYPTO_BYTES = -1; + break; } // calculated depending on above parameters @@ -304,7 +303,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic digest = new ShakeDigest(shakeSize); } - public bool crypto_sign_open(byte[] m, byte[] sm, byte[] pk) + internal bool crypto_sign_open(byte[] m, byte[] sm, byte[] pk) { uint sigLen = Pack.LE_To_UInt32(sm, 0); byte[] m_from_sm = Arrays.CopyOfRange(sm, 4, 4 + m.Length); @@ -432,7 +431,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return status; } - void VerifyProof(Signature.Proof proof, View view1, View view2, int challenge, byte[] salt, + private void VerifyProof(Signature.Proof proof, View view1, View view2, int challenge, byte[] salt, uint roundNumber, byte[] tmp, uint[] plaintext, Tape tape) { Array.Copy(proof.communicatedBits, 0, view2.communicatedBits, 0, andSizeBytes); @@ -534,7 +533,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic mpc_LowMC_verify(view1, view2, tape, tmp_ints, plaintext, challenge); } - void mpc_LowMC_verify(View view1, View view2, Tape tapes, uint[] tmp, uint[] plaintext, int challenge) + private void mpc_LowMC_verify(View view1, View view2, Tape tapes, uint[] tmp, uint[] plaintext, int challenge) { Utils.Fill(tmp, 0, tmp.Length, 0); @@ -576,7 +575,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic Array.Copy(tmp, 3 * stateSizeWords, view2.outputShare, 0, stateSizeWords); } - void mpc_substitution_verify(uint[] state, Tape rand, View view1, View view2) + private void mpc_substitution_verify(uint[] state, Tape rand, View view1, View view2) { uint[] a = new uint[2]; uint[] b = new uint[2]; @@ -611,7 +610,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - void mpc_AND_verify(uint[] in1, uint[] in2, uint[] output, Tape rand, View view1, View view2) + private void mpc_AND_verify(uint[] in1, uint[] in2, uint[] output, Tape rand, View view1, View view2) { uint[] r = {Utils.GetBit(rand.tapes[0], rand.pos), Utils.GetBit(rand.tapes[1], rand.pos)}; @@ -646,7 +645,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } - private int DeserializeSignature(Signature sig, byte[] sigBytes, uint sigBytesLen, int sigBytesOffset) { Signature.Proof[] proofs = sig.proofs; @@ -1086,7 +1084,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return true; } - public void crypto_sign(byte[] sm, byte[] m, byte[] sk) + internal void crypto_sign(byte[] sm, byte[] m, byte[] sk) { picnic_sign(sk, m, sm); Array.Copy(m, 0, sm, 4, m.Length); @@ -1142,7 +1140,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic /*** Serialization functions ***/ - int SerializeSignature(Signature sig, byte[] sigBytes, int sigOffset) + private int SerializeSignature(Signature sig, byte[] sigBytes, int sigOffset) { Signature.Proof[] proofs = sig.proofs; byte[] challengeBits = sig.challengeBits; @@ -1204,7 +1202,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return sigByteIndex - sigOffset; } - int GetChallenge(byte[] challenge, int round) + private int GetChallenge(byte[] challenge, int round) { return (Utils.GetBit(challenge, 2 * round + 1) << 1) | Utils.GetBit(challenge, 2 * round); } @@ -1418,7 +1416,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } /* Caller must allocate the first parameter */ - void Prove(Signature.Proof proof, int challenge, byte[] seeds, int seedsOffset, + private void Prove(Signature.Proof proof, int challenge, byte[] seeds, int seedsOffset, View[] views, byte[][] commitments, byte[][] gs) { if (challenge == 0) @@ -1456,7 +1454,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - void H3(uint[] circuitOutput, uint[] plaintext, uint[][][] viewOutputs, + private void H3(uint[] circuitOutput, uint[] plaintext, uint[][][] viewOutputs, byte[][][] AS, byte[] challengeBits, byte[] salt, byte[] message, byte[][][] gs) { @@ -1659,7 +1657,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic int stateOffset; for (int i = 0; i < numSboxes * 3; i += 3) { - for (int j = 0; j < 3; j++) { stateOffset = ((3 + j) * stateSizeWords) * 32; @@ -1748,7 +1745,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic digest.Update((byte) 2); digest.BlockUpdate(seed, seedOffset, seedSizeBytes); digest.OutputFinal(tape, 0, digestSizeBytes); -// Console.Error.Write("tape: " + Hex.toHexString(tape)); /* Expand the hashed seed, salt, round and player indices, and output * length to create the tape. */ @@ -1949,7 +1945,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return missingLeaves; } - private void HCP(byte[] challengeHash, uint[] challengeC, uint[] challengeP, byte[][] Ch, byte[] hCv, byte[] salt, uint[] pubKey, uint[] plaintext, byte[] message) { @@ -1971,7 +1966,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - static int BitsToChunks(int chunkLenBits, byte[] input, int inputLen, uint[] chunks) + private static int BitsToChunks(int chunkLenBits, byte[] input, int inputLen, uint[] chunks) { if (chunkLenBits > inputLen * 8) { @@ -1992,7 +1987,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return chunkCount; } - static uint AppendUnique(uint[] list, uint value, uint position) + private static uint AppendUnique(uint[] list, uint value, uint position) { if (position == 0) { @@ -2171,7 +2166,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return true; } - static uint Extend(uint bit) + private static uint Extend(uint bit) { return ~(bit - 1); } @@ -2233,7 +2228,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - protected internal void aux_mpc_sbox(uint[] input, uint[] output, Tape tape) + internal void aux_mpc_sbox(uint[] input, uint[] output, Tape tape) { for (int i = 0; i < numSboxes * 3; i += 3) { @@ -2341,7 +2336,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic digest.OutputFinal(saltAndRoot, 0, saltAndRoot.Length); } - static bool is_picnic3(int parameters) + private static bool is_picnic3(int parameters) { return parameters == 7 /*Picnic3_L1*/ || parameters == 8 /*Picnic3_L3*/ || @@ -2349,7 +2344,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } //todo return int; - public void crypto_sign_keypair(byte[] pk, byte[] sk, SecureRandom random) + internal void crypto_sign_keypair(byte[] pk, byte[] sk, SecureRandom random) { // set array sizes byte[] plaintext_bytes = new byte[PICNIC_MAX_LOWMC_BLOCK_SIZE]; @@ -2474,7 +2469,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - protected internal void xor_array(uint[] output, uint[] in1, uint[] in2, int in2_offset, int length) + internal void xor_array(uint[] output, uint[] in1, uint[] in2, int in2_offset, int length) { for (int i = 0; i < length; i++) { @@ -2482,12 +2477,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } - protected internal void matrix_mul(uint[] output, uint[] state, uint[] matrix, int matrixOffset) + internal void matrix_mul(uint[] output, uint[] state, uint[] matrix, int matrixOffset) { matrix_mul_offset(output, 0, state, 0, matrix, matrixOffset); } - protected void matrix_mul_offset(uint[] output, int outputOffset, uint[] state, int stateOffset, uint[] matrix, + internal void matrix_mul_offset(uint[] output, int outputOffset, uint[] state, int stateOffset, uint[] matrix, int matrixOffset) { // Use temp to correctly handle the case when state = output diff --git a/crypto/src/pqc/crypto/picnic/Signature2.cs b/crypto/src/pqc/crypto/picnic/Signature2.cs index 7659fb314..c6f44380c 100644 --- a/crypto/src/pqc/crypto/picnic/Signature2.cs +++ b/crypto/src/pqc/crypto/picnic/Signature2.cs @@ -1,7 +1,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - public class Signature2 + internal class Signature2 { internal byte[] salt; internal byte[] iSeedInfo; // Info required to recompute the tree of all initial seeds @@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic internal Proof2[] proofs; // One proof for each online execution the verifier checks //todo initialize in engine! - public Signature2(PicnicEngine engine) + internal Signature2(PicnicEngine engine) { challengeHash = new byte[engine.digestSizeBytes]; salt = new byte[PicnicEngine.saltSizeBytes]; @@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic proofs = new Proof2[engine.numMPCRounds]; } - public class Proof2 + internal class Proof2 { internal byte[] seedInfo; // Information required to compute the tree with seeds of of all opened parties internal int seedInfoLen; // Length of seedInfo buffer @@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic internal byte[] input; // Masked input used in online execution internal byte[] msgs; // Broadcast messages of unopened party P[t] - public Proof2(PicnicEngine engine) + internal Proof2(PicnicEngine engine) { seedInfo = null; seedInfoLen = 0; @@ -45,6 +45,3 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } } } - - - diff --git a/crypto/src/pqc/crypto/picnic/Tape.cs b/crypto/src/pqc/crypto/picnic/Tape.cs index dd1a44de8..c433b3267 100644 --- a/crypto/src/pqc/crypto/picnic/Tape.cs +++ b/crypto/src/pqc/crypto/picnic/Tape.cs @@ -1,125 +1,128 @@ using Org.BouncyCastle.Crypto.Utilities; -using Org.BouncyCastle.Pqc.Crypto.Picnic; using Org.BouncyCastle.Utilities; -public class Tape +namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - internal byte[][] tapes; - internal int pos; - int nTapes; - - private PicnicEngine engine; - public Tape(PicnicEngine engine) + internal class Tape { - this.engine = engine; - tapes = new byte[engine.numMPCParties][]; //[2 * engine.andSizeBytes]; - for (int i = 0; i < engine.numMPCParties; i++) - { - tapes[i] = new byte[2 * engine.andSizeBytes]; - } - pos = 0; - nTapes = engine.numMPCParties; - } + internal byte[][] tapes; + internal int pos; + int nTapes; - protected internal void SetAuxBits(byte[] input) - { - int last = engine.numMPCParties - 1; - int pos = 0; - int n = engine.stateSizeBits; + private PicnicEngine engine; - for(int j = 0; j < engine.numRounds; j++) + internal Tape(PicnicEngine engine) { - for(int i = 0; i < n; i++) + this.engine = engine; + tapes = new byte[engine.numMPCParties][]; //[2 * engine.andSizeBytes]; + for (int i = 0; i < engine.numMPCParties; i++) { - Utils.SetBit(this.tapes[last], n + n*2*j + i, Utils.GetBit(input, pos++)); + tapes[i] = new byte[2 * engine.andSizeBytes]; } + pos = 0; + nTapes = engine.numMPCParties; } - } - - /* Input is the tapes for one parallel repitition; i.e., tapes[t] - * Updates the random tapes of all players with the mask values for the output of - * AND gates, and computes the N-th party's share such that the AND gate invariant - * holds on the mask values. - */ - protected internal void ComputeAuxTape(byte[] inputs) - { - uint[] roundKey = new uint[PicnicEngine.LOWMC_MAX_WORDS]; - uint[] x = new uint[PicnicEngine.LOWMC_MAX_WORDS]; - uint[] y = new uint[PicnicEngine.LOWMC_MAX_WORDS]; - uint[] key = new uint[PicnicEngine.LOWMC_MAX_WORDS]; - uint[] key0 = new uint[PicnicEngine.LOWMC_MAX_WORDS]; - key0[engine.stateSizeWords - 1] = 0; - TapesToParityBits(key0, engine.stateSizeBits); - -// System.out.print("key0: "); -// for (int i = 0; i < key0.Length; i++) -// {System.out.printf("%08x ", key0[i]);}System.out.Println(); - - // key = key0 x KMatrix[0]^(-1) - KMatricesWithPointer current = LowmcConstants.Instance.KMatrixInv(engine, 0); - engine.matrix_mul(key, key0, current.GetData(), current.GetMatrixPointer()); - -// System.out.print("key: "); -// for (int i = 0; i < key0.Length; i++) -// {System.out.printf("%08x ", key[i]);}System.out.Println(); + internal void SetAuxBits(byte[] input) + { + int last = engine.numMPCParties - 1; + int pos = 0; + int n = engine.stateSizeBits; + for(int j = 0; j < engine.numRounds; j++) + { + for(int i = 0; i < n; i++) + { + Utils.SetBit(this.tapes[last], n + n*2*j + i, Utils.GetBit(input, pos++)); + } + } + } - if(inputs != null) + /* Input is the tapes for one parallel repitition; i.e., tapes[t] + * Updates the random tapes of all players with the mask values for the output of + * AND gates, and computes the N-th party's share such that the AND gate invariant + * holds on the mask values. + */ + internal void ComputeAuxTape(byte[] inputs) { - Pack.UInt32_To_LE(Arrays.CopyOf(key, engine.stateSizeWords), inputs, 0); - } + uint[] roundKey = new uint[PicnicEngine.LOWMC_MAX_WORDS]; + uint[] x = new uint[PicnicEngine.LOWMC_MAX_WORDS]; + uint[] y = new uint[PicnicEngine.LOWMC_MAX_WORDS]; + uint[] key = new uint[PicnicEngine.LOWMC_MAX_WORDS]; + uint[] key0 = new uint[PicnicEngine.LOWMC_MAX_WORDS]; + key0[engine.stateSizeWords - 1] = 0; + TapesToParityBits(key0, engine.stateSizeBits); - for (int r = engine.numRounds; r > 0; r--) - { - current = LowmcConstants.Instance.KMatrix(engine, r); - engine.matrix_mul(roundKey, key, current.GetData(), current.GetMatrixPointer()); // roundKey = key * KMatrix(r) + // System.out.print("key0: "); + // for (int i = 0; i < key0.Length; i++) + // {System.out.printf("%08x ", key0[i]);}System.out.Println(); + + // key = key0 x KMatrix[0]^(-1) + KMatricesWithPointer current = LowmcConstants.Instance.KMatrixInv(engine, 0); + engine.matrix_mul(key, key0, current.GetData(), current.GetMatrixPointer()); - engine.xor_array(x, x, roundKey, 0, engine.stateSizeWords); + // System.out.print("key: "); + // for (int i = 0; i < key0.Length; i++) + // {System.out.printf("%08x ", key[i]);}System.out.Println(); - current = LowmcConstants.Instance.LMatrixInv(engine, r-1); - engine.matrix_mul(y, x, current.GetData(), current.GetMatrixPointer()); - if(r == 1) + if(inputs != null) { - // Use key as input - System.Array.Copy(key0, 0, x, 0, key0.Length); + Pack.UInt32_To_LE(Arrays.CopyOf(key, engine.stateSizeWords), inputs, 0); } - else + + + for (int r = engine.numRounds; r > 0; r--) { - this.pos = engine.stateSizeBits * 2 * (r - 1); - // Read input mask shares from tapes - TapesToParityBits(x, engine.stateSizeBits); + current = LowmcConstants.Instance.KMatrix(engine, r); + engine.matrix_mul(roundKey, key, current.GetData(), current.GetMatrixPointer()); // roundKey = key * KMatrix(r) + + engine.xor_array(x, x, roundKey, 0, engine.stateSizeWords); + + current = LowmcConstants.Instance.LMatrixInv(engine, r-1); + engine.matrix_mul(y, x, current.GetData(), current.GetMatrixPointer()); + + if(r == 1) + { + // Use key as input + System.Array.Copy(key0, 0, x, 0, key0.Length); + } + else + { + this.pos = engine.stateSizeBits * 2 * (r - 1); + // Read input mask shares from tapes + TapesToParityBits(x, engine.stateSizeBits); + } + + this.pos = engine.stateSizeBits * 2 * (r - 1) + engine.stateSizeBits; + engine.aux_mpc_sbox(x, y, this); } - this.pos = engine.stateSizeBits * 2 * (r - 1) + engine.stateSizeBits; - engine.aux_mpc_sbox(x, y, this); + // Reset the random tape counter so that the online execution uses the + // same random bits as when computing the aux shares + this.pos = 0; } - // Reset the random tape counter so that the online execution uses the - // same random bits as when computing the aux shares - this.pos = 0; - } - - private void TapesToParityBits(uint[] output, int outputBitLen) - { - for (int i = 0; i < outputBitLen; i++) + private void TapesToParityBits(uint[] output, int outputBitLen) { - Utils.SetBitInWordArray(output, i, Utils.Parity16(TapesToWord())); + for (int i = 0; i < outputBitLen; i++) + { + Utils.SetBitInWordArray(output, i, Utils.Parity16(TapesToWord())); + } } - } - - protected internal uint TapesToWord() - { - byte[] shares = new byte[4]; - for (int i = 0; i < 16; i++) + internal uint TapesToWord() { - byte bit = Utils.GetBit(this.tapes[i], this.pos); - Utils.SetBit(shares, i, bit); + byte[] shares = new byte[4]; + + for (int i = 0; i < 16; i++) + { + byte bit = Utils.GetBit(this.tapes[i], this.pos); + Utils.SetBit(shares, i, bit); + } + this.pos++; + return Pack.LE_To_UInt32(shares, 0); } - this.pos++; - return Pack.LE_To_UInt32(shares, 0); } -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/picnic/Tree.cs b/crypto/src/pqc/crypto/picnic/Tree.cs index 50f844a52..80b2f87ba 100644 --- a/crypto/src/pqc/crypto/picnic/Tree.cs +++ b/crypto/src/pqc/crypto/picnic/Tree.cs @@ -1,12 +1,11 @@ using System; + using Org.BouncyCastle.Crypto.Utilities; -using Org.BouncyCastle.Pqc.Crypto.Picnic; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - - public class Tree + internal sealed class Tree { private static int MAX_SEED_SIZE_BYTES = 32; private uint MAX_AUX_BYTES; @@ -22,17 +21,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic private PicnicEngine engine; - protected internal byte[][] GetLeaves() + internal byte[][] GetLeaves() { return this.nodes; } - protected internal uint GetLeavesOffset() + internal uint GetLeavesOffset() { return this.numNodes - this.numLeaves; } - public Tree(PicnicEngine engine, uint numLeaves, int dataSize) + internal Tree(PicnicEngine engine, uint numLeaves, int dataSize) { this.engine = engine; MAX_AUX_BYTES = ((PicnicEngine.LOWMC_MAX_AND_GATES + PicnicEngine.LOWMC_MAX_KEY_BITS) / 8 + 1); @@ -69,7 +68,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic /* Create a Merkle tree by hashing up all nodes. * leafData must have Length this.numNodes, but some may be NULL. */ - protected internal void BuildMerkleTree(byte[][] leafData, byte[] salt) + internal void BuildMerkleTree(byte[][] leafData, byte[] salt) { uint firstLeaf = this.numNodes - this.numLeaves; @@ -92,7 +91,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } /* verifyMerkleTree: verify for each leaf that is set */ - protected internal int VerifyMerkleTree(byte[][] leafData, byte[] salt) + internal int VerifyMerkleTree(byte[][] leafData, byte[] salt) { uint firstLeaf = this.numNodes - this.numLeaves; @@ -131,7 +130,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return 0; } - protected internal int ReconstructSeeds(uint[] hideList, uint hideListSize, + internal int ReconstructSeeds(uint[] hideList, uint hideListSize, byte[] input, uint inputLen, byte[] salt, uint repIndex) { int ret = 0; @@ -163,7 +162,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } /* Serialze the missing nodes that the verifier will require to check commitments for non-missing leaves */ - protected internal byte[] OpenMerkleTree(uint[] missingLeaves, uint missingLeavesSize, int[] outputSizeBytes) + internal byte[] OpenMerkleTree(uint[] missingLeaves, uint missingLeavesSize, int[] outputSizeBytes) { uint[] revealedSize = new uint[1]; uint[] revealed = this.GetRevealedMerkleNodes(missingLeaves, missingLeavesSize, revealedSize); @@ -293,7 +292,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic } - protected internal uint RevealSeedsSize(uint[] hideList, uint hideListSize) + internal uint RevealSeedsSize(uint[] hideList, uint hideListSize) { uint[] numNodesRevealed = new uint[1]; numNodesRevealed[0] = 0; @@ -301,7 +300,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return numNodesRevealed[0] * (uint)engine.seedSizeBytes; } - protected internal int RevealSeeds(uint[] hideList, uint hideListSize, byte[] output, int outputSize) + internal int RevealSeeds(uint[] hideList, uint hideListSize, byte[] output, int outputSize) { // byte[] outputBase = Arrays.clone(output); uint[] revealedSize = new uint[1]; @@ -330,7 +329,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return output.Length - outLen; } - protected internal uint OpenMerkleTreeSize(uint[] missingLeaves, uint missingLeavesSize) + internal uint OpenMerkleTreeSize(uint[] missingLeaves, uint missingLeavesSize) { uint[] revealedSize = new uint[1]; uint[] revealed = this.GetRevealedMerkleNodes(missingLeaves, missingLeavesSize, revealedSize); @@ -454,15 +453,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic this.haveNode[parent] = true; } - - protected internal byte[] GetLeaf(uint leafIndex) + internal byte[] GetLeaf(uint leafIndex) { uint firstLeaf = this.numNodes - this.numLeaves; return this.nodes[firstLeaf + leafIndex]; } /* addMerkleNodes: deserialize and add the data for nodes provided by the committer */ - protected internal int AddMerkleNodes(uint[] missingLeaves, uint missingLeavesSize, byte[] input, uint inputSize) + internal int AddMerkleNodes(uint[] missingLeaves, uint missingLeavesSize, byte[] input, uint inputSize) { // if (inputSize > INT_MAX) { // return -1; @@ -495,7 +493,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return 0; } - protected internal void GenerateSeeds(byte[] rootSeed, byte[] salt, uint repIndex) + internal void GenerateSeeds(byte[] rootSeed, byte[] salt, uint repIndex) { this.nodes[0] = rootSeed; this.haveNode[0] = true; @@ -578,6 +576,5 @@ namespace Org.BouncyCastle.Pqc.Crypto.Picnic return this.exists[i] == 1; } - } -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/picnic/View.cs b/crypto/src/pqc/crypto/picnic/View.cs index d72afa9d4..cac47631a 100644 --- a/crypto/src/pqc/crypto/picnic/View.cs +++ b/crypto/src/pqc/crypto/picnic/View.cs @@ -1,18 +1,16 @@ -using Org.BouncyCastle.Pqc.Crypto.Picnic; - namespace Org.BouncyCastle.Pqc.Crypto.Picnic { - public class View + internal class View { internal uint[] inputShare; internal byte[] communicatedBits; internal uint[] outputShare; - public View(PicnicEngine engine) + internal View(PicnicEngine engine) { inputShare = new uint[engine.stateSizeBytes]; communicatedBits = new byte[engine.andSizeBytes]; outputShare = new uint[engine.stateSizeBytes]; } } -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/sike/Fpx.cs b/crypto/src/pqc/crypto/sike/Fpx.cs index 9ba332753..140b36afb 100644 --- a/crypto/src/pqc/crypto/sike/Fpx.cs +++ b/crypto/src/pqc/crypto/sike/Fpx.cs @@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Cyclotomic squaring on elements of norm 1, using a^(p+1) = 1. - protected internal void sqr_Fp2_cycl(ulong[][] a, ulong[] one) + internal void sqr_Fp2_cycl(ulong[][] a, ulong[] one) { ulong[] t0 = new ulong[engine.param.NWORDS_FIELD]; @@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // n-way simultaneous inversion using Montgomery's trick. // SECURITY NOTE: This function does not run in constant time. // Also, vec and out CANNOT be the same variable! - protected internal void mont_n_way_inv(ulong[][][] vec, uint n, ulong[][][] output) + internal void mont_n_way_inv(ulong[][][] vec, uint n, ulong[][][] output) { ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); int i; @@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Copy a field element, c = a. - protected internal void fpcopy(ulong[] a, long aOffset, ulong[] c) + internal void fpcopy(ulong[] a, long aOffset, ulong[] c) { for (uint i = 0; i < engine.param.NWORDS_FIELD; i++) { @@ -77,21 +77,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // GF(p^2) addition without correction, c = a+b in GF(p^2). - protected internal void mp2_add(ulong[][] a, ulong[][] b, ulong[][] c) + internal void mp2_add(ulong[][] a, ulong[][] b, ulong[][] c) { mp_add(a[0], b[0], c[0], engine.param.NWORDS_FIELD); mp_add(a[1], b[1], c[1], engine.param.NWORDS_FIELD); } // Modular correction, a = a in GF(p^2). - protected internal void fp2correction(ulong[][] a) + internal void fp2correction(ulong[][] a) { fpcorrectionPRIME(a[0]); fpcorrectionPRIME(a[1]); } // Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit. - protected internal ulong mp_add(ulong[] a, ulong[] b, ulong[] c, uint nwords) + internal ulong mp_add(ulong[] a, ulong[] b, ulong[] c, uint nwords) { ulong carry = 0; @@ -169,7 +169,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Is x = 0? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise. // SECURITY NOTE: This function does not run in constant-time. - protected internal bool is_felm_zero(ulong[] x) + internal bool is_felm_zero(ulong[] x) { for (uint i = 0; i < engine.param.NWORDS_FIELD; i++) { @@ -205,7 +205,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Test if a is a square in GF(p^2) and return 1 if true, 0 otherwise // If a is a quadratic residue, s will be assigned with a partially computed square root of a - protected internal bool is_sqr_fp2(ulong[][] a, ulong[] s) + internal bool is_sqr_fp2(ulong[][] a, ulong[] s) { uint i; ulong[] a0 = new ulong[engine.param.NWORDS_FIELD], @@ -365,7 +365,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2) // This uses the binary GCD for inversion in fp and is NOT constant time!!! - protected internal void fp2inv_mont_bingcd(ulong[][] a) + internal void fp2inv_mont_bingcd(ulong[][] a) { ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -381,7 +381,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // GF(p^2) division by two, c = a/2 in GF(p^2). - protected internal void fp2div2(ulong[][] a, ulong[][] c) + internal void fp2div2(ulong[][] a, ulong[][] c) { //todo/org : make fp class and change this to generic fpdiv2 fpdiv2_PRIME(a[0], c[0]); @@ -606,7 +606,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike Debug.Assert(t == 0); } - protected internal static bool subarrayEquals(ulong[] a, ulong[] b, uint length) + internal static bool subarrayEquals(ulong[] a, ulong[] b, uint length) { // if(a.Length < length || b.Length < length) // return false; @@ -619,7 +619,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike return true; } - protected internal static bool subarrayEquals(ulong[][] a, ulong[][] b, uint length) + internal static bool subarrayEquals(ulong[][] a, ulong[][] b, uint length) { int nwords_feild = b[0].Length; // if(a[0].Length < length || b[0].Length < length) @@ -633,7 +633,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike return true; } - protected internal static bool subarrayEquals(ulong[][] a, ulong[][] b, uint bOffset, uint length) + internal static bool subarrayEquals(ulong[][] a, ulong[][] b, uint bOffset, uint length) { int nwords_feild = b[0].Length; // if(a[0].Length*2 < length || b[0].Length*2 < length) @@ -647,7 +647,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike return true; } - protected internal static bool subarrayEquals(ulong[][] a, ulong[] b, uint bOffset, uint length) + internal static bool subarrayEquals(ulong[][] a, ulong[] b, uint bOffset, uint length) { int nwords_field = a[0].Length; // if(a[0].Length < length || b.Length < length) @@ -662,9 +662,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Computes square roots of elements in (Fp2)^2 using Hamburg's trick. - protected internal void sqrt_Fp2(ulong[][] u, ulong[][] y) + internal void sqrt_Fp2(ulong[][] u, ulong[][] y) { - ulong[] t0 = new ulong[engine.param.NWORDS_FIELD], t1 = new ulong[engine.param.NWORDS_FIELD], t2 = new ulong[engine.param.NWORDS_FIELD], @@ -714,7 +713,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // GF(p^2) squaring using Montgomery arithmetic, c = a^2 in GF(p^2). // Inputs: a = a0+a1*i, where a0, a1 are in [0, 2*p-1] // Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1] - protected internal void fp2sqr_mont(ulong[][] a, ulong[][] c) + internal void fp2sqr_mont(ulong[][] a, ulong[][] c) { ulong[] t1 = new ulong[engine.param.NWORDS_FIELD], t2 = new ulong[engine.param.NWORDS_FIELD], @@ -731,7 +730,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Modular addition, c = a+b mod PRIME. // Inputs: a, b in [0, 2*PRIME-1] // Output: c in [0, 2*PRIME-1] - protected internal void fpaddPRIME(ulong[] a, ulong[] b, ulong[] c) + internal void fpaddPRIME(ulong[] a, ulong[] b, ulong[] c) { ulong i, carry = 0; ulong mask; @@ -769,7 +768,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Cyclotomic cubing on elements of norm 1, using a^(p+1) = 1. - protected internal void cube_Fp2_cycl(ulong[][] a, ulong[] one) + internal void cube_Fp2_cycl(ulong[][] a, ulong[] one) { ulong[] t0 = new ulong[engine.param.NWORDS_FIELD]; @@ -786,7 +785,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Modular subtraction, c = a-b mod PRIME. // Inputs: a, b in [0, 2*PRIME-1] // Output: c in [0, 2*PRIME-1] - protected internal void fpsubPRIME(ulong[] a, ulong[] b, uint bOffset, ulong[] c) + internal void fpsubPRIME(ulong[] a, ulong[] b, uint bOffset, ulong[] c) { ulong i, borrow = 0; ulong mask; @@ -811,7 +810,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } } - protected internal void fpsubPRIME(ulong[] a, uint aOffset, ulong[] b, ulong[] c) + internal void fpsubPRIME(ulong[] a, uint aOffset, ulong[] b, ulong[] c) { ulong i, borrow = 0; ulong mask; @@ -836,7 +835,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } } - protected internal void fpsubPRIME(ulong[] a, ulong[] b, ulong[] c) + internal void fpsubPRIME(ulong[] a, ulong[] b, ulong[] c) { ulong i, borrow = 0; ulong mask; @@ -864,7 +863,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // todo/org : move to fp_generic // Modular negation, a = -a mod PRIME. // Input/output: a in [0, 2*PRIME-1] - protected internal void fpnegPRIME(ulong[] a) + internal void fpnegPRIME(ulong[] a) { ulong i, borrow = 0; @@ -881,7 +880,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // todo/org : move to fp_generic // Conversion of a GF(p^2) element from Montgomery representation to standard representation, // c_i = ma_i*R^(-1) = a_i in GF(p^2). - protected internal void from_fp2mont(ulong[][] ma, ulong[][] c) + internal void from_fp2mont(ulong[][] ma, ulong[][] c) { from_mont(ma[0], c[0]); from_mont(ma[1], c[1]); @@ -889,7 +888,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // todo/org : move to fp_generic // Conversion of GF(p^2) element from Montgomery to standard representation, and encoding by removing leading 0 bytes - protected internal void fp2_encode(ulong[][] x, byte[] enc, uint encOffset) + internal void fp2_encode(ulong[][] x, byte[] enc, uint encOffset) { ulong[][] t = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -899,7 +898,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Parse byte sequence back uinto GF(p^2) element, and conversion to Montgomery representation - protected internal void fp2_decode(byte[] x, ulong[][] dec, uint xOffset) + internal void fp2_decode(byte[] x, ulong[][] dec, uint xOffset) { decode_to_digits(x, xOffset, dec[0], engine.param.FP2_ENCODED_BYTES / 2, engine.param.NWORDS_FIELD); decode_to_digits(x,xOffset + (engine.param.FP2_ENCODED_BYTES/2), dec[1], engine.param.FP2_ENCODED_BYTES / 2, engine.param.NWORDS_FIELD); @@ -907,7 +906,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Conversion of elements in Z_r to Montgomery representation, where the order r is up to NBITS_ORDER bits. - protected internal void to_Montgomery_mod_order(ulong[] a, ulong[] mc, ulong[] order, ulong[] Montgomery_rprime, ulong[] Montgomery_Rprime) + internal void to_Montgomery_mod_order(ulong[] a, ulong[] mc, ulong[] order, ulong[] Montgomery_rprime, ulong[] Montgomery_Rprime) { Montgomery_multiply_mod_order(a, Montgomery_Rprime, mc, order, Montgomery_rprime); } @@ -916,7 +915,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // ma, mb and mc are assumed to be in Montgomery representation. // The Montgomery constant r' = -r^(-1) mod 2^(log_2(r)) is the value "Montgomery_rprime", where r is the order. // Assume log_2(r) is a multiple of RADIX bits - protected internal void Montgomery_multiply_mod_order(ulong[] ma, ulong[] mb, ulong[] mc, ulong[] order, ulong[] Montgomery_rprime) + internal void Montgomery_multiply_mod_order(ulong[] ma, ulong[] mb, ulong[] mc, ulong[] order, ulong[] Montgomery_rprime) { ulong i, cout = 0, bout = 0; ulong mask; @@ -949,7 +948,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Inversion of an odd uinteger modulo an even uinteger of the form 2^m. // Algorithm 3: Explicit Quadratic Modular inverse modulo 2^m from Dumas'12: http://arxiv.org/pdf/1209.6626.pdf // If the input is invalid (even), the function outputs c = a. - protected internal void inv_mod_orderA(ulong[] a, ulong[] c) + internal void inv_mod_orderA(ulong[] a, ulong[] c) { uint i, f, s = 0; ulong[] am1 = new ulong[engine.param.NWORDS_ORDER], @@ -999,7 +998,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords. // NOTE: a and c CANNOT be the same variable! - protected internal void multiply(ulong[] a, ulong[] b, ulong[] c, uint nwords) + internal void multiply(ulong[] a, ulong[] b, ulong[] c, uint nwords) { ulong i, j; ulong t = 0, u = 0, v = 0; @@ -1187,7 +1186,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Montgomery inversion modulo order, c = a^(-1)*R mod order. - protected internal void Montgomery_inversion_mod_order_bingcd(ulong[] a, ulong[] c, ulong[] order, ulong[] Montgomery_rprime, ulong[] Montgomery_Rprime) + internal void Montgomery_inversion_mod_order_bingcd(ulong[] a, ulong[] c, ulong[] order, ulong[] Montgomery_rprime, ulong[] Montgomery_Rprime) { ulong[] x = new ulong[engine.param.NWORDS_ORDER], t = new ulong[engine.param.NWORDS_ORDER]; @@ -1211,7 +1210,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Conversion of elements in Z_r from Montgomery to standard representation, where the order is up to NBITS_ORDER bits. - protected internal void from_Montgomery_mod_order(ulong[] ma, ulong[] c, ulong[] order, ulong[] Montgomery_rprime) + internal void from_Montgomery_mod_order(ulong[] ma, ulong[] c, ulong[] order, ulong[] Montgomery_rprime) { ulong[] one = new ulong[engine.param.NWORDS_ORDER]; one[0] = 1; @@ -1221,7 +1220,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Computes the input modulo 3 // The input is assumed to be NWORDS_ORDER ulong - protected internal uint mod3(ulong[] a) + internal uint mod3(ulong[] a) { ulong result = 0; for (int i = 0; i < engine.param.NWORDS_ORDER; ++i) @@ -1234,7 +1233,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Conversion of a GF(p^2) element to Montgomery representation, // mc_i = a_i*R^2*R^(-1) = a_i*R in GF(p^2). - protected internal void to_fp2mont(ulong[][] a, ulong[][] mc) + internal void to_fp2mont(ulong[][] a, ulong[][] mc) { to_mont(a[0], mc[0]); to_mont(a[1], mc[1]); @@ -1251,7 +1250,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // todo/org : move to fp_generic // Modular correction to reduce field element a in [0, 2*PRIME-1] to [0, PRIME-1]. - protected internal void fpcorrectionPRIME(ulong[] a) + internal void fpcorrectionPRIME(ulong[] a) { ulong i, borrow = 0; ulong mask; @@ -1276,7 +1275,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } } - protected internal byte cmp_f2elm(ulong[][] x, ulong[][] y) + internal byte cmp_f2elm(ulong[][] x, ulong[][] y) { // Comparison of two GF(p^2) elements in constant time. // Is x != y? return -1 if condition is true, 0 otherwise. ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -1298,7 +1297,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Encoding digits to bytes according to endianness - protected internal void encode_to_bytes(ulong[] x, byte[] enc, uint encOffset, uint nbytes) + internal void encode_to_bytes(ulong[] x, byte[] enc, uint encOffset, uint nbytes) { byte[] test = new byte[((nbytes*4+7)&~7)]; Pack.UInt64_To_LE(x, test, 0); @@ -1306,7 +1305,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Decoding bytes to digits according to endianness - protected internal void decode_to_digits(byte[] x, uint xOffset, ulong[] dec, uint nbytes, uint ndigits) + internal void decode_to_digits(byte[] x, uint xOffset, ulong[] dec, uint nbytes, uint ndigits) { // x -> dec dec[ndigits - 1] = 0; @@ -1317,7 +1316,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // r = a - b*i where v = a + b*i - protected internal void fp2_conj(ulong[][] v, ulong[][] r) + internal void fp2_conj(ulong[][] v, ulong[][] r) { fpcopy(v[0], 0, r[0]); fpcopy(v[1], 0, r[1]); @@ -1368,28 +1367,28 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Copy a GF(p^2) element, c = a. - protected internal void fp2copy(ulong[][] a, ulong[][] c) + internal void fp2copy(ulong[][] a, ulong[][] c) { fpcopy(a[0], 0, c[0]); fpcopy(a[1], 0, c[1]); } // Copy a GF(p^2) element, c = a. - protected internal void fp2copy(ulong[][] a, uint aOffset, ulong[][] c) + internal void fp2copy(ulong[][] a, uint aOffset, ulong[][] c) { fpcopy(a[0 + aOffset], 0, c[0]); fpcopy(a[1 + aOffset], 0, c[1]); } // Copy a GF(p^2) element, c = a. - protected internal void fp2copy(ulong[] a, uint aOffset, ulong[][] c) + internal void fp2copy(ulong[] a, uint aOffset, ulong[][] c) { fpcopy(a, aOffset, c[0]); fpcopy(a, aOffset + engine.param.NWORDS_FIELD, c[1]); } // Zero a field element, a = 0. - protected internal void fpzero(ulong[] a) + internal void fpzero(ulong[] a) { uint i; @@ -1400,7 +1399,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // GF(p^2) subtraction with correction with 2*p, c = a-b+2p in GF(p^2). - protected internal void mp2_sub_p2(ulong[][] a, ulong[][] b, ulong[][] c) + internal void mp2_sub_p2(ulong[][] a, ulong[][] b, ulong[][] c) { //todo/org : make fp class and change this to generic mp_sub_p2 mp_subPRIME_p2(a[0], b[0], c[0]); @@ -1408,7 +1407,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords. - protected internal void mp_mul(ulong[] a, ulong[] b, ulong[] c, uint nwords) + internal void mp_mul(ulong[] a, ulong[] b, ulong[] c, uint nwords) { ulong i, j; ulong t = 0, u = 0, v = 0; @@ -1461,7 +1460,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords. - protected internal void mp_mul(ulong[] a, uint aOffset, ulong[] b, ulong[] c, uint nwords) + internal void mp_mul(ulong[] a, uint aOffset, ulong[] b, ulong[] c, uint nwords) { ulong i, j; ulong t = 0, u = 0, v = 0; @@ -1516,7 +1515,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // GF(p^2) multiplication using Montgomery arithmetic, c = a*b in GF(p^2). // Inputs: a = a0+a1*i and b = b0+b1*i, where a0, a1, b0, b1 are in [0, 2*p-1] // Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1] - protected internal void fp2mul_mont(ulong[][] a, ulong[][] b, ulong[][] c) + internal void fp2mul_mont(ulong[][] a, ulong[][] b, ulong[][] c) { ulong[] t1 = new ulong[engine.param.NWORDS_FIELD], t2 = new ulong[engine.param.NWORDS_FIELD]; @@ -1535,7 +1534,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike rdc_mont(tt1, c[0]); // c[0] = a0*b0 - a1*b1 } - protected internal void fp2mul_mont(ulong[][] a, ulong[][] b, uint bOffset, ulong[][] c) + internal void fp2mul_mont(ulong[][] a, ulong[][] b, uint bOffset, ulong[][] c) { // System.out.pruint("b: "); @@ -1559,7 +1558,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike rdc_mont(tt1, c[0]); // c[0] = a0*b0 - a1*b1 } - protected internal void fp2mul_mont(ulong[][] a, ulong[] b, uint bOffset, ulong[][] c) + internal void fp2mul_mont(ulong[][] a, ulong[] b, uint bOffset, ulong[][] c) { ulong[] t1 = new ulong[engine.param.NWORDS_FIELD], t2 = new ulong[engine.param.NWORDS_FIELD]; @@ -1587,7 +1586,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit. - protected internal ulong mp_sub(ulong[] a, ulong[] b, ulong[] c, uint nwords) + internal ulong mp_sub(ulong[] a, ulong[] b, ulong[] c, uint nwords) { ulong i, borrow = 0; @@ -1606,7 +1605,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Is x < y? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise. // SECURITY NOTE: This function does not run in constant-time. - protected internal bool is_orderelm_lt(ulong[] x, ulong[] y) + internal bool is_orderelm_lt(ulong[] x, ulong[] y) { for (int i = (int)engine.param.NWORDS_ORDER-1; i >= 0; i--) { @@ -1637,7 +1636,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision squaring, c = a^2 mod p. - protected internal void fpsqr_mont(ulong[] ma, ulong[] mc) + internal void fpsqr_mont(ulong[] ma, ulong[] mc) { ulong[] temp = new ulong[2*engine.param.NWORDS_FIELD]; @@ -1658,7 +1657,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2). - protected internal void fp2inv_mont(ulong[][] a) + internal void fp2inv_mont(ulong[][] a) { ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -1673,7 +1672,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Computes a = 3*a // The input is assumed to be OBOB_BITS-2 bits ulong and stored in SECRETKEY_B_BYTES - protected internal void mul3(byte[] a) + internal void mul3(byte[] a) { ulong[] temp1 = new ulong[engine.param.NWORDS_ORDER], temp2 = new ulong[engine.param.NWORDS_ORDER]; @@ -1686,7 +1685,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Compare two byte arrays in constant time. // Returns 0 if the byte arrays are equal, -1 otherwise. - protected internal byte ct_compare(byte[] a, byte[] b, uint len) + internal byte ct_compare(byte[] a, byte[] b, uint len) { byte r = 0; @@ -1699,7 +1698,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // Conditional move in constant time. // If selector = -1 then load r with a, else if selector = 0 then keep r. - protected internal void ct_cmov(byte[] r, byte[] a, uint len, byte selector) + internal void ct_cmov(byte[] r, byte[] a, uint len, byte selector) { for (uint i = 0; i < len; i++) { @@ -1708,7 +1707,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Copy wordsize digits, c = a, where lng(a) = nwords. - protected internal void copy_words(ulong[] a, ulong[] c, uint nwords) + internal void copy_words(ulong[] a, ulong[] c, uint nwords) { uint i; for (i = 0; i < nwords; i++) @@ -1718,7 +1717,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // c = (2^k)*a - protected internal void fp2shl(ulong[][] a, uint k, ulong[][] c) + internal void fp2shl(ulong[][] a, uint k, ulong[][] c) { fp2copy(a, c); for (uint j = 0; j < k; j++) @@ -1728,7 +1727,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Copy wordsize digits, c = a, where lng(a) = nwords. - protected internal void copy_words(PointProj a, PointProj c) + internal void copy_words(PointProj a, PointProj c) { uint i; for (i = 0; i < engine.param.NWORDS_FIELD; i++) @@ -1759,7 +1758,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike // GF(p^2) addition, c = a+b in GF(p^2). - protected internal void fp2add(ulong[][] a, ulong[][] b, ulong[][] c) + internal void fp2add(ulong[][] a, ulong[][] b, ulong[][] c) { //todo/org : make fp class and change this to generic function fpaddPRIME(a[0], b[0], c[0]); @@ -1767,7 +1766,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // GF(p^2) subtraction, c = a-b in GF(p^2). - protected internal void fp2sub(ulong[][] a, ulong[][] b, ulong[][] c) + internal void fp2sub(ulong[][] a, ulong[][] b, ulong[][] c) { //todo/org : make fp class and change this to generic function fpsubPRIME(a[0], b[0], c[0]); @@ -1783,7 +1782,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision multiplication, c = a*b mod p. - protected internal void fpmul_mont(ulong[] ma, ulong[] mb, ulong[] mc) + internal void fpmul_mont(ulong[] ma, ulong[] mb, ulong[] mc) { ulong[] temp = new ulong[2*engine.param.NWORDS_FIELD]; @@ -1792,7 +1791,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } // Multiprecision multiplication, c = a*b mod p. - protected internal void fpmul_mont(ulong[] ma, uint maOffset, ulong[] mb, ulong[] mc) + internal void fpmul_mont(ulong[] ma, uint maOffset, ulong[] mb, ulong[] mc) { ulong[] temp = new ulong[2*engine.param.NWORDS_FIELD]; @@ -2233,5 +2232,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike } } } - - } \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/sike/Isogeny.cs b/crypto/src/pqc/crypto/sike/Isogeny.cs index 2d0ef1473..be9e3ba4d 100644 --- a/crypto/src/pqc/crypto/sike/Isogeny.cs +++ b/crypto/src/pqc/crypto/sike/Isogeny.cs @@ -12,7 +12,7 @@ internal sealed class Isogeny // Doubling of a Montgomery point in projective coordinates (X:Z) over affine curve coefficient A. // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants (A+2)/4. // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2). - protected internal void Double(PointProj P, PointProj Q, ulong[][] A24, uint k) + internal void Double(PointProj P, PointProj Q, ulong[][] A24, uint k) { ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -37,7 +37,7 @@ internal sealed class Isogeny } } - protected internal void CompleteMPoint(ulong[][] A, PointProj P, PointProjFull R) + internal void CompleteMPoint(ulong[][] A, PointProj P, PointProjFull R) { // Given an xz-only representation on a montgomery curve, compute its affine representation ulong[][] zero = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -81,10 +81,9 @@ internal sealed class Isogeny internal void Ladder(PointProj P, ulong[] m, ulong[][] A, uint order_bits, PointProj R) { - PointProj R0 = new PointProj(engine.param.NWORDS_FIELD), - R1 = new PointProj(engine.param.NWORDS_FIELD); + var R0 = new PointProj(engine.param.NWORDS_FIELD); + var R1 = new PointProj(engine.param.NWORDS_FIELD); ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); - uint bit = 0; ulong mask; int j, swap, prevbit = 0; @@ -96,7 +95,7 @@ internal sealed class Isogeny engine.fpx.fp2div2(A24, A24); // A24 = (A+2)/4 j = (int)order_bits - 1; - bit = (uint) ((m[j >> (int)Internal.LOG2RADIX] >> (int)(j & (Internal.RADIX-1))) & 1); + uint bit = (uint) ((m[j >> (int)Internal.LOG2RADIX] >> (int)(j & (Internal.RADIX-1))) & 1); while (bit == 0) { j--; @@ -106,7 +105,7 @@ internal sealed class Isogeny // R0 <- P, R1 <- 2P engine.fpx.fp2copy(P.X, R0.X); engine.fpx.fp2copy(P.Z, R0.Z); - xDBL_e(P, R1, A24, 1); + XDblE(P, R1, A24, 1); // Main loop for (int i = (int)j - 1; i >= 0; i--) @@ -116,12 +115,12 @@ internal sealed class Isogeny prevbit = (int) bit; mask = (ulong) (0 - swap); - swap_points(R0, R1, mask); - xDBLADD_proj(R0, R1, P.X, P.Z, A24); + SwapPoints(R0, R1, mask); + XDblAddProj(R0, R1, P.X, P.Z, A24); } swap = 0 ^ prevbit; mask = (ulong) (0 - swap); - swap_points(R0, R1, mask); + SwapPoints(R0, R1, mask); engine.fpx.fp2copy(R0.X, R.X); engine.fpx.fp2copy(R0.Z, R.Z); @@ -130,7 +129,7 @@ internal sealed class Isogeny // Simultaneous doubling and differential addition. // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, affine difference xPQ=x(P-Q) and Montgomery curve constant A24=(A+2)/4. // Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP. - private void xDBLADD_proj(PointProj P, PointProj Q, ulong[][] XPQ, ulong[][] ZPQ, ulong[][] A24) + private void XDblAddProj(PointProj P, PointProj Q, ulong[][] XPQ, ulong[][] ZPQ, ulong[][] A24) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -162,7 +161,7 @@ internal sealed class Isogeny // Doubling of a Montgomery point in projective coordinates (X:Z) over affine curve coefficient A. // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants (A+2)/4. // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2). - private void xDBL_e(PointProj P, PointProj Q, ulong[][] A24, int e) + private void XDblE(PointProj P, PointProj Q, ulong[][] A24, int e) { ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -192,14 +191,14 @@ internal sealed class Isogeny // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings. e triplings in E costs k*(5M + 6S + 9A) // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z, Montgomery curve constant A2 = A/2 and the number of triplings e. // Output: projective Montgomery x-coordinates Q <- [3^e]P. - internal void xTPLe_fast(PointProj P, PointProj Q, ulong[][] A2, uint e) + internal void XTplEFast(PointProj P, PointProj Q, ulong[][] A2, uint e) { - PointProj T = new PointProj(engine.param.NWORDS_FIELD); + var T = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.copy_words(P, T); for (int j = 0; j < e; j++) { - xTPL_fast(T, T, A2); + XTplFast(T, T, A2); } engine.fpx.copy_words(T, Q); } @@ -207,7 +206,7 @@ internal sealed class Isogeny // Montgomery curve (E: y^2 = x^3 + A*x^2 + x) x-only tripling at a cost 5M + 6S + 9A = 27p + 61a. // Input : projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constant A/2. // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3). - private void xTPL_fast(PointProj P, PointProj Q, ulong[][] A2) + private void XTplFast(PointProj P, PointProj Q, ulong[][] A2) { ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -238,10 +237,10 @@ internal sealed class Isogeny } - protected internal void LADDER3PT(ulong[][] xP, ulong[][] xQ, ulong[][] xPQ, ulong[] m, uint AliceOrBob, PointProj R, ulong[][] A) + internal void LADDER3PT(ulong[][] xP, ulong[][] xQ, ulong[][] xPQ, ulong[] m, uint AliceOrBob, PointProj R, ulong[][] A) { - PointProj R0 = new PointProj(engine.param.NWORDS_FIELD), - R2 = new PointProj(engine.param.NWORDS_FIELD); + var R0 = new PointProj(engine.param.NWORDS_FIELD); + var R2 = new PointProj(engine.param.NWORDS_FIELD); ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong mask; uint i, nbits, bit, swap, prevbit = 0; @@ -277,17 +276,17 @@ internal sealed class Isogeny swap = bit ^ prevbit; prevbit = bit; mask = 0 - (ulong) swap; - swap_points(R, R2, mask); - xDBLADD(R0, R2, R.X, A24); + SwapPoints(R, R2, mask); + XDblAdd(R0, R2, R.X, A24); engine.fpx.fp2mul_mont(R2.X, R.Z, R2.X); } swap = 0 ^ prevbit; mask = 0 - (ulong)swap; - swap_points(R, R2, mask); + SwapPoints(R, R2, mask); } // Complete point on A = 0 curve - protected internal void CompletePoint(PointProj P, PointProjFull R) + internal void CompletePoint(PointProj P, PointProjFull R) { ulong[][] xz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), s2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -318,13 +317,11 @@ internal sealed class Isogeny // Swap points. // If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P - protected internal void swap_points(PointProj P, PointProj Q, ulong option) + internal void SwapPoints(PointProj P, PointProj Q, ulong option) { //todo/org : put this in the PointProj class ulong temp; - int i; - - for (i = 0; i < engine.param.NWORDS_FIELD; i++) + for (int i = 0; i < engine.param.NWORDS_FIELD; i++) { temp = option & (P.X[0][i] ^ Q.X[0][i]); P.X[0][i] = temp ^ P.X[0][i]; @@ -344,7 +341,7 @@ internal sealed class Isogeny // Simultaneous doubling and differential addition. // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, affine difference xPQ=x(P-Q) and Montgomery curve constant A24=(A+2)/4. // Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP. - protected internal void xDBLADD(PointProj P, PointProj Q, ulong[][] xPQ, ulong[][] A24) + internal void XDblAdd(PointProj P, PointProj Q, ulong[][] xPQ, ulong[][] A24) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -373,21 +370,21 @@ internal sealed class Isogeny // Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A+2C and 4C. // Output: projective Montgomery x-coordinates Q <- (2^e)*P. - protected internal void xDBLe(PointProj P, PointProj Q, ulong[][] A24plus, ulong[][] C24, uint e) + internal void XDblE(PointProj P, PointProj Q, ulong[][] A24plus, ulong[][] C24, uint e) { int i; engine.fpx.copy_words(P, Q); for (i = 0; i < e; i++) { - xDBL(Q, Q, A24plus, C24); + XDbl(Q, Q, A24plus, C24); } } // Doubling of a Montgomery point in projective coordinates (X:Z). // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants A+2C and 4C. // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2). - protected void xDBL(PointProj P, PointProj Q, ulong[][] A24plus, ulong[][] C24) + internal void XDbl(PointProj P, PointProj Q, ulong[][] A24plus, ulong[][] C24) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -407,7 +404,7 @@ internal sealed class Isogeny // Tripling of a Montgomery point in projective coordinates (X:Z). // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constants A24plus = A+2C and A24minus = A-2C. // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3). - private void xTPL(PointProj P, PointProj Q, ulong[][] A24minus, ulong[][] A24plus) + private void XTpl(PointProj P, PointProj Q, ulong[][] A24minus, ulong[][] A24plus) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -444,20 +441,20 @@ internal sealed class Isogeny // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A24plus = A+2C and A24minus = A-2C. // Output: projective Montgomery x-coordinates Q <- (3^e)*P. - protected internal void xTPLe(PointProj P, PointProj Q, ulong[][] A24minus, ulong[][] A24plus, uint e) + internal void XTplE(PointProj P, PointProj Q, ulong[][] A24minus, ulong[][] A24plus, uint e) { int i; engine.fpx.copy_words(P, Q); for (i = 0; i < e; i++) { - xTPL(Q, Q, A24minus, A24plus); + XTpl(Q, Q, A24minus, A24plus); } } // Given the x-coordinates of P, Q, and R, returns the value A corresponding to the Montgomery curve E_A: y^2=x^3+A*x^2+x such that R=Q-P on E_A. // Input: the x-coordinates xP, xQ, and xR of the points P, Q and R. // Output: the coefficient A corresponding to the curve E_A: y^2=x^3+A*x^2+x. - protected internal void get_A(ulong[][] xP, ulong[][] xQ, ulong[][] xR, ulong[][] A) + internal void GetA(ulong[][] xP, ulong[][] xQ, ulong[][] xR, ulong[][] A) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -482,7 +479,7 @@ internal sealed class Isogeny // Computes the j-invariant of a Montgomery curve with projective constant. // Input: A,C in GF(p^2). // Output: j=256*(A^2-3*C^2)^3/(C^4*(A^2-4*C^2)), which is the j-invariant of the Montgomery curve B*y^2=x^3+(A/C)*x^2+x or (equivalently) j-invariant of B'*y^2=C*x^3+A*x^2+C*x. - protected internal void j_inv(ulong[][] A, ulong[][] C, ulong[][] jinv) + internal void JInv(ulong[][] A, ulong[][] C, ulong[][] jinv) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -510,7 +507,7 @@ internal sealed class Isogeny // Computes the corresponding 3-isogeny of a projective Montgomery point (X3:Z3) of order 3. // Input: projective point of order three P = (X3:Z3). // Output: the 3-isogenous Montgomery curve with projective coefficient A/C. - protected internal void get_3_isog(PointProj P, ulong[][] A24minus, ulong[][] A24plus, ulong[][][] coeff) + internal void Get3Isog(PointProj P, ulong[][] A24minus, ulong[][] A24plus, ulong[][][] coeff) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -540,7 +537,7 @@ internal sealed class Isogeny // a point P with 2 coefficients in coeff (computed in the function get_3_Isog()). // Inputs: projective points P = (X3:Z3) and Q = (X:Z). // Output: the projective point Q <- phi(Q) = (X3:Z3). - protected internal void eval_3_isog(PointProj Q, ulong[][][] coeff) + internal void Eval3Isog(PointProj Q, ulong[][][] coeff) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -561,7 +558,7 @@ internal sealed class Isogeny // 3-way simultaneous inversion // Input: z1,z2,z3 // Output: 1/z1,1/z2,1/z3 (override inputs). - protected internal void inv_3_way(ulong[][] z1, ulong[][] z2, ulong[][] z3) + internal void Inv3Way(ulong[][] z1, ulong[][] z2, ulong[][] z3) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -581,7 +578,7 @@ internal sealed class Isogeny // Computes the corresponding 2-isogeny of a projective Montgomery point (X2:Z2) of order 2. // Input: projective point of order two P = (X2:Z2). // Output: the 2-isogenous Montgomery curve with projective coefficients A/C. - protected internal void get_2_isog(PointProj P, ulong[][] A, ulong[][] C) + internal void Get2Isog(PointProj P, ulong[][] A, ulong[][] C) { engine.fpx.fp2sqr_mont(P.X, A); // A = X2^2 engine.fpx.fp2sqr_mont(P.Z, C); // C = Z2^2 @@ -591,7 +588,7 @@ internal sealed class Isogeny // Evaluates the isogeny at the point (X:Z) in the domain of the isogeny, given a 2-isogeny phi. // Inputs: the projective point P = (X:Z) and the 2-isogeny kernel projetive point Q = (X2:Z2). // Output: the projective point P = phi(P) = (X:Z) in the codomain. - protected internal void eval_2_isog(PointProj P, PointProj Q) + internal void Eval2Isog(PointProj P, PointProj Q) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -614,7 +611,7 @@ internal sealed class Isogeny // Input: projective point of order four P = (X4:Z4). // Output: the 4-isogenous Montgomery curve with projective coefficients A+2C/4C and the 3 coefficients // that are used to evaluate the isogeny at a point in eval_4_Isog(). - protected internal void get_4_isog(PointProj P, ulong[][] A24plus, ulong[][] C24, ulong[][][] coeff) + internal void Get4Isog(PointProj P, ulong[][] A24plus, ulong[][] C24, ulong[][][] coeff) { engine.fpx.mp2_sub_p2(P.X, P.Z, coeff[1]); // coeff[1] = X4-Z4 engine.fpx.mp2_add(P.X, P.Z, coeff[2]); // coeff[2] = X4+Z4 @@ -631,7 +628,7 @@ internal sealed class Isogeny // by the 3 coefficients in coeff (computed in the function get_4_Isog()). // Inputs: the coefficients defining the isogeny, and the projective point P = (X:Z). // Output: the projective point P = phi(P) = (X:Z) in the codomain. - protected internal void eval_4_isog(PointProj P, ulong[][][] coeff) + internal void Eval4Isog(PointProj P, ulong[][][] coeff) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -651,9 +648,5 @@ internal sealed class Isogeny engine.fpx.fp2mul_mont(P.X, t1, P.X); // Xfinal engine.fpx.fp2mul_mont(P.Z, t0, P.Z); // Zfinal } - - - } - -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/sike/SIDH.cs b/crypto/src/pqc/crypto/sike/SIDH.cs index c1d1714f6..8246291c6 100644 --- a/crypto/src/pqc/crypto/sike/SIDH.cs +++ b/crypto/src/pqc/crypto/sike/SIDH.cs @@ -4,13 +4,13 @@ internal sealed class Sidh { private readonly SikeEngine engine; - public Sidh(SikeEngine engine) + internal Sidh(SikeEngine engine) { this.engine = engine; } // Initialization of basis points - protected void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR) + internal void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR) { engine.fpx.fpcopy(gen, 0, XP[0]); engine.fpx.fpcopy(gen, engine.param.NWORDS_FIELD, XP[1]); @@ -23,7 +23,7 @@ internal sealed class Sidh // Bob's ephemeral public key generation // Input: a private key PrivateKeyB in the range [0, 2^Floor(Log(2,oB)) - 1]. // Output: the public key PublicKeyB consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes. - protected internal void EphemeralKeyGeneration_B(byte[] sk, byte[] pk) + internal void EphemeralKeyGeneration_B(byte[] sk, byte[] pk) { PointProj R = new PointProj(engine.param.NWORDS_FIELD), phiP = new PointProj(engine.param.NWORDS_FIELD), @@ -71,29 +71,29 @@ internal sealed class Sidh engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Bob[ii++]; - engine.isogeny.xTPLe(R, R, A24minus, A24plus, m); + engine.isogeny.XTplE(R, R, A24minus, A24plus, m); index += m; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_3_isog(pts[i], coeff); + engine.isogeny.Eval3Isog(pts[i], coeff); } - engine.isogeny.eval_3_isog(phiP, coeff); - engine.isogeny.eval_3_isog(phiQ, coeff); - engine.isogeny.eval_3_isog(phiR, coeff); + engine.isogeny.Eval3Isog(phiP, coeff); + engine.isogeny.Eval3Isog(phiQ, coeff); + engine.isogeny.Eval3Isog(phiR, coeff); engine.fpx.fp2copy(pts[npts - 1].X, R.X); engine.fpx.fp2copy(pts[npts - 1].Z, R.Z); index = pts_index[npts - 1]; npts -= 1; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); - engine.isogeny.eval_3_isog(phiP, coeff); - engine.isogeny.eval_3_isog(phiQ, coeff); - engine.isogeny.eval_3_isog(phiR, coeff); - engine.isogeny.inv_3_way(phiP.Z, phiQ.Z, phiR.Z); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); + engine.isogeny.Eval3Isog(phiP, coeff); + engine.isogeny.Eval3Isog(phiQ, coeff); + engine.isogeny.Eval3Isog(phiR, coeff); + engine.isogeny.Inv3Way(phiP.Z, phiQ.Z, phiR.Z); engine.fpx.fp2mul_mont(phiP.X, phiP.Z, phiP.X); engine.fpx.fp2mul_mont(phiQ.X, phiQ.Z, phiQ.X); @@ -108,7 +108,7 @@ internal sealed class Sidh // Alice's ephemeral public key generation // Input: a private key PrivateKeyA in the range [0, 2^eA - 1]. // Output: the public key PublicKeyA consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes. - protected internal void EphemeralKeyGeneration_A(byte[] ephemeralsk, byte[] ct) + internal void EphemeralKeyGeneration_A(byte[] ephemeralsk, byte[] ct) { PointProj R = new PointProj(engine.param.NWORDS_FIELD), phiP = new PointProj(engine.param.NWORDS_FIELD), @@ -149,12 +149,12 @@ internal sealed class Sidh if (engine.param.OALICE_BITS % 2 == 1) { PointProj S = new PointProj(engine.param.NWORDS_FIELD); - engine.isogeny.xDBLe(R, S, A24plus, C24, (engine.param.OALICE_BITS - 1)); - engine.isogeny.get_2_isog(S, A24plus, C24); - engine.isogeny.eval_2_isog(phiP, S); - engine.isogeny.eval_2_isog(phiQ, S); - engine.isogeny.eval_2_isog(phiR, S); - engine.isogeny.eval_2_isog(R, S); + engine.isogeny.XDblE(R, S, A24plus, C24, (engine.param.OALICE_BITS - 1)); + engine.isogeny.Get2Isog(S, A24plus, C24); + engine.isogeny.Eval2Isog(phiP, S); + engine.isogeny.Eval2Isog(phiQ, S); + engine.isogeny.Eval2Isog(phiR, S); + engine.isogeny.Eval2Isog(R, S); } // Traverse tree @@ -168,18 +168,18 @@ internal sealed class Sidh engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Alice[ii++]; - engine.isogeny.xDBLe(R, R, A24plus, C24, 2*m); + engine.isogeny.XDblE(R, R, A24plus, C24, 2*m); index += m; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_4_isog(pts[i], coeff); + engine.isogeny.Eval4Isog(pts[i], coeff); } - engine.isogeny.eval_4_isog(phiP, coeff); - engine.isogeny.eval_4_isog(phiQ, coeff); - engine.isogeny.eval_4_isog(phiR, coeff); + engine.isogeny.Eval4Isog(phiP, coeff); + engine.isogeny.Eval4Isog(phiQ, coeff); + engine.isogeny.Eval4Isog(phiR, coeff); engine.fpx.fp2copy(pts[npts-1].X, R.X); engine.fpx.fp2copy(pts[npts-1].Z, R.Z); @@ -187,12 +187,12 @@ internal sealed class Sidh npts -= 1; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); - engine.isogeny.eval_4_isog(phiP, coeff); - engine.isogeny.eval_4_isog(phiQ, coeff); - engine.isogeny.eval_4_isog(phiR, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); + engine.isogeny.Eval4Isog(phiP, coeff); + engine.isogeny.Eval4Isog(phiQ, coeff); + engine.isogeny.Eval4Isog(phiR, coeff); - engine.isogeny.inv_3_way(phiP.Z, phiQ.Z, phiR.Z); + engine.isogeny.Inv3Way(phiP.Z, phiQ.Z, phiR.Z); engine.fpx.fp2mul_mont(phiP.X, phiP.Z, phiP.X); engine.fpx.fp2mul_mont(phiQ.X, phiQ.Z, phiQ.X); engine.fpx.fp2mul_mont(phiR.X, phiR.Z, phiR.X); @@ -209,7 +209,7 @@ internal sealed class Sidh // Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1]. // Bob's PublicKeyB consists of 3 elements in GF(p^2) encoded by removing leading 0 bytes. // Output: a shared secret SharedSecretA that consists of one element in GF(p^2) encoded by removing leading 0 bytes. - protected internal void EphemeralSecretAgreement_A(byte[] ephemeralsk, byte[] pk, byte[] jinvariant) + internal void EphemeralSecretAgreement_A(byte[] ephemeralsk, byte[] pk, byte[] jinvariant) { PointProj R = new PointProj(engine.param.NWORDS_FIELD); PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_ALICE]; @@ -230,7 +230,7 @@ internal sealed class Sidh engine.fpx.fp2_decode(pk, PKB[2], 2*engine.param.FP2_ENCODED_BYTES); // Initialize constants: A24plus = A+2C, C24 = 4C, where C=1 - engine.isogeny.get_A(PKB[0], PKB[1], PKB[2], A); + engine.isogeny.GetA(PKB[0], PKB[1], PKB[2], A); engine.fpx.mp_add(engine.param.Montgomery_one, engine.param.Montgomery_one, C24[0], engine.param.NWORDS_FIELD); engine.fpx.mp2_add(A, C24, A24plus); engine.fpx.mp_add(C24[0], C24[0], C24[0], engine.param.NWORDS_FIELD); @@ -243,9 +243,9 @@ internal sealed class Sidh { PointProj S = new PointProj(engine.param.NWORDS_FIELD); - engine.isogeny.xDBLe(R, S, A24plus, C24, engine.param.OALICE_BITS - 1); - engine.isogeny.get_2_isog(S, A24plus, C24); - engine.isogeny.eval_2_isog(R, S); + engine.isogeny.XDblE(R, S, A24plus, C24, engine.param.OALICE_BITS - 1); + engine.isogeny.Get2Isog(S, A24plus, C24); + engine.isogeny.Eval2Isog(R, S); } // Traverse tree @@ -259,14 +259,14 @@ internal sealed class Sidh engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Alice[ii++]; - engine.isogeny.xDBLe(R, R, A24plus, C24, 2*m); + engine.isogeny.XDblE(R, R, A24plus, C24, 2*m); index += m; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_4_isog(pts[i], coeff); + engine.isogeny.Eval4Isog(pts[i], coeff); } engine.fpx.fp2copy(pts[npts-1].X, R.X); @@ -275,11 +275,11 @@ internal sealed class Sidh npts -= 1; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); engine.fpx.mp2_add(A24plus, A24plus, A24plus); engine.fpx.fp2sub(A24plus, C24, A24plus); engine.fpx.fp2add(A24plus, A24plus, A24plus); - engine.isogeny.j_inv(A24plus, C24, jinv); + engine.isogeny.JInv(A24plus, C24, jinv); engine.fpx.fp2_encode(jinv, jinvariant, 0); // Format shared secret } @@ -288,7 +288,7 @@ internal sealed class Sidh // Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1]. // Alice's PublicKeyA consists of 3 elements in GF(p^2) encoded by removing leading 0 bytes. // Output: a shared secret SharedSecretB that consists of one element in GF(p^2) encoded by removing leading 0 bytes. - protected internal void EphemeralSecretAgreement_B(byte[] sk, byte[] ct, byte[] jinvariant_) + internal void EphemeralSecretAgreement_B(byte[] sk, byte[] ct, byte[] jinvariant_) { PointProj R = new PointProj(engine.param.NWORDS_FIELD); PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_BOB]; @@ -309,7 +309,7 @@ internal sealed class Sidh engine.fpx.fp2_decode(ct, PKB[2], 2*engine.param.FP2_ENCODED_BYTES); // Initialize constants: A24plus = A+2C, A24minus = A-2C, where C=1 - engine.isogeny.get_A(PKB[0], PKB[1], PKB[2], A); + engine.isogeny.GetA(PKB[0], PKB[1], PKB[2], A); engine.fpx.mp_add(engine.param.Montgomery_one, engine.param.Montgomery_one, A24minus[0], engine.param.NWORDS_FIELD); engine.fpx.mp2_add(A, A24minus, A24plus); engine.fpx.mp2_sub_p2(A, A24minus, A24minus); @@ -329,13 +329,13 @@ internal sealed class Sidh engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Bob[ii++]; - engine.isogeny.xTPLe(R, R, A24minus, A24plus, m); + engine.isogeny.XTplE(R, R, A24minus, A24plus, m); index += m; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_3_isog(pts[i], coeff); + engine.isogeny.Eval3Isog(pts[i], coeff); } engine.fpx.fp2copy(pts[npts-1].X, R.X); @@ -344,14 +344,12 @@ internal sealed class Sidh npts -= 1; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); engine.fpx.fp2add(A24plus, A24minus, A); engine.fpx.fp2add(A, A, A); engine.fpx.fp2sub(A24plus, A24minus, A24plus); - engine.isogeny.j_inv(A, A24plus, jinv); + engine.isogeny.JInv(A, A24plus, jinv); engine.fpx.fp2_encode(jinv, jinvariant_, 0); // Format shared secret } - } - -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs b/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs index ca140aa50..cf69d0f82 100644 --- a/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs +++ b/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs @@ -9,12 +9,12 @@ internal sealed class SidhCompressed { private readonly SikeEngine engine; - public SidhCompressed(SikeEngine engine) + internal SidhCompressed(SikeEngine engine) { this.engine = engine; } - protected void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR) + internal void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR) { // Initialization of basis points engine.fpx.fpcopy(gen, 0, XP[0]); @@ -25,8 +25,7 @@ internal sealed class SidhCompressed engine.fpx.fpcopy(gen, 5*engine.param.NWORDS_FIELD, XR[1]); } - - protected internal void FormatPrivKey_B(byte[] skB) + internal void FormatPrivKey_B(byte[] skB) { skB[engine.param.SECRETKEY_B_BYTES-2] &= (byte)engine.param.MASK3_BOB; skB[engine.param.SECRETKEY_B_BYTES-1] &= (byte)engine.param.MASK2_BOB; // Clear necessary bits so that 3*ephemeralsk is still less than Bob_order @@ -35,7 +34,7 @@ internal sealed class SidhCompressed // Generation of Alice's secret key // Outputs random value in [0, 2^eA - 1] - protected void random_mod_order_A(byte[] random_digits, SecureRandom random) + internal void random_mod_order_A(byte[] random_digits, SecureRandom random) { byte[] temp = new byte[engine.param.SECRETKEY_A_BYTES]; random.NextBytes(temp); @@ -46,7 +45,7 @@ internal sealed class SidhCompressed // Generation of Bob's secret key // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] - protected void random_mod_order_B(byte[] random_digits, SecureRandom random) + internal void random_mod_order_B(byte[] random_digits, SecureRandom random) { byte[] temp = new byte[engine.param.SECRETKEY_B_BYTES]; random.NextBytes(temp); @@ -55,7 +54,7 @@ internal sealed class SidhCompressed } // Project 3-pouint ladder - protected void Ladder3pt_dual(PointProj[] Rs, ulong[] m, uint AliceOrBob, PointProj R, ulong[][] A24) + internal void Ladder3pt_dual(PointProj[] Rs, ulong[] m, uint AliceOrBob, PointProj R, ulong[][] A24) { PointProj R0 = new PointProj(engine.param.NWORDS_FIELD), R2 = new PointProj(engine.param.NWORDS_FIELD); @@ -85,18 +84,16 @@ internal sealed class SidhCompressed prevbit = bit; mask = 0 - (ulong)swap; - engine.isogeny.swap_points(R, R2, mask); - engine.isogeny.xDBLADD(R0, R2, R.X, A24); + engine.isogeny.SwapPoints(R, R2, mask); + engine.isogeny.XDblAdd(R0, R2, R.X, A24); engine.fpx.fp2mul_mont(R2.X, R.Z, R2.X); } swap = 0 ^ prevbit; mask = 0 - (ulong)swap; - engine.isogeny.swap_points(R, R2, mask); + engine.isogeny.SwapPoints(R, R2, mask); } - - - protected void Elligator2(ulong[][] a24, uint[] r, uint rIndex, ulong[][] x, byte[] bit, uint bitOffset, uint COMPorDEC) + internal void Elligator2(ulong[][] a24, uint[] r, uint rIndex, ulong[][] x, byte[] bit, uint bitOffset, uint COMPorDEC) { // Generate an x-coordinate of a pouint on curve with (affine) coefficient a24 // Use the counter r uint i; @@ -189,8 +186,7 @@ internal sealed class SidhCompressed // {System.out.printf("%016x ", x[di][dj] );}System.out.Println();} } - - protected void make_positive(ulong[][] x) + internal void make_positive(ulong[][] x) { uint nbytes = engine.param.NWORDS_FIELD; ulong[] zero = new ulong[engine.param.NWORDS_FIELD]; @@ -213,8 +209,7 @@ internal sealed class SidhCompressed engine.fpx.to_fp2mont(x, x); } - - protected void BiQuad_affine(ulong[][] a24, ulong[][] x0, ulong[][] x1, PointProj R) + internal void BiQuad_affine(ulong[][] a24, ulong[][] x0, ulong[][] x1, PointProj R) { ulong[][] Ap2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), aa = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -259,8 +254,7 @@ internal sealed class SidhCompressed engine.fpx.fp2add(aa, aa, R.Z); } - - protected void get_4_isog_dual(PointProj P, ulong[][] A24, ulong[][] C24, ulong[][][] coeff) + internal void get_4_isog_dual(PointProj P, ulong[][] A24, ulong[][] C24, ulong[][][] coeff) { engine.fpx.fp2sub(P.X, P.Z, coeff[1]); engine.fpx.fp2add(P.X, P.Z, coeff[2]); @@ -275,7 +269,7 @@ internal sealed class SidhCompressed // if (engine.param.OALICE_BITS % 2 == 1) - protected void eval_dual_2_isog(ulong[][] X2, ulong[][] Z2, PointProj P) + internal void eval_dual_2_isog(ulong[][] X2, ulong[][] Z2, PointProj P) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -288,7 +282,7 @@ internal sealed class SidhCompressed engine.fpx.fp2mul_mont(Z2, t0, P.X); } - protected void eval_final_dual_2_isog(PointProj P) + internal void eval_final_dual_2_isog(PointProj P) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -306,7 +300,7 @@ internal sealed class SidhCompressed } - protected void eval_dual_4_isog_shared(ulong[][] X4pZ4, ulong[][] X42, ulong[][] Z42, ulong[][][] coeff, uint coeffOffset) + internal void eval_dual_4_isog_shared(ulong[][] X4pZ4, ulong[][] X42, ulong[][] Z42, ulong[][][] coeff, uint coeffOffset) { // System.out.print("coeff0: "); // for (uint di = 0; di < 2; di++){ @@ -340,8 +334,7 @@ internal sealed class SidhCompressed // System.out.printf("%016x ", coeff[2 + coeffOffset][di][dj]);}System.out.Println();} } - - protected void eval_dual_4_isog(ulong[][] A24, ulong[][] C24, ulong[][][] coeff, uint coeffOffset, PointProj P) + internal void eval_dual_4_isog(ulong[][] A24, ulong[][] C24, ulong[][][] coeff, uint coeffOffset, PointProj P) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -365,8 +358,7 @@ internal sealed class SidhCompressed engine.fpx.fp2mul_mont(coeff[2 + coeffOffset], P.Z, P.Z); } - - protected void eval_full_dual_4_isog(ulong[][][][] As, PointProj P) + internal void eval_full_dual_4_isog(ulong[][][][] As, PointProj P) { //todo : check // First all 4-isogenies @@ -384,8 +376,7 @@ internal sealed class SidhCompressed eval_final_dual_2_isog(P); // to A = 0 } - - protected void TripleAndParabola_proj(PointProjFull R, ulong[][] l1x, ulong[][] l1z) + internal void TripleAndParabola_proj(PointProjFull R, ulong[][] l1x, ulong[][] l1z) { engine.fpx.fp2sqr_mont(R.X, l1z); engine.fpx.fp2add(l1z, l1z, l1x); @@ -394,8 +385,7 @@ internal sealed class SidhCompressed engine.fpx.fp2add(R.Y, R.Y, l1z); } - - protected void Tate3_proj(PointProjFull P, PointProjFull Q, ulong[][] gX, ulong[][] gZ) + internal void Tate3_proj(PointProjFull P, PointProjFull Q, ulong[][] gX, ulong[][] gZ) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), l1x = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -408,8 +398,7 @@ internal sealed class SidhCompressed engine.fpx.fp2add(gX, t0, gX); } - - protected void FinalExpo3(ulong[][] gX, ulong[][] gZ) + internal void FinalExpo3(ulong[][] gX, ulong[][] gZ) { uint i; @@ -432,8 +421,7 @@ internal sealed class SidhCompressed } } - - protected void FinalExpo3_2way(ulong[][][] gX, ulong[][][] gZ) + internal void FinalExpo3_2way(ulong[][][] gX, ulong[][][] gZ) { uint i, j; @@ -463,7 +451,6 @@ internal sealed class SidhCompressed } } - private bool FirstPoint_dual(PointProj P, PointProjFull R, byte[] ind) { PointProjFull R3 = new PointProjFull(engine.param.NWORDS_FIELD), @@ -580,7 +567,6 @@ internal sealed class SidhCompressed return true; } - private bool SecondPoint_dual(PointProj P, PointProjFull R, byte[] ind) { PointProjFull RS3 = new PointProjFull(engine.param.NWORDS_FIELD); @@ -612,8 +598,7 @@ internal sealed class SidhCompressed } } - - protected void FirstPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) + internal void FirstPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) { bool b = false; PointProj P = new PointProj(engine.param.NWORDS_FIELD); @@ -668,8 +653,7 @@ internal sealed class SidhCompressed } } - - protected void SecondPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) + internal void SecondPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) { bool b = false; PointProj P = new PointProj(engine.param.NWORDS_FIELD); @@ -724,8 +708,7 @@ internal sealed class SidhCompressed } } - - protected void makeDiff(PointProjFull R, PointProjFull S, PointProj D) + internal void makeDiff(PointProjFull R, PointProjFull S, PointProj D) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -749,8 +732,7 @@ internal sealed class SidhCompressed } } - - protected void BuildOrdinary3nBasis_dual(ulong[][] a24, ulong[][][][] As, PointProjFull[] R, uint[] r, uint[] bitsEll, uint bitsEllOffset) + internal void BuildOrdinary3nBasis_dual(ulong[][] a24, ulong[][][][] As, PointProjFull[] R, uint[] r, uint[] bitsEll, uint bitsEllOffset) { PointProj D = new PointProj(engine.param.NWORDS_FIELD); @@ -809,8 +791,7 @@ internal sealed class SidhCompressed makeDiff(R[0], R[1], D); } - - protected void FullIsogeny_A_dual(byte[] PrivateKeyA, ulong[][][][] As, ulong[][] a24, uint sike) + internal void FullIsogeny_A_dual(byte[] PrivateKeyA, ulong[][][][] As, ulong[][] a24, uint sike) { // Input: a private key PrivateKeyA in the range [0, 2^eA - 1]. // Output: the public key PublicKeyA consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes. @@ -925,9 +906,9 @@ internal sealed class SidhCompressed { PointProj S = new PointProj(engine.param.NWORDS_FIELD); - engine.isogeny.xDBLe(R, S, A24, C24, engine.param.OALICE_BITS - 1); - engine.isogeny.get_2_isog(S, A24, C24); - engine.isogeny.eval_2_isog(R, S); + engine.isogeny.XDblE(R, S, A24, C24, engine.param.OALICE_BITS - 1); + engine.isogeny.Get2Isog(S, A24, C24); + engine.isogeny.Eval2Isog(R, S); engine.fpx.fp2copy(S.X, As[engine.param.MAX_Alice][2]); engine.fpx.fp2copy(S.Z, As[engine.param.MAX_Alice][3]); } @@ -945,7 +926,7 @@ internal sealed class SidhCompressed engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Alice[ii++]; - engine.isogeny.xDBLe(R, R, A24, C24, 2*m); + engine.isogeny.XDblE(R, R, A24, C24, 2*m); index += m; } @@ -976,7 +957,7 @@ internal sealed class SidhCompressed get_4_isog_dual(R, A24, C24, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_4_isog(pts[i], coeff); + engine.isogeny.Eval4Isog(pts[i], coeff); // System.out.print(i + "ptsX: "); // for (uint di = 0; di < 2; di++){ @@ -1043,8 +1024,7 @@ internal sealed class SidhCompressed // System.out.printf("%016x ", a24[di][dj]);}System.out.Println();} } - - protected void Dlogs3_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) + internal void Dlogs3_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) { solve_dlog(f[0], D, d0, 3); solve_dlog(f[2], D, c0, 3); @@ -1054,8 +1034,7 @@ internal sealed class SidhCompressed engine.fpx.mp_sub(engine.param.Bob_order, c1, c1, engine.param.NWORDS_ORDER); } - - protected void BuildOrdinary3nBasis_Decomp_dual(ulong[][] A24, PointProj[] Rs, uint[] r, uint[] bitsEll, uint bitsEllIndex) + internal void BuildOrdinary3nBasis_Decomp_dual(ulong[][] A24, PointProj[] Rs, uint[] r, uint[] bitsEll, uint bitsEllIndex) { byte[] bitEll = new byte[2]; @@ -1071,8 +1050,7 @@ internal sealed class SidhCompressed BiQuad_affine(A24, Rs[0].X, Rs[1].X, Rs[2]); } - - protected void PKADecompression_dual(byte[] SecretKeyB, byte[] CompressedPKA, PointProj R, ulong[][] A) + internal void PKADecompression_dual(byte[] SecretKeyB, byte[] CompressedPKA, PointProj R, ulong[][] A) { byte bit; uint[] rs = new uint[3]; @@ -1120,7 +1098,7 @@ internal sealed class SidhCompressed engine.fpx.fpcopy(engine.param.Montgomery_one, 0, Rs[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, Rs[1].Z[0]); - engine.isogeny.swap_points(Rs[0], Rs[1], ((ulong) -bit));//todo check + engine.isogeny.SwapPoints(Rs[0], Rs[1], ((ulong) -bit));//todo check engine.fpx.decode_to_digits(SecretKeyB, 0, SKin, engine.param.SECRETKEY_B_BYTES, engine.param.NWORDS_ORDER); engine.fpx.to_Montgomery_mod_order(SKin, t1, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); // Converting to Montgomery representation engine.fpx.decode_to_digits(CompressedPKA, 0, temp, engine.param.ORDER_B_ENCODED_BYTES, engine.param.NWORDS_ORDER); @@ -1155,8 +1133,7 @@ internal sealed class SidhCompressed engine.isogeny.Double(R, R, A24, engine.param.OALICE_BITS); // x, z := Double(A24, x, 1, eA); } - - protected void Compress_PKA_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] a24, uint[] rs, byte[] CompressedPKA) + internal void Compress_PKA_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] a24, uint[] rs, byte[] CompressedPKA) { uint bit; ulong[] temp = new ulong[engine.param.NWORDS_ORDER], @@ -1231,7 +1208,7 @@ internal sealed class SidhCompressed // Alice's ephemeral public key generation using compression -- SIKE protocol // Output: PrivateKeyA[MSG_BYTES + engine.param.SECRETKEY_A_BYTES] <- x(K_A) where K_A = PA + sk_A*Q_A - protected internal uint EphemeralKeyGeneration_A_extended(byte[] PrivateKeyA, byte[] CompressedPKA) + internal uint EphemeralKeyGeneration_A_extended(byte[] PrivateKeyA, byte[] CompressedPKA) { uint[] rs = new uint[3]; int[] D = new int[engine.param.DLEN_3]; @@ -1363,14 +1340,14 @@ internal sealed class SidhCompressed engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Bob[ii++]; - engine.isogeny.xTPLe(R, R, A24minus, A24plus, m); + engine.isogeny.XTplE(R, R, A24minus, A24plus, m); index += m; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_3_isog(pts[i], coeff); + engine.isogeny.Eval3Isog(pts[i], coeff); } engine.fpx.fp2copy(pts[npts-1].X, R.X); @@ -1379,18 +1356,17 @@ internal sealed class SidhCompressed npts -= 1; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); engine.fpx.fp2add(A24plus, A24minus, A); engine.fpx.fp2add(A, A, A); engine.fpx.fp2sub(A24plus, A24minus, A24plus); - engine.isogeny.j_inv(A, A24plus, jinv); + engine.isogeny.JInv(A, A24plus, jinv); engine.fpx.fp2_encode(jinv, SharedSecretB, 0); // Format shared secret return 0; } - - protected void BuildEntangledXonly(ulong[][] A, PointProj[] R, byte[] qnr, byte[] ind) + internal void BuildEntangledXonly(ulong[][] A, PointProj[] R, byte[] qnr, byte[] ind) { ulong[] s = new ulong[engine.param.NWORDS_FIELD]; ulong[][] t_ptr, @@ -1456,8 +1432,7 @@ internal sealed class SidhCompressed engine.fpx.fp2mul_mont(t, r, R[2].X); } - - protected void RecoverY(ulong[][] A, PointProj[] xs, PointProjFull[] Rs) + internal void RecoverY(ulong[][] A, PointProj[] xs, PointProjFull[] Rs) { ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -1497,8 +1472,7 @@ internal sealed class SidhCompressed engine.fpx.fp2mul_mont(Rs[1].Y, Rs[1].Z, Rs[1].Y); } - - protected void BuildOrdinary2nBasis_dual(ulong[][] A, ulong[][][][] Ds, PointProjFull[] Rs, byte[] qnr, byte[] ind) + internal void BuildOrdinary2nBasis_dual(ulong[][] A, ulong[][][][] Ds, PointProjFull[] Rs, byte[] qnr, byte[] ind) { uint i; ulong[] t0 = new ulong[engine.param.NWORDS_FIELD]; @@ -1545,9 +1519,9 @@ internal sealed class SidhCompressed // Move them back to A = 6 for(i = 0; i < engine.param.MAX_Bob; i++) { - engine.isogeny.eval_3_isog(xs[0], Ds[engine.param.MAX_Bob-1-i]); - engine.isogeny.eval_3_isog(xs[1], Ds[engine.param.MAX_Bob-1-i]); - engine.isogeny.eval_3_isog(xs[2], Ds[engine.param.MAX_Bob-1-i]); + engine.isogeny.Eval3Isog(xs[0], Ds[engine.param.MAX_Bob-1-i]); + engine.isogeny.Eval3Isog(xs[1], Ds[engine.param.MAX_Bob-1-i]); + engine.isogeny.Eval3Isog(xs[2], Ds[engine.param.MAX_Bob-1-i]); } // Recover y-coordinates with a single sqrt on A = 6 @@ -1563,7 +1537,7 @@ internal sealed class SidhCompressed // Bob's ephemeral public key generation // Input: a private key PrivateKeyB in the range [0, 2^Floor(Log(2,oB)) - 1]. // Output: the public key PublicKeyB consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes. - protected void FullIsogeny_B_dual(byte[] PrivateKeyB, ulong[][][][] Ds, ulong[][] A) + internal void FullIsogeny_B_dual(byte[] PrivateKeyB, ulong[][][][] Ds, ulong[][] A) { PointProj R = new PointProj(engine.param.NWORDS_FIELD), Q3 = new PointProj(engine.param.NWORDS_FIELD); @@ -1621,15 +1595,15 @@ internal sealed class SidhCompressed engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Bob[ii++]; - engine.isogeny.xTPLe(R, R, A24minus, A24plus, m); + engine.isogeny.XTplE(R, R, A24minus, A24plus, m); index += m; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_3_isog(pts[i], coeff); + engine.isogeny.Eval3Isog(pts[i], coeff); } - engine.isogeny.eval_3_isog(Q3, coeff); // Kernel of dual + engine.isogeny.Eval3Isog(Q3, coeff); // Kernel of dual engine.fpx.fp2sub(Q3.X,Q3.Z,Ds[row-1][0]); engine.fpx.fp2add(Q3.X,Q3.Z,Ds[row-1][1]); @@ -1638,8 +1612,8 @@ internal sealed class SidhCompressed index = pts_index[npts-1]; npts -= 1; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); - engine.isogeny.eval_3_isog(Q3, coeff); // Kernel of dual + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); + engine.isogeny.Eval3Isog(Q3, coeff); // Kernel of dual engine.fpx.fp2sub(Q3.X, Q3.Z, Ds[engine.param.MAX_Bob-1][0]); engine.fpx.fp2add(Q3.X, Q3.Z, Ds[engine.param.MAX_Bob-1][1]); @@ -1650,8 +1624,7 @@ internal sealed class SidhCompressed engine.fpx.fp2add(A, A, A); // A = 2*(A24plus+A24mins)/(A24plus-A24minus) } - - protected void Dlogs2_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) + internal void Dlogs2_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) { solve_dlog(f[0], D, d0, 2); solve_dlog(f[2], D, c0, 2); @@ -1661,8 +1634,7 @@ internal sealed class SidhCompressed engine.fpx.mp_sub(engine.param.Alice_order, c1, c1, engine.param.NWORDS_ORDER); } - - protected void BuildEntangledXonly_Decomp(ulong[][] A, PointProj[] R, uint qnr, uint ind) + internal void BuildEntangledXonly_Decomp(ulong[][] A, PointProj[] R, uint qnr, uint ind) { ulong[][] t_ptr, r = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -1714,7 +1686,7 @@ internal sealed class SidhCompressed } // Bob's PK decompression -- SIKE protocol - protected void PKBDecompression_extended(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A, byte[] tphiBKA_t, uint tphiBKA_tOffset) + internal void PKBDecompression_extended(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A, byte[] tphiBKA_t, uint tphiBKA_tOffset) { ulong mask = unchecked((ulong) -1L); uint qnr, ind; @@ -1807,12 +1779,12 @@ internal sealed class SidhCompressed engine.fpx.inv_mod_orderA(tmp2, inv); engine.fpx.multiply(inv, tmp1, scal, engine.param.NWORDS_ORDER); scal[engine.param.NWORDS_ORDER-1] &= (ulong)mask; - engine.isogeny.swap_points(Rs[0], Rs[1], unchecked((ulong)-1L));//check + engine.isogeny.SwapPoints(Rs[0], Rs[1], unchecked((ulong)-1L));//check Ladder3pt_dual(Rs, scal, engine.param.ALICE, R, A24); } engine.fpx.fp2div2(A,Adiv2); - engine.isogeny.xTPLe_fast(R, R, Adiv2, engine.param.OBOB_EXPON); + engine.isogeny.XTplEFast(R, R, Adiv2, engine.param.OBOB_EXPON); engine.fpx.fp2_encode(R.X, tphiBKA_t, tphiBKA_tOffset); engine.fpx.fp2_encode(R.Z, tphiBKA_t, tphiBKA_tOffset + engine.param.FP2_ENCODED_BYTES); @@ -1820,7 +1792,7 @@ internal sealed class SidhCompressed } // Bob's PK compression -- SIKE protocol - protected void Compress_PKB_dual_extended(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) + internal void Compress_PKB_dual_extended(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) { ulong mask = unchecked((ulong) -1L); ulong[] tmp = new ulong[2*engine.param.NWORDS_ORDER], @@ -1876,7 +1848,7 @@ internal sealed class SidhCompressed } // Bob's PK decompression -- SIDH protocol - protected void PKBDecompression(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A) + internal void PKBDecompression(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A) { ulong mask = unchecked((ulong) -1L); uint bit,qnr,ind; @@ -1909,7 +1881,7 @@ internal sealed class SidhCompressed engine.fpx.fp2div2(A24, A24); engine.fpx.decode_to_digits(SecretKeyA, SecretKeyAOffset, SKin, engine.param.SECRETKEY_A_BYTES, engine.param.NWORDS_ORDER); - engine.isogeny.swap_points(Rs[0], Rs[1], 0-(ulong)bit); + engine.isogeny.SwapPoints(Rs[0], Rs[1], 0-(ulong)bit); if (bit == 0) { engine.fpx.decode_to_digits(CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, comp_temp, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); @@ -1941,11 +1913,11 @@ internal sealed class SidhCompressed Ladder3pt_dual(Rs, vone, engine.param.ALICE, R, A24); } engine.fpx.fp2div2(A, A24); - engine.isogeny.xTPLe_fast(R, R, A24, engine.param.OBOB_EXPON); + engine.isogeny.XTplEFast(R, R, A24, engine.param.OBOB_EXPON); } // Bob's PK compression -- SIDH protocol - protected void Compress_PKB_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) + internal void Compress_PKB_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) { ulong[] tmp = new ulong[2*engine.param.NWORDS_ORDER], @@ -1990,7 +1962,7 @@ internal sealed class SidhCompressed } // Bob's ephemeral public key generation using compression -- SIKE protocol - protected internal uint EphemeralKeyGeneration_B_extended(byte[] PrivateKeyB, byte[] CompressedPKB, uint sike) + internal uint EphemeralKeyGeneration_B_extended(byte[] PrivateKeyB, byte[] CompressedPKB, uint sike) { byte[] qnr = new byte[1], ind = new byte[1]; int[] D = new int[engine.param.DLEN_2]; @@ -2114,13 +2086,13 @@ internal sealed class SidhCompressed } // Bob's ephemeral public key generation using compression -- SIDH protocol - protected uint EphemeralKeyGeneration_B(byte[] PrivateKeyB, byte[] CompressedPKB) + internal uint EphemeralKeyGeneration_B(byte[] PrivateKeyB, byte[] CompressedPKB) { return EphemeralKeyGeneration_B_extended(PrivateKeyB, CompressedPKB, 0); } // Alice's ephemeral shared secret computation using compression -- SIKE protocol - protected internal uint EphemeralSecretAgreement_A_extended(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA, uint sike) + internal uint EphemeralSecretAgreement_A_extended(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA, uint sike) { uint i, ii = 0, row, m, index = 0, npts = 0; uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_ALICE]; @@ -2153,9 +2125,9 @@ internal sealed class SidhCompressed { PointProj S = new PointProj(engine.param.NWORDS_FIELD); - engine.isogeny.xDBLe(R, S, A24plus, C24, (engine.param.OALICE_BITS - 1)); - engine.isogeny.get_2_isog(S, A24plus, C24); - engine.isogeny.eval_2_isog(R, S); + engine.isogeny.XDblE(R, S, A24plus, C24, (engine.param.OALICE_BITS - 1)); + engine.isogeny.Get2Isog(S, A24plus, C24); + engine.isogeny.Eval2Isog(R, S); } // Traverse tree @@ -2169,14 +2141,14 @@ internal sealed class SidhCompressed engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Alice[ii++]; - engine.isogeny.xDBLe(R, R, A24plus, C24, 2*m); + engine.isogeny.XDblE(R, R, A24plus, C24, 2*m); index += m; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_4_isog(pts[i], coeff); + engine.isogeny.Eval4Isog(pts[i], coeff); } engine.fpx.fp2copy(pts[npts-1].X, R.X); @@ -2185,11 +2157,11 @@ internal sealed class SidhCompressed npts -= 1; } - engine.isogeny.get_4_isog(R, A24plus, C24, coeff); + engine.isogeny.Get4Isog(R, A24plus, C24, coeff); engine.fpx.fp2add(A24plus, A24plus, A24plus); engine.fpx.fp2sub(A24plus, C24, A24plus); engine.fpx.fp2add(A24plus, A24plus, A24plus); - engine.isogeny.j_inv(A24plus, C24, jinv); + engine.isogeny.JInv(A24plus, C24, jinv); engine.fpx.fp2_encode(jinv, SharedSecretA, 0); // Format shared secret return 0; @@ -2200,13 +2172,12 @@ internal sealed class SidhCompressed // Inputs: Alice's PrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^engine.param.OALICE_BITS. // Bob's decompressed data consists of point_R in (X:Z) coordinates and the curve parameter param_A in GF(p^2). // Output: a shared secret SharedSecretA that consists of one element in GF(p^2). - uint EphemeralSecretAgreement_A(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA) + private uint EphemeralSecretAgreement_A(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA) { return EphemeralSecretAgreement_A_extended(PrivateKeyA, PrivateKeyAOffset, PKB, SharedSecretA, 0); } - - protected internal byte validate_ciphertext(byte[] ephemeralsk_, byte[] CompressedPKB, byte[] xKA, uint xKAOffset, byte[] tphiBKA_t, uint tphiBKA_tOffset) + internal byte validate_ciphertext(byte[] ephemeralsk_, byte[] CompressedPKB, byte[] xKA, uint xKAOffset, byte[] tphiBKA_t, uint tphiBKA_tOffset) { // If ct validation passes returns 0, otherwise returns -1. PointProj[] phis = new PointProj[3], pts = new PointProj[engine.param.MAX_INT_POINTS_BOB]; @@ -2264,23 +2235,23 @@ internal sealed class SidhCompressed engine.fpx.fp2copy(R.Z, pts[npts].Z); pts_index[npts++] = index; m = engine.param.strat_Bob[ii++]; - engine.isogeny.xTPLe(R, R, A24minus, A24plus, m); + engine.isogeny.XTplE(R, R, A24minus, A24plus, m); index += m; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); for (i = 0; i < npts; i++) { - engine.isogeny.eval_3_isog(pts[i], coeff); + engine.isogeny.Eval3Isog(pts[i], coeff); } - engine.isogeny.eval_3_isog(phis[0], coeff); + engine.isogeny.Eval3Isog(phis[0], coeff); engine.fpx.fp2copy(pts[npts-1].X, R.X); engine.fpx.fp2copy(pts[npts-1].Z, R.Z); index = pts_index[npts-1]; npts -= 1; } - engine.isogeny.get_3_isog(R, A24minus, A24plus, coeff); - engine.isogeny.eval_3_isog(phis[0], coeff); // phis[0] <- phiB(PA + skA*QA) + engine.isogeny.Get3Isog(R, A24minus, A24plus, coeff); + engine.isogeny.Eval3Isog(phis[0], coeff); // phis[0] <- phiB(PA + skA*QA) engine.fpx.fp2_decode(CompressedPKB, A, 4*engine.param.ORDER_A_ENCODED_BYTES); @@ -2296,13 +2267,11 @@ internal sealed class SidhCompressed return (engine.fpx.cmp_f2elm(comp1, comp2)); } - - /// DLOG // Computes the discrete log of input r = g^d where g = e(P,Q)^ell^e, and P,Q are torsion generators in the initial curve // Return the integer d - void solve_dlog(ulong[][] r, int[] D, ulong[] d, uint ell) + internal void solve_dlog(ulong[][] r, int[] D, ulong[] d, uint ell) { if (ell == 2) { @@ -2449,12 +2418,10 @@ internal sealed class SidhCompressed } } - - // Traverse a Pohlig-Hellman optimal strategy to solve a discrete log in a group of order ell^e // Leaves are used to recover the digits which are numbers from 0 to ell^w-1 except by the last leaf that gives a digit between 0 and ell^(e mod w) // Assume w does not divide the exponent e - void Traverse_w_notdiv_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT1, ulong[] CT2, + internal void Traverse_w_notdiv_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT1, ulong[] CT2, int[] D, uint Dlen, uint ell, uint ellw, uint ell_emodw, uint w, uint e) { ulong[][] rp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), @@ -2628,12 +2595,10 @@ internal sealed class SidhCompressed } } - - // Traverse a Pohlig-Hellman optimal strategy to solve a discrete log in a group of order ell^e // The leaves of the tree will be used to recover the signed digits which are numbers from +/-{0,1... Ceil((ell^w-1)/2)} // Assume the integer w divides the exponent e - void Traverse_w_div_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT, int[] D, uint Dlen, uint ellw, uint w) + internal void Traverse_w_div_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT, int[] D, uint Dlen, uint ellw, uint w) { ulong[][] rp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD), alpha = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); @@ -3158,9 +3123,5 @@ internal sealed class SidhCompressed } engine.fpx.fp2copy(temp, fout); } - - - } - -} \ No newline at end of file +} diff --git a/crypto/src/pqc/crypto/sike/SIKEEngine.cs b/crypto/src/pqc/crypto/sike/SIKEEngine.cs index 6a825fe44..12f468340 100644 --- a/crypto/src/pqc/crypto/sike/SIKEEngine.cs +++ b/crypto/src/pqc/crypto/sike/SIKEEngine.cs @@ -4,43 +4,42 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Pqc.Crypto.Sike { -internal sealed class SikeEngine -{ - //private readonly SecureRandom random; - - protected internal Internal param; - protected internal Isogeny isogeny; - protected internal Fpx fpx; - private Sidh sidh; - private SidhCompressed sidhCompressed; - private bool isCompressed; - - public uint GetDefaultSessionKeySize() + internal sealed class SikeEngine { - return param.MSG_BYTES * 8; - } + internal Internal param; + internal Isogeny isogeny; + internal Fpx fpx; + private Sidh sidh; + private SidhCompressed sidhCompressed; + private bool isCompressed; + + internal uint GetDefaultSessionKeySize() + { + return param.MSG_BYTES * 8; + } - public int GetCipherTextSize() - { - return param.CRYPTO_CIPHERTEXTBYTES; - } + internal int GetCipherTextSize() + { + return param.CRYPTO_CIPHERTEXTBYTES; + } - public uint GetPrivateKeySize() - { - return param.CRYPTO_SECRETKEYBYTES; - } + internal uint GetPrivateKeySize() + { + return param.CRYPTO_SECRETKEYBYTES; + } - public uint GetPublicKeySize() - { - return param.CRYPTO_PUBLICKEYBYTES; - } - public SikeEngine(int ver, bool isCompressed, SecureRandom random) - { - //this.random = random; - this.isCompressed = isCompressed; - //todo switch for different parameters - switch(ver) + internal uint GetPublicKeySize() { + return param.CRYPTO_PUBLICKEYBYTES; + } + + internal SikeEngine(int ver, bool isCompressed, SecureRandom random) + { + //this.random = random; + this.isCompressed = isCompressed; + //todo switch for different parameters + switch(ver) + { case 434: param = new P434(isCompressed); break; @@ -55,239 +54,236 @@ internal sealed class SikeEngine break; default: break; - + } + fpx = new Fpx(this); + isogeny = new Isogeny(this); + if(isCompressed) + { + sidhCompressed = new SidhCompressed(this); + } + sidh = new Sidh(this); } - fpx = new Fpx(this); - isogeny = new Isogeny(this); - if(isCompressed) + + // SIKE's key generation + // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) + // public key pk (CRYPTO_PUBLICKEYBYTES bytes) + internal int crypto_kem_keypair(byte[] pk, byte[] sk, SecureRandom random) { - sidhCompressed = new SidhCompressed(this); - } - sidh = new Sidh(this); - } + random.NextBytes(sk, 0, (int)param.MSG_BYTES); - // SIKE's key generation - // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) - // public key pk (CRYPTO_PUBLICKEYBYTES bytes) - public int crypto_kem_keypair(byte[] pk, byte[] sk, SecureRandom random) - { - random.NextBytes(sk, 0, (int)param.MSG_BYTES); + if (isCompressed) + { + // Generation of Alice's secret key + // Outputs random value in [0, 2^eA - 1] - if (isCompressed) - { - // Generation of Alice's secret key - // Outputs random value in [0, 2^eA - 1] + random.NextBytes(sk, (int)param.MSG_BYTES, (int)param.SECRETKEY_A_BYTES); + sk[param.MSG_BYTES] &= 0xFE; // Make private scalar even + sk[param.MSG_BYTES + param.SECRETKEY_A_BYTES - 1] &= (byte)param.MASK_ALICE; // Masking last - random.NextBytes(sk, (int)param.MSG_BYTES, (int)param.SECRETKEY_A_BYTES); - sk[param.MSG_BYTES] &= 0xFE; // Make private scalar even - sk[param.MSG_BYTES + param.SECRETKEY_A_BYTES - 1] &= (byte)param.MASK_ALICE; // Masking last + sidhCompressed.EphemeralKeyGeneration_A_extended(sk, pk); - sidhCompressed.EphemeralKeyGeneration_A_extended(sk, pk); + // Append public key pk to secret key sk + System.Array.Copy(pk, 0, sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES, param.CRYPTO_PUBLICKEYBYTES); + } + else + { + // Generation of Bob's secret key + // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] + // todo/org: SIDH.random_mod_order_B(sk, random); - // Append public key pk to secret key sk - System.Array.Copy(pk, 0, sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES, param.CRYPTO_PUBLICKEYBYTES); - } - else - { - // Generation of Bob's secret key - // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] - // todo/org: SIDH.random_mod_order_B(sk, random); + random.NextBytes(sk, (int)param.MSG_BYTES, (int)param.SECRETKEY_B_BYTES); + sk[param.MSG_BYTES + param.SECRETKEY_B_BYTES - 1] &= (byte)param.MASK_BOB; - random.NextBytes(sk, (int)param.MSG_BYTES, (int)param.SECRETKEY_B_BYTES); - sk[param.MSG_BYTES + param.SECRETKEY_B_BYTES - 1] &= (byte)param.MASK_BOB; + sidh.EphemeralKeyGeneration_B(sk, pk); - sidh.EphemeralKeyGeneration_B(sk, pk); + // Append public key pk to secret key sk + System.Array.Copy(pk, 0, sk, param.MSG_BYTES + param.SECRETKEY_B_BYTES, param.CRYPTO_PUBLICKEYBYTES); - // Append public key pk to secret key sk - System.Array.Copy(pk, 0, sk, param.MSG_BYTES + param.SECRETKEY_B_BYTES, param.CRYPTO_PUBLICKEYBYTES); + } + return 0; } - return 0; - } - - // SIKE's encapsulation - // Input: public key pk (CRYPTO_PUBLICKEYBYTES bytes) - // Outputs: shared secret ss (CRYPTO_BYTES bytes) - // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes) - public int crypto_kem_enc(byte[] ct, byte[] ss, byte[] pk, SecureRandom random) - { - if(isCompressed) + // SIKE's encapsulation + // Input: public key pk (CRYPTO_PUBLICKEYBYTES bytes) + // Outputs: shared secret ss (CRYPTO_BYTES bytes) + // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes) + internal int crypto_kem_enc(byte[] ct, byte[] ss, byte[] pk, SecureRandom random) { - byte[] ephemeralsk = new byte[param.SECRETKEY_B_BYTES]; - byte[] jinvariant = new byte[param.FP2_ENCODED_BYTES]; - byte[] h = new byte[param.MSG_BYTES]; - byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; + if(isCompressed) + { + byte[] ephemeralsk = new byte[param.SECRETKEY_B_BYTES]; + byte[] jinvariant = new byte[param.FP2_ENCODED_BYTES]; + byte[] h = new byte[param.MSG_BYTES]; + byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; - // Generate ephemeralsk <- G(m||pk) mod oB - random.NextBytes(temp, 0, (int)param.MSG_BYTES); - System.Array.Copy(pk, 0, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); + // Generate ephemeralsk <- G(m||pk) mod oB + random.NextBytes(temp, 0, (int)param.MSG_BYTES); + System.Array.Copy(pk, 0, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); - IXof digest = new ShakeDigest(256); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); - digest.OutputFinal(ephemeralsk, 0, (int) param.SECRETKEY_B_BYTES); + IXof digest = new ShakeDigest(256); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); + digest.OutputFinal(ephemeralsk, 0, (int) param.SECRETKEY_B_BYTES); - sidhCompressed.FormatPrivKey_B(ephemeralsk); + sidhCompressed.FormatPrivKey_B(ephemeralsk); -// System.out.println("ephemeralsk: " + Hex.toHexstring(ephemeralsk)); + // System.out.println("ephemeralsk: " + Hex.toHexstring(ephemeralsk)); - // Encrypt - sidhCompressed.EphemeralKeyGeneration_B_extended(ephemeralsk, ct, 1); + // Encrypt + sidhCompressed.EphemeralKeyGeneration_B_extended(ephemeralsk, ct, 1); -// System.out.println("ct: " + Hex.toHexstring(ct)); -// System.out.println("pk: " + Hex.toHexstring(pk)); + // System.out.println("ct: " + Hex.toHexstring(ct)); + // System.out.println("pk: " + Hex.toHexstring(pk)); - sidhCompressed.EphemeralSecretAgreement_B(ephemeralsk, pk, jinvariant); + sidhCompressed.EphemeralSecretAgreement_B(ephemeralsk, pk, jinvariant); -// System.out.println("jinv: " + Hex.toHexstring(jinvariant)); + // System.out.println("jinv: " + Hex.toHexstring(jinvariant)); - digest.BlockUpdate(jinvariant, 0, (int) param.FP2_ENCODED_BYTES); - digest.OutputFinal(h, 0, (int) param.MSG_BYTES); + digest.BlockUpdate(jinvariant, 0, (int) param.FP2_ENCODED_BYTES); + digest.OutputFinal(h, 0, (int) param.MSG_BYTES); -// System.out.println("h: " + Hex.toHexstring(h)); -// System.out.println("temp: " + Hex.toHexstring(temp)); + // System.out.println("h: " + Hex.toHexstring(h)); + // System.out.println("temp: " + Hex.toHexstring(temp)); - for (int i = 0; i < param.MSG_BYTES; i++) - { - ct[i + param.PARTIALLY_COMPRESSED_CHUNK_CT] = (byte) (temp[i] ^ h[i]); - } + for (int i = 0; i < param.MSG_BYTES; i++) + { + ct[i + param.PARTIALLY_COMPRESSED_CHUNK_CT] = (byte) (temp[i] ^ h[i]); + } - // Generate shared secret ss <- H(m||ct) - System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); + // Generate shared secret ss <- H(m||ct) + System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); - digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); - return 0; - } - else - { - byte[] ephemeralsk = new byte[param.SECRETKEY_A_BYTES]; - byte[] jinvariant = new byte[param.FP2_ENCODED_BYTES]; - byte[] h = new byte[param.MSG_BYTES]; - byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); + digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); + return 0; + } + else + { + byte[] ephemeralsk = new byte[param.SECRETKEY_A_BYTES]; + byte[] jinvariant = new byte[param.FP2_ENCODED_BYTES]; + byte[] h = new byte[param.MSG_BYTES]; + byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; - // Generate ephemeralsk <- G(m||pk) mod oA - random.NextBytes(temp, 0, (int)param.MSG_BYTES); - System.Array.Copy(pk, 0, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); + // Generate ephemeralsk <- G(m||pk) mod oA + random.NextBytes(temp, 0, (int)param.MSG_BYTES); + System.Array.Copy(pk, 0, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); - IXof digest = new ShakeDigest(256); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); - digest.OutputFinal(ephemeralsk, 0, (int) param.SECRETKEY_A_BYTES); - ephemeralsk[param.SECRETKEY_A_BYTES - 1] &= (byte) param.MASK_ALICE; + IXof digest = new ShakeDigest(256); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); + digest.OutputFinal(ephemeralsk, 0, (int) param.SECRETKEY_A_BYTES); + ephemeralsk[param.SECRETKEY_A_BYTES - 1] &= (byte) param.MASK_ALICE; - // Encrypt - sidh.EphemeralKeyGeneration_A(ephemeralsk, ct); - sidh.EphemeralSecretAgreement_A(ephemeralsk, pk, jinvariant); + // Encrypt + sidh.EphemeralKeyGeneration_A(ephemeralsk, ct); + sidh.EphemeralSecretAgreement_A(ephemeralsk, pk, jinvariant); - digest.BlockUpdate(jinvariant, 0, (int) param.FP2_ENCODED_BYTES); - digest.OutputFinal(h, 0, (int) param.MSG_BYTES); + digest.BlockUpdate(jinvariant, 0, (int) param.FP2_ENCODED_BYTES); + digest.OutputFinal(h, 0, (int) param.MSG_BYTES); - for (int i = 0; i < param.MSG_BYTES; i++) - { - ct[i + param.CRYPTO_PUBLICKEYBYTES] = (byte) (temp[i] ^ h[i]); - } + for (int i = 0; i < param.MSG_BYTES; i++) + { + ct[i + param.CRYPTO_PUBLICKEYBYTES] = (byte) (temp[i] ^ h[i]); + } - // Generate shared secret ss <- H(m||ct) - System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); + // Generate shared secret ss <- H(m||ct) + System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); - digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); + digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); - return 0; + return 0; + } } - } - // SIKE's decapsulation - // Input: secret key sk (CRYPTO_SECRETKEYBYTES = MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) - // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes) - // Outputs: shared secret ss (CRYPTO_BYTES bytes) - public int crypto_kem_dec(byte[] ss, byte[] ct, byte[] sk) - { - if (isCompressed) + // SIKE's decapsulation + // Input: secret key sk (CRYPTO_SECRETKEYBYTES = MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) + // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes) + // Outputs: shared secret ss (CRYPTO_BYTES bytes) + internal int crypto_kem_dec(byte[] ss, byte[] ct, byte[] sk) { - byte[] ephemeralsk_ = new byte[param.SECRETKEY_B_BYTES]; - byte[] jinvariant_ = new byte[param.FP2_ENCODED_BYTES + 2*param.FP2_ENCODED_BYTES + param.SECRETKEY_A_BYTES], - h_ = new byte[param.MSG_BYTES]; - byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; - byte[] tphiBKA_t = jinvariant_;//jinvariant_[param.FP2_ENCODED_BYTES]; + if (isCompressed) + { + byte[] ephemeralsk_ = new byte[param.SECRETKEY_B_BYTES]; + byte[] jinvariant_ = new byte[param.FP2_ENCODED_BYTES + 2*param.FP2_ENCODED_BYTES + param.SECRETKEY_A_BYTES], + h_ = new byte[param.MSG_BYTES]; + byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; + byte[] tphiBKA_t = jinvariant_;//jinvariant_[param.FP2_ENCODED_BYTES]; - // Decrypt - sidhCompressed.EphemeralSecretAgreement_A_extended(sk, param.MSG_BYTES, ct, jinvariant_, 1); + // Decrypt + sidhCompressed.EphemeralSecretAgreement_A_extended(sk, param.MSG_BYTES, ct, jinvariant_, 1); - IXof digest = new ShakeDigest(256); - digest.BlockUpdate(jinvariant_, 0, (int) param.FP2_ENCODED_BYTES); - digest.OutputFinal(h_, 0, (int) param.MSG_BYTES); + IXof digest = new ShakeDigest(256); + digest.BlockUpdate(jinvariant_, 0, (int) param.FP2_ENCODED_BYTES); + digest.OutputFinal(h_, 0, (int) param.MSG_BYTES); -// System.out.println("h_: " + Hex.toHexstring(h_)); + // System.out.println("h_: " + Hex.toHexstring(h_)); - for (int i = 0; i < param.MSG_BYTES; i++) - { - temp[i] = (byte) (ct[i + param.PARTIALLY_COMPRESSED_CHUNK_CT] ^ h_[i]); - } + for (int i = 0; i < param.MSG_BYTES; i++) + { + temp[i] = (byte) (ct[i + param.PARTIALLY_COMPRESSED_CHUNK_CT] ^ h_[i]); + } - // Generate ephemeralsk_ <- G(m||pk) mod oB - System.Array.Copy(sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); + // Generate ephemeralsk_ <- G(m||pk) mod oB + System.Array.Copy(sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); - digest.OutputFinal(ephemeralsk_, 0, (int) param.SECRETKEY_B_BYTES); - sidhCompressed.FormatPrivKey_B(ephemeralsk_); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); + digest.OutputFinal(ephemeralsk_, 0, (int) param.SECRETKEY_B_BYTES); + sidhCompressed.FormatPrivKey_B(ephemeralsk_); - // Generate shared secret ss <- H(m||ct), or output ss <- H(s||ct) in case of ct verification failure - // No need to recompress, just check if x(phi(P) + t*phi(Q)) == x((a0 + t*a1)*R1 + (b0 + t*b1)*R2) - byte selector = sidhCompressed.validate_ciphertext(ephemeralsk_, ct, sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES + param.CRYPTO_PUBLICKEYBYTES, tphiBKA_t, param.FP2_ENCODED_BYTES); - // If ct validation passes (selector = 0) then do ss = H(m||ct), otherwise (selector = -1) load s to do ss = H(s||ct) - fpx.ct_cmov(temp, sk, param.MSG_BYTES, selector); + // Generate shared secret ss <- H(m||ct), or output ss <- H(s||ct) in case of ct verification failure + // No need to recompress, just check if x(phi(P) + t*phi(Q)) == x((a0 + t*a1)*R1 + (b0 + t*b1)*R2) + byte selector = sidhCompressed.validate_ciphertext(ephemeralsk_, ct, sk, param.MSG_BYTES + param.SECRETKEY_A_BYTES + param.CRYPTO_PUBLICKEYBYTES, tphiBKA_t, param.FP2_ENCODED_BYTES); + // If ct validation passes (selector = 0) then do ss = H(m||ct), otherwise (selector = -1) load s to do ss = H(s||ct) + fpx.ct_cmov(temp, sk, param.MSG_BYTES, selector); - System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); - digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); + System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); + digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); - return 0; - } - else - { - byte[] ephemeralsk_ = new byte[param.SECRETKEY_A_BYTES]; - byte[] jinvariant_ = new byte[param.FP2_ENCODED_BYTES]; - byte[] h_ = new byte[param.MSG_BYTES]; - byte[] c0_ = new byte[param.CRYPTO_PUBLICKEYBYTES]; - byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; - - // Decrypt - // int EphemeralSecretAgreement_B(PrivateKeyB, PublicKeyA, SharedSecretB) - sidh.EphemeralSecretAgreement_B(sk, ct, jinvariant_); - - IXof digest = new ShakeDigest(256); - digest.BlockUpdate(jinvariant_, 0, (int) param.FP2_ENCODED_BYTES); - digest.OutputFinal(h_, 0, (int) param.MSG_BYTES); - for (int i = 0; i < param.MSG_BYTES; i++) - { - temp[i] = (byte) (ct[i + param.CRYPTO_PUBLICKEYBYTES] ^ h_[i]); + return 0; } + else + { + byte[] ephemeralsk_ = new byte[param.SECRETKEY_A_BYTES]; + byte[] jinvariant_ = new byte[param.FP2_ENCODED_BYTES]; + byte[] h_ = new byte[param.MSG_BYTES]; + byte[] c0_ = new byte[param.CRYPTO_PUBLICKEYBYTES]; + byte[] temp = new byte[param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES]; - // Generate ephemeralsk_ <- G(m||pk) mod oA - System.Array.Copy(sk, param.MSG_BYTES + param.SECRETKEY_B_BYTES, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); + // Decrypt + // int EphemeralSecretAgreement_B(PrivateKeyB, PublicKeyA, SharedSecretB) + sidh.EphemeralSecretAgreement_B(sk, ct, jinvariant_); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); - digest.OutputFinal(ephemeralsk_, 0, (int) param.SECRETKEY_A_BYTES); - ephemeralsk_[param.SECRETKEY_A_BYTES - 1] &= (byte) param.MASK_ALICE; + IXof digest = new ShakeDigest(256); + digest.BlockUpdate(jinvariant_, 0, (int) param.FP2_ENCODED_BYTES); + digest.OutputFinal(h_, 0, (int) param.MSG_BYTES); + for (int i = 0; i < param.MSG_BYTES; i++) + { + temp[i] = (byte) (ct[i + param.CRYPTO_PUBLICKEYBYTES] ^ h_[i]); + } + // Generate ephemeralsk_ <- G(m||pk) mod oA + System.Array.Copy(sk, param.MSG_BYTES + param.SECRETKEY_B_BYTES, temp, param.MSG_BYTES, param.CRYPTO_PUBLICKEYBYTES); - // Generate shared secret ss <- H(m||ct), or output ss <- H(s||ct) in case of ct verification failure - sidh.EphemeralKeyGeneration_A(ephemeralsk_, c0_); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_PUBLICKEYBYTES + param.MSG_BYTES)); + digest.OutputFinal(ephemeralsk_, 0, (int) param.SECRETKEY_A_BYTES); + ephemeralsk_[param.SECRETKEY_A_BYTES - 1] &= (byte) param.MASK_ALICE; - // If selector = 0 then do ss = H(m||ct), else if selector = -1 load s to do ss = H(s||ct) - byte selector = fpx.ct_compare(c0_, ct, param.CRYPTO_PUBLICKEYBYTES); - fpx.ct_cmov(temp, sk, param.MSG_BYTES, selector); - System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); - digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); - digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); + // Generate shared secret ss <- H(m||ct), or output ss <- H(s||ct) in case of ct verification failure + sidh.EphemeralKeyGeneration_A(ephemeralsk_, c0_); - return 0; + // If selector = 0 then do ss = H(m||ct), else if selector = -1 load s to do ss = H(s||ct) + byte selector = fpx.ct_compare(c0_, ct, param.CRYPTO_PUBLICKEYBYTES); + fpx.ct_cmov(temp, sk, param.MSG_BYTES, selector); + + System.Array.Copy(ct, 0, temp, param.MSG_BYTES, param.CRYPTO_CIPHERTEXTBYTES); + digest.BlockUpdate(temp, 0, (int) (param.CRYPTO_CIPHERTEXTBYTES + param.MSG_BYTES)); + digest.OutputFinal(ss, 0, (int) param.CRYPTO_BYTES); + + return 0; + } } } - } - -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs b/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs index 3c523ba8c..879f1d8ef 100644 --- a/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs +++ b/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs @@ -4,6 +4,7 @@ using Org.BouncyCastle.Crypto; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikeKemExtractor : IEncapsulatedSecretExtractor { @@ -26,10 +27,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike public byte[] ExtractSecret(byte[] encapsulation) { - return ExtractSecret(encapsulation, engine.GetDefaultSessionKeySize()); + return ExtractSecret(encapsulation, (int)engine.GetDefaultSessionKeySize()); } - public byte[] ExtractSecret(byte[] encapsulation, uint sessionKeySizeInBits) + public byte[] ExtractSecret(byte[] encapsulation, int sessionKeySizeInBits) { Console.Error.WriteLine("WARNING: the SIKE algorithm is only for research purposes, insecure"); byte[] session_key = new byte[sessionKeySizeInBits / 8]; diff --git a/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs b/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs index 76689496f..5e4bd41eb 100644 --- a/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs +++ b/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs @@ -6,6 +6,7 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikeKemGenerator : IEncapsulatedSecretGenerator { @@ -22,10 +23,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike SikePublicKeyParameters key = (SikePublicKeyParameters)recipientKey; SikeEngine engine = key.Parameters.Engine; - return GenerateEncapsulated(recipientKey, engine.GetDefaultSessionKeySize()); + return GenerateEncapsulated(recipientKey, (int)engine.GetDefaultSessionKeySize()); } - public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey, uint sessionKeySizeInBits) + public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey, + int sessionKeySizeInBits) { Console.Error.WriteLine("WARNING: the SIKE algorithm is only for research purposes, insecure"); SikePublicKeyParameters key = (SikePublicKeyParameters)recipientKey; diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs b/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs index 353587637..f595032eb 100644 --- a/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs +++ b/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs @@ -1,8 +1,11 @@ +using System; + using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikeKeyGenerationParameters : KeyGenerationParameters { diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs b/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs index 3ba67faa9..20def8a32 100644 --- a/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs +++ b/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs @@ -1,8 +1,11 @@ +using System; + using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikeKeyPairGenerator : IAsymmetricCipherKeyPairGenerator { diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs index 5d515eb1d..759c8dd5d 100644 --- a/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs +++ b/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs @@ -1,7 +1,10 @@ +using System; + using Org.BouncyCastle.Crypto; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public abstract class SikeKeyParameters : AsymmetricKeyParameter { diff --git a/crypto/src/pqc/crypto/sike/SIKEParameters.cs b/crypto/src/pqc/crypto/sike/SIKEParameters.cs index 3aa332341..d18797067 100644 --- a/crypto/src/pqc/crypto/sike/SIKEParameters.cs +++ b/crypto/src/pqc/crypto/sike/SIKEParameters.cs @@ -1,5 +1,8 @@ +using System; + namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikeParameters { public static readonly SikeParameters sikep434 = new SikeParameters(434, false, "sikep434"); diff --git a/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs index 0666ffb72..ee7116b68 100644 --- a/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs @@ -1,7 +1,10 @@ +using System; + using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikePrivateKeyParameters : SikeKeyParameters { diff --git a/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs index b567e979c..3300ed438 100644 --- a/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs @@ -1,7 +1,10 @@ +using System; + using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Sike { + [Obsolete("Will be removed")] public sealed class SikePublicKeyParameters : SikeKeyParameters { diff --git a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusParameters.cs b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusParameters.cs index e8a95fd2f..8cde7cf7f 100644 --- a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusParameters.cs +++ b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusParameters.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Org.BouncyCastle.Crypto.Utilities; @@ -265,9 +266,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus * @param id the oid of interest. * @return the parameter set. */ - public static SphincsPlusParameters GetParams(uint id) + public static SphincsPlusParameters GetParams(int id) { - return oidToParams[id]; + return oidToParams[Convert.ToUInt32(id)]; } /** @@ -276,14 +277,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus * @param params the parameters of interest. * @return the OID for the parameter set. */ - public static uint GetID(SphincsPlusParameters parameters) + public static int GetID(SphincsPlusParameters parameters) { - return paramsToOid[parameters]; + return Convert.ToInt32(paramsToOid[parameters]); } public byte[] GetEncoded() { - return Pack.UInt32_To_BE(GetID(this)); + return Pack.UInt32_To_BE((uint)GetID(this)); } } diff --git a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPrivateKeyParameters.cs b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPrivateKeyParameters.cs index ed5195da2..55757b927 100644 --- a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPrivateKeyParameters.cs @@ -53,13 +53,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus public byte[] GetEncoded() { - var id = Pack.UInt32_To_BE(SphincsPlusParameters.GetID(Parameters)); + var id = Pack.UInt32_To_BE((uint)SphincsPlusParameters.GetID(Parameters)); return Arrays.ConcatenateAll(id, m_sk.seed, m_sk.prf, m_pk.seed, m_pk.root); } public byte[] GetEncodedPublicKey() { - var id = Pack.UInt32_To_BE(SphincsPlusParameters.GetID(Parameters)); + var id = Pack.UInt32_To_BE((uint)SphincsPlusParameters.GetID(Parameters)); return Arrays.ConcatenateAll(id, m_pk.seed, m_pk.root); } } diff --git a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPublicKeyParameters.cs b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPublicKeyParameters.cs index 96e9324cc..b34843998 100644 --- a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusPublicKeyParameters.cs @@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus public byte[] GetEncoded() { - var id = Pack.UInt32_To_BE(SphincsPlusParameters.GetID(Parameters)); + var id = Pack.UInt32_To_BE((uint)SphincsPlusParameters.GetID(Parameters)); return Arrays.ConcatenateAll(id, m_pk.seed, m_pk.root); } } diff --git a/crypto/src/pqc/crypto/utils/PqcUtilities.cs b/crypto/src/pqc/crypto/utils/PqcUtilities.cs index 1f1da5e74..67e58fd28 100644 --- a/crypto/src/pqc/crypto/utils/PqcUtilities.cs +++ b/crypto/src/pqc/crypto/utils/PqcUtilities.cs @@ -15,7 +15,7 @@ using Org.BouncyCastle.Pqc.Crypto.SphincsPlus; namespace Org.BouncyCastle.Pqc.Crypto.Utilities { - public class PqcUtilities + internal class PqcUtilities { private readonly static Dictionary<CmceParameters, DerObjectIdentifier> mcElieceOids = new Dictionary<CmceParameters, DerObjectIdentifier>(); private readonly static Dictionary<DerObjectIdentifier, CmceParameters> mcElieceParams = new Dictionary<DerObjectIdentifier, CmceParameters>(); @@ -25,10 +25,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities private readonly static Dictionary<PicnicParameters, DerObjectIdentifier> picnicOids = new Dictionary<PicnicParameters, DerObjectIdentifier>(); private readonly static Dictionary<DerObjectIdentifier, PicnicParameters> picnicParams = new Dictionary<DerObjectIdentifier, PicnicParameters>(); - + +#pragma warning disable CS0618 // Type or member is obsolete private readonly static Dictionary<SikeParameters, DerObjectIdentifier> sikeOids = new Dictionary<SikeParameters, DerObjectIdentifier>(); private readonly static Dictionary<DerObjectIdentifier, SikeParameters> sikeParams = new Dictionary<DerObjectIdentifier, SikeParameters>(); - +#pragma warning restore CS0618 // Type or member is obsolete + private readonly static Dictionary<KyberParameters, DerObjectIdentifier> kyberOids = new Dictionary<KyberParameters, DerObjectIdentifier>(); private readonly static Dictionary<DerObjectIdentifier, KyberParameters> kyberParams = new Dictionary<DerObjectIdentifier, KyberParameters>(); @@ -132,7 +134,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities picnicParams[BCObjectIdentifiers.picnicl1full] = PicnicParameters.picnicl1full; picnicParams[BCObjectIdentifiers.picnicl3full] = PicnicParameters.picnicl3full; picnicParams[BCObjectIdentifiers.picnicl5full] = PicnicParameters.picnicl5full; - + +#pragma warning disable CS0618 // Type or member is obsolete sikeParams[BCObjectIdentifiers.sikep434] = SikeParameters.sikep434; sikeParams[BCObjectIdentifiers.sikep503] = SikeParameters.sikep503; sikeParams[BCObjectIdentifiers.sikep610] = SikeParameters.sikep610; @@ -141,7 +144,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities sikeParams[BCObjectIdentifiers.sikep503_compressed] = SikeParameters.sikep503_compressed; sikeParams[BCObjectIdentifiers.sikep610_compressed] = SikeParameters.sikep610_compressed; sikeParams[BCObjectIdentifiers.sikep751_compressed] = SikeParameters.sikep751_compressed; - + sikeOids[SikeParameters.sikep434] = BCObjectIdentifiers.sikep434; sikeOids[SikeParameters.sikep503] = BCObjectIdentifiers.sikep503; sikeOids[SikeParameters.sikep610] = BCObjectIdentifiers.sikep610; @@ -150,7 +153,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities sikeOids[SikeParameters.sikep503_compressed] = BCObjectIdentifiers.sikep503_compressed; sikeOids[SikeParameters.sikep610_compressed] = BCObjectIdentifiers.sikep610_compressed; sikeOids[SikeParameters.sikep751_compressed] = BCObjectIdentifiers.sikep751_compressed; - +#pragma warning restore CS0618 // Type or member is obsolete + kyberOids[KyberParameters.kyber512] = BCObjectIdentifiers.kyber512; kyberOids[KyberParameters.kyber768] = BCObjectIdentifiers.kyber768; kyberOids[KyberParameters.kyber1024] = BCObjectIdentifiers.kyber1024; @@ -203,7 +207,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities hqcOids[HqcParameters.hqc256] = BCObjectIdentifiers.hqc256; } - public static DerObjectIdentifier McElieceOidLookup(CmceParameters parameters) + internal static DerObjectIdentifier McElieceOidLookup(CmceParameters parameters) { return mcElieceOids[parameters]; } @@ -248,17 +252,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities internal static DerObjectIdentifier SphincsPlusOidLookup(SphincsPlusParameters parameters) { - uint pId = SphincsPlusParameters.GetID(parameters); + int pId = SphincsPlusParameters.GetID(parameters); if ((pId & 0x020000) == 0x020000) - { return BCObjectIdentifiers.sphincsPlus_shake_256; - } if ((pId & 0x05) == 0x05 || (pId & 0x06) == 0x06) - { return BCObjectIdentifiers.sphincsPlus_sha_512; - } return BCObjectIdentifiers.sphincsPlus_sha_256; } @@ -272,6 +272,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities { return picnicParams[oid]; } + +#pragma warning disable CS0618 // Type or member is obsolete internal static DerObjectIdentifier SikeOidLookup(SikeParameters parameters) { return sikeOids[parameters]; @@ -281,6 +283,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities { return sikeParams[oid]; } +#pragma warning restore CS0618 // Type or member is obsolete internal static DerObjectIdentifier BikeOidLookup(BikeParameters parameters) { diff --git a/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs b/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs index 7db65dbfb..6ad9bdb0c 100644 --- a/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs +++ b/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs @@ -81,7 +81,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities if (algOID.On(BCObjectIdentifiers.sphincsPlus)) { byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets(); - SphincsPlusParameters spParams = SphincsPlusParameters.GetParams((uint)BigInteger.ValueOf(Pack.BE_To_UInt32(keyEnc, 0)).IntValue); + SphincsPlusParameters spParams = SphincsPlusParameters.GetParams(BigInteger.ValueOf(Pack.BE_To_UInt32(keyEnc, 0)).IntValue); return new SphincsPlusPrivateKeyParameters(spParams, Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length)); } @@ -99,6 +99,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities return new PicnicPrivateKeyParameters(picnicParams, keyEnc); } +#pragma warning disable CS0618 // Type or member is obsolete if (algOID.On(BCObjectIdentifiers.pqc_kem_sike)) { byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets(); @@ -106,6 +107,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities return new SikePrivateKeyParameters(sikeParams, keyEnc); } +#pragma warning restore CS0618 // Type or member is obsolete if (algOID.On(BCObjectIdentifiers.pqc_kem_bike)) { byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets(); diff --git a/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs index 806eae8b7..53b34b3f4 100644 --- a/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs +++ b/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs @@ -93,6 +93,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities PqcUtilities.PicnicOidLookup(picnicPrivateKeyParameters.Parameters)); return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes); } +#pragma warning disable CS0618 // Type or member is obsolete if (privateKey is SikePrivateKeyParameters sikePrivateKeyParameters) { byte[] encoding = sikePrivateKeyParameters.GetEncoded(); @@ -101,14 +102,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities PqcUtilities.SikeOidLookup(sikePrivateKeyParameters.Parameters)); return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes); } +#pragma warning restore CS0618 // Type or member is obsolete if (privateKey is FalconPrivateKeyParameters falconPrivateKeyParameters) { Asn1EncodableVector v = new Asn1EncodableVector(); v.Add(new DerInteger(1)); - v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyf())); + v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyLittleF())); v.Add(new DerOctetString(falconPrivateKeyParameters.GetG())); - v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyF())); + v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyBigF())); AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier( PqcUtilities.FalconOidLookup(falconPrivateKeyParameters.Parameters)); diff --git a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs index 5d55a73aa..9eea279b1 100644 --- a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs +++ b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs @@ -82,7 +82,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities Converters[BCObjectIdentifiers.picnicl1full] = new PicnicConverter(); Converters[BCObjectIdentifiers.picnicl3full] = new PicnicConverter(); Converters[BCObjectIdentifiers.picnicl5full] = new PicnicConverter(); - + +#pragma warning disable CS0618 // Type or member is obsolete Converters[BCObjectIdentifiers.sikep434] = new SikeConverter(); Converters[BCObjectIdentifiers.sikep503] = new SikeConverter(); Converters[BCObjectIdentifiers.sikep610] = new SikeConverter(); @@ -91,7 +92,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities Converters[BCObjectIdentifiers.sikep503_compressed] = new SikeConverter(); Converters[BCObjectIdentifiers.sikep610_compressed] = new SikeConverter(); Converters[BCObjectIdentifiers.sikep751_compressed] = new SikeConverter(); - +#pragma warning restore CS0618 // Type or member is obsolete + Converters[BCObjectIdentifiers.dilithium2] = new DilithiumConverter(); Converters[BCObjectIdentifiers.dilithium3] = new DilithiumConverter(); Converters[BCObjectIdentifiers.dilithium5] = new DilithiumConverter(); @@ -197,11 +199,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities { internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams) { - byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); + byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); - SphincsPlusParameters spParams = SphincsPlusParameters.GetParams((uint)BigInteger.ValueOf(Pack.BE_To_UInt32(keyEnc, 0)).IntValue); + SphincsPlusParameters spParams = SphincsPlusParameters.GetParams((int)Pack.BE_To_UInt32(keyEnc, 0)); - return new SphincsPlusPublicKeyParameters(spParams, Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length)); + return new SphincsPlusPublicKeyParameters(spParams, Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length)); } } @@ -223,7 +225,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities { internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams) { - byte[] keyEnc = DerOctetString.GetInstance( + byte[] keyEnc = Asn1OctetString.GetInstance( DerSequence.GetInstance(keyInfo.ParsePublicKey())[0]).GetOctets(); SaberParameters saberParams = PqcUtilities.SaberParamsLookup(keyInfo.AlgorithmID.Algorithm); @@ -237,19 +239,20 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities { internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams) { - byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); + byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); PicnicParameters picnicParams = PqcUtilities.PicnicParamsLookup(keyInfo.AlgorithmID.Algorithm); return new PicnicPublicKeyParameters(picnicParams, keyEnc); } } + [Obsolete("Will be removed")] private class SikeConverter : SubjectPublicKeyInfoConverter { internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams) { - byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); + byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets(); SikeParameters sikeParams = PqcUtilities.SikeParamsLookup(keyInfo.AlgorithmID.Algorithm); diff --git a/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs index 39d437320..b88834e50 100644 --- a/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs +++ b/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs @@ -89,6 +89,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities PqcUtilities.PicnicOidLookup(picnicPublicKeyParameters.Parameters)); return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding)); } +#pragma warning disable CS0618 // Type or member is obsolete if (publicKey is SikePublicKeyParameters sikePublicKeyParameters) { byte[] encoding = sikePublicKeyParameters.GetEncoded(); @@ -97,6 +98,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities PqcUtilities.SikeOidLookup(sikePublicKeyParameters.Parameters)); return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding)); } +#pragma warning restore CS0618 // Type or member is obsolete if (publicKey is FalconPublicKeyParameters falconPublicKeyParameters) { byte[] encoding = falconPublicKeyParameters.GetEncoded(); diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs index 3a7c5f0cb..08853e45e 100644 --- a/crypto/src/security/DotNetUtilities.cs +++ b/crypto/src/security/DotNetUtilities.cs @@ -5,9 +5,12 @@ using System.Runtime.Versioning; using System.Security.Cryptography; using SystemX509 = System.Security.Cryptography.X509Certificates; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities; @@ -50,23 +53,11 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetDsaKeyPair(DSAParameters dp) { - DsaValidationParameters validationParameters = (dp.Seed != null) - ? new DsaValidationParameters(dp.Seed, dp.Counter) - : null; - - DsaParameters parameters = new DsaParameters( - new BigInteger(1, dp.P), - new BigInteger(1, dp.Q), - new BigInteger(1, dp.G), - validationParameters); - - DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters( - new BigInteger(1, dp.Y), - parameters); + DsaPublicKeyParameters pubKey = GetDsaPublicKey(dp); DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters( new BigInteger(1, dp.X), - parameters); + pubKey.Parameters); return new AsymmetricCipherKeyPair(pubKey, privKey); } @@ -93,6 +84,62 @@ namespace Org.BouncyCastle.Security parameters); } +#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER + public static AsymmetricCipherKeyPair GetECDsaKeyPair(ECDsa ecDsa) + { + return GetECKeyPair("ECDSA", ecDsa.ExportParameters(true)); + } + + public static ECPublicKeyParameters GetECDsaPublicKey(ECDsa ecDsa) + { + return GetECPublicKey("ECDSA", ecDsa.ExportParameters(false)); + } + + public static AsymmetricCipherKeyPair GetECKeyPair(string algorithm, ECParameters ec) + { + ECPublicKeyParameters pubKey = GetECPublicKey(algorithm, ec); + + ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( + pubKey.AlgorithmName, + new BigInteger(1, ec.D), + pubKey.Parameters); + + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + + public static ECPublicKeyParameters GetECPublicKey(string algorithm, ECParameters ec) + { + X9ECParameters x9 = GetX9ECParameters(ec.Curve); + if (x9 == null) + throw new NotSupportedException("Unrecognized curve"); + + return new ECPublicKeyParameters( + algorithm, + GetECPoint(x9.Curve, ec.Q), + new ECDomainParameters(x9)); + } + + private static Math.EC.ECPoint GetECPoint(Math.EC.ECCurve curve, ECPoint point) + { + return curve.CreatePoint(new BigInteger(1, point.X), new BigInteger(1, point.Y)); + } + + private static X9ECParameters GetX9ECParameters(ECCurve curve) + { + if (!curve.IsNamed) + throw new NotSupportedException("Only named curves are supported"); + + Oid oid = curve.Oid; + if (oid != null) + { + string oidValue = oid.Value; + if (oidValue != null) + return ECKeyPairGenerator.FindECCurveByOid(new DerObjectIdentifier(oidValue)); + } + return null; + } +#endif + public static AsymmetricCipherKeyPair GetRsaKeyPair(RSA rsa) { return GetRsaKeyPair(rsa.ExportParameters(true)); @@ -100,17 +147,11 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp) { - BigInteger modulus = new BigInteger(1, rp.Modulus); - BigInteger pubExp = new BigInteger(1, rp.Exponent); - - RsaKeyParameters pubKey = new RsaKeyParameters( - false, - modulus, - pubExp); + RsaKeyParameters pubKey = GetRsaPublicKey(rp); RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters( - modulus, - pubExp, + pubKey.Modulus, + pubKey.Exponent, new BigInteger(1, rp.D), new BigInteger(1, rp.P), new BigInteger(1, rp.Q), @@ -137,17 +178,18 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey) { - if (privateKey is DSA) - { - return GetDsaKeyPair((DSA)privateKey); - } + if (privateKey is DSA dsa) + return GetDsaKeyPair(dsa); - if (privateKey is RSA) - { - return GetRsaKeyPair((RSA)privateKey); - } +#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER + if (privateKey is ECDsa ecDsa) + return GetECDsaKeyPair(ecDsa); +#endif - throw new ArgumentException("Unsupported algorithm specified", "privateKey"); + if (privateKey is RSA rsa) + return GetRsaKeyPair(rsa); + + throw new ArgumentException("Unsupported algorithm specified", nameof(privateKey)); } #if NET5_0_OR_GREATER @@ -244,6 +286,18 @@ namespace Org.BouncyCastle.Security return BigIntegers.AsUnsignedByteArray(size, n); } + // TODO Why do we use CspParameters instead of just RSA.Create in methods below? +// private static RSA CreateRSA(RSAParameters rp) +// { +//#if NETCOREAPP2_0_OR_GREATER || NET472_OR_GREATER || NETSTANDARD2_1_OR_GREATER +// return RSA.Create(rp); +//#else +// var rsa = RSA.Create(); +// rsa.ImportParameters(rp); +// return rsa; +//#endif +// } + #if NET5_0_OR_GREATER [SupportedOSPlatform("windows")] #endif diff --git a/crypto/src/security/JksStore.cs b/crypto/src/security/JksStore.cs index 30b21fad2..9f4aced96 100644 --- a/crypto/src/security/JksStore.cs +++ b/crypto/src/security/JksStore.cs @@ -10,6 +10,7 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.IO; using Org.BouncyCastle.X509; @@ -216,9 +217,7 @@ namespace Org.BouncyCastle.Security { var aliases = new HashSet<string>(m_certificateEntries.Keys); aliases.UnionWith(m_keyEntries.Keys); - // FIXME - //return CollectionUtilities.Proxy(aliases); - return aliases; + return CollectionUtilities.Proxy(aliases); } } diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs index d9d855c45..e66224a67 100644 --- a/crypto/src/security/PrivateKeyFactory.cs +++ b/crypto/src/security/PrivateKeyFactory.cs @@ -2,8 +2,10 @@ using System; using System.IO; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Gnu; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.Rosstandart; @@ -128,29 +130,99 @@ namespace Org.BouncyCastle.Security ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed()); return new ECPrivateKeyParameters(d, dParams); } - else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001) || + algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512) || + algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256)) { - Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance( - algID.Parameters.ToAsn1Object()); + Asn1Object p = algID.Parameters.ToAsn1Object(); + Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(p); - X9ECParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + ECGost3410Parameters ecSpec; + BigInteger d; - if (ecP == null) - throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); + if (p is Asn1Sequence seq && (seq.Count == 2 || seq.Count == 3)) + { + X9ECParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + if (ecP == null) + throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); - Asn1Object privKey = keyInfo.ParsePrivateKey(); - ECPrivateKeyStructure ec; + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(gostParams.PublicKeyParamSet, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); - if (privKey is DerInteger) - { - ec = new ECPrivateKeyStructure(ecP.N.BitLength, ((DerInteger)privKey).PositiveValue); + Asn1OctetString privEnc = keyInfo.PrivateKeyData; + if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64) + { + d = new BigInteger(1, Arrays.Reverse(privEnc.GetOctets())); + } + else + { + Asn1Object privKey = keyInfo.ParsePrivateKey(); + if (privKey is DerInteger derInteger) + { + d = derInteger.PositiveValue; + } + else + { + byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()); + d = new BigInteger(1, dVal); + } + } } else { - ec = ECPrivateKeyStructure.GetInstance(privKey); + X962Parameters x962Parameters = X962Parameters.GetInstance(p); + + if (x962Parameters.IsNamedCurve) + { + DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(x962Parameters.Parameters); + X9ECParameters ecP = ECNamedCurveTable.GetByOid(oid); + if (ecP == null) + throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); + + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(oid, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); + } + else if (x962Parameters.IsImplicitlyCA) + { + ecSpec = null; + } + else + { + X9ECParameters ecP = X9ECParameters.GetInstance(x962Parameters.Parameters); + + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(algOid, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); + } + + Asn1Object privKey = keyInfo.ParsePrivateKey(); + if (privKey is DerInteger derD) + { + d = derD.Value; + } + else + { + ECPrivateKeyStructure ec = ECPrivateKeyStructure.GetInstance(privKey); + + d = ec.GetKey(); + } } - return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet); + return new ECPrivateKeyParameters( + d, + new ECGost3410Parameters( + ecSpec, + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet)); } else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) { @@ -170,7 +242,8 @@ namespace Org.BouncyCastle.Security return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); } - else if (algOid.Equals(EdECObjectIdentifiers.id_X25519)) + else if (algOid.Equals(EdECObjectIdentifiers.id_X25519) + || algOid.Equals(CryptlibObjectIdentifiers.curvey25519)) { return new X25519PrivateKeyParameters(GetRawKey(keyInfo)); } @@ -178,7 +251,8 @@ namespace Org.BouncyCastle.Security { return new X448PrivateKeyParameters(GetRawKey(keyInfo)); } - else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519)) + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519) + || algOid.Equals(GnuObjectIdentifiers.Ed25519)) { return new Ed25519PrivateKeyParameters(GetRawKey(keyInfo)); } diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs index e0c7ce950..8c3e9db99 100644 --- a/crypto/src/security/PublicKeyFactory.cs +++ b/crypto/src/security/PublicKeyFactory.cs @@ -2,8 +2,10 @@ using System; using System.IO; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Gnu; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.Rosstandart; @@ -211,7 +213,8 @@ namespace Org.BouncyCastle.Security return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet); } - else if (algOid.Equals(EdECObjectIdentifiers.id_X25519)) + else if (algOid.Equals(EdECObjectIdentifiers.id_X25519) + || algOid.Equals(CryptlibObjectIdentifiers.curvey25519)) { return new X25519PublicKeyParameters(GetRawKey(keyInfo)); } @@ -219,7 +222,8 @@ namespace Org.BouncyCastle.Security { return new X448PublicKeyParameters(GetRawKey(keyInfo)); } - else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519)) + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519) + || algOid.Equals(GnuObjectIdentifiers.Ed25519)) { return new Ed25519PublicKeyParameters(GetRawKey(keyInfo)); } diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs index e6210dad7..6500cdf13 100644 --- a/crypto/src/security/SignerUtilities.cs +++ b/crypto/src/security/SignerUtilities.cs @@ -379,14 +379,18 @@ namespace Org.BouncyCastle.Security AlgorithmMap["GOST-3410-2012-256"] = "ECGOST3410-2012-256"; AlgorithmMap["GOST3411WITHECGOST3410-2012-256"] = "ECGOST3410-2012-256"; + AlgorithmMap["GOST3411-2012-256WITHECGOST3410"] = "ECGOST3410-2012-256"; AlgorithmMap["GOST3411-2012-256WITHECGOST3410-2012-256"] = "ECGOST3410-2012-256"; + AlgorithmMap["GOST3411-2012-256/ECGOST3410"] = "ECGOST3410-2012-256"; AlgorithmMap["GOST3411-2012-256/ECGOST3410-2012-256"] = "ECGOST3410-2012-256"; AlgorithmMap[RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256.Id] = "ECGOST3410-2012-256"; AlgorithmMap["GOST-3410-2012-512"] = "ECGOST3410-2012-512"; AlgorithmMap["GOST3411WITHECGOST3410-2012-512"] = "ECGOST3410-2012-512"; + AlgorithmMap["GOST3411-2012-512WITHECGOST3410"] = "ECGOST3410-2012-512"; AlgorithmMap["GOST3411-2012-512WITHECGOST3410-2012-512"] = "ECGOST3410-2012-512"; + AlgorithmMap["GOST3411-2012-512/ECGOST3410"] = "ECGOST3410-2012-512"; AlgorithmMap["GOST3411-2012-512/ECGOST3410-2012-512"] = "ECGOST3410-2012-512"; AlgorithmMap[RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512.Id] = "ECGOST3410-2012-512"; diff --git a/crypto/src/tls/AbstractTlsPeer.cs b/crypto/src/tls/AbstractTlsPeer.cs index 4e1b28e58..6d7c88f1b 100644 --- a/crypto/src/tls/AbstractTlsPeer.cs +++ b/crypto/src/tls/AbstractTlsPeer.cs @@ -157,5 +157,7 @@ namespace Org.BouncyCastle.Tls { return HeartbeatMode.peer_not_allowed_to_send; } + + public virtual bool IgnoreCorruptDtlsRecords => false; } } diff --git a/crypto/src/tls/CombinedHash.cs b/crypto/src/tls/CombinedHash.cs index 71151d2a5..360b9d426 100644 --- a/crypto/src/tls/CombinedHash.cs +++ b/crypto/src/tls/CombinedHash.cs @@ -43,6 +43,14 @@ namespace Org.BouncyCastle.Tls m_sha1.Update(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + m_md5.Update(input); + m_sha1.Update(input); + } +#endif + public virtual byte[] CalculateHash() { if (null != m_context && TlsUtilities.IsSsl(m_context)) diff --git a/crypto/src/tls/DatagramReceiver.cs b/crypto/src/tls/DatagramReceiver.cs index 5ab605ac4..a689515f6 100644 --- a/crypto/src/tls/DatagramReceiver.cs +++ b/crypto/src/tls/DatagramReceiver.cs @@ -10,5 +10,10 @@ namespace Org.BouncyCastle.Tls /// <exception cref="IOException"/> int Receive(byte[] buf, int off, int len, int waitMillis); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + int Receive(Span<byte> buffer, int waitMillis); +#endif } } diff --git a/crypto/src/tls/DatagramSender.cs b/crypto/src/tls/DatagramSender.cs index bf14c18fe..c2a987b51 100644 --- a/crypto/src/tls/DatagramSender.cs +++ b/crypto/src/tls/DatagramSender.cs @@ -10,5 +10,10 @@ namespace Org.BouncyCastle.Tls /// <exception cref="IOException"/> void Send(byte[] buf, int off, int len); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + void Send(ReadOnlySpan<byte> buffer); +#endif } } diff --git a/crypto/src/tls/DeferredHash.cs b/crypto/src/tls/DeferredHash.cs index 82f7899a5..e6397ab1e 100644 --- a/crypto/src/tls/DeferredHash.cs +++ b/crypto/src/tls/DeferredHash.cs @@ -176,6 +176,22 @@ namespace Org.BouncyCastle.Tls } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + if (m_buf != null) + { + m_buf.Write(input); + return; + } + + foreach (TlsHash hash in m_hashes.Values) + { + hash.Update(input); + } + } +#endif + public byte[] CalculateHash() { throw new InvalidOperationException("Use 'ForkPrfHash' to get a definite hash"); diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs index b8c09617a..0a4a711ae 100644 --- a/crypto/src/tls/DtlsClientProtocol.cs +++ b/crypto/src/tls/DtlsClientProtocol.cs @@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords); } InvalidateSession(state); @@ -392,7 +392,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords); } /// <exception cref="IOException"/> diff --git a/crypto/src/tls/DtlsRecordLayer.cs b/crypto/src/tls/DtlsRecordLayer.cs index b93253146..bab6892b7 100644 --- a/crypto/src/tls/DtlsRecordLayer.cs +++ b/crypto/src/tls/DtlsRecordLayer.cs @@ -1,8 +1,6 @@ using System; using System.IO; -#if !PORTABLE || DOTNET using System.Net.Sockets; -#endif using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Utilities; @@ -244,6 +242,9 @@ namespace Org.BouncyCastle.Tls /// <exception cref="IOException"/> public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Receive(buf.AsSpan(off, len), waitMillis); +#else long currentTimeMillis = DateTimeUtilities.CurrentUnixMs(); Timeout timeout = Timeout.ForWaitMillis(waitMillis, currentTimeMillis); @@ -307,11 +308,85 @@ namespace Org.BouncyCastle.Tls } return -1; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + public virtual int Receive(Span<byte> buffer, int waitMillis) + { + long currentTimeMillis = DateTimeUtilities.CurrentUnixMs(); + + Timeout timeout = Timeout.ForWaitMillis(waitMillis, currentTimeMillis); + byte[] record = null; + + while (waitMillis >= 0) + { + if (null != m_retransmitTimeout && m_retransmitTimeout.RemainingMillis(currentTimeMillis) < 1) + { + m_retransmit = null; + m_retransmitEpoch = null; + m_retransmitTimeout = null; + } + + if (Timeout.HasExpired(m_heartbeatTimeout, currentTimeMillis)) + { + if (null != m_heartbeatInFlight) + throw new TlsTimeoutException("Heartbeat timed out"); + + this.m_heartbeatInFlight = HeartbeatMessage.Create(m_context, + HeartbeatMessageType.heartbeat_request, m_heartbeat.GeneratePayload()); + this.m_heartbeatTimeout = new Timeout(m_heartbeat.TimeoutMillis, currentTimeMillis); + + this.m_heartbeatResendMillis = DtlsReliableHandshake.INITIAL_RESEND_MILLIS; + this.m_heartbeatResendTimeout = new Timeout(m_heartbeatResendMillis, currentTimeMillis); + + SendHeartbeatMessage(m_heartbeatInFlight); + } + else if (Timeout.HasExpired(m_heartbeatResendTimeout, currentTimeMillis)) + { + this.m_heartbeatResendMillis = DtlsReliableHandshake.BackOff(m_heartbeatResendMillis); + this.m_heartbeatResendTimeout = new Timeout(m_heartbeatResendMillis, currentTimeMillis); + + SendHeartbeatMessage(m_heartbeatInFlight); + } + + waitMillis = Timeout.ConstrainWaitMillis(waitMillis, m_heartbeatTimeout, currentTimeMillis); + waitMillis = Timeout.ConstrainWaitMillis(waitMillis, m_heartbeatResendTimeout, currentTimeMillis); + + // NOTE: Guard against bad logic giving a negative value + if (waitMillis < 0) + { + waitMillis = 1; + } + + int receiveLimit = System.Math.Min(buffer.Length, GetReceiveLimit()) + RECORD_HEADER_LENGTH; + if (null == record || record.Length < receiveLimit) + { + record = new byte[receiveLimit]; + } + + int received = ReceiveRecord(record, 0, receiveLimit, waitMillis); + int processed = ProcessRecord(received, record, buffer); + if (processed >= 0) + { + return processed; + } + + currentTimeMillis = DateTimeUtilities.CurrentUnixMs(); + waitMillis = Timeout.GetWaitMillis(timeout, currentTimeMillis); + } + + return -1; + } +#endif + /// <exception cref="IOException"/> public virtual void Send(byte[] buf, int off, int len) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Send(buf.AsSpan(off, len)); +#else short contentType = ContentType.application_data; if (m_inHandshake || m_writeEpoch == m_retransmitEpoch) @@ -340,7 +415,7 @@ namespace Org.BouncyCastle.Tls // Implicitly send change_cipher_spec and change to pending cipher state // TODO Send change_cipher_spec and finished records in single datagram? - byte[] data = new byte[]{ 1 }; + byte[] data = new byte[1]{ 1 }; SendRecord(ContentType.change_cipher_spec, data, 0, data.Length); this.m_writeEpoch = nextEpoch; @@ -348,7 +423,51 @@ namespace Org.BouncyCastle.Tls } SendRecord(contentType, buf, off, len); +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + public virtual void Send(ReadOnlySpan<byte> buffer) + { + short contentType = ContentType.application_data; + + if (m_inHandshake || m_writeEpoch == m_retransmitEpoch) + { + contentType = ContentType.handshake; + + short handshakeType = TlsUtilities.ReadUint8(buffer); + if (handshakeType == HandshakeType.finished) + { + DtlsEpoch nextEpoch = null; + if (m_inHandshake) + { + nextEpoch = m_pendingEpoch; + } + else if (m_writeEpoch == m_retransmitEpoch) + { + nextEpoch = m_currentEpoch; + } + + if (nextEpoch == null) + { + // TODO + throw new InvalidOperationException(); + } + + // Implicitly send change_cipher_spec and change to pending cipher state + + // TODO Send change_cipher_spec and finished records in single datagram? + ReadOnlySpan<byte> data = stackalloc byte[1]{ 1 }; + SendRecord(ContentType.change_cipher_spec, data); + + this.m_writeEpoch = nextEpoch; + } + } + + SendRecord(contentType, buffer); } +#endif /// <exception cref="IOException"/> public virtual void Close() @@ -434,11 +553,13 @@ namespace Org.BouncyCastle.Tls { m_peer.NotifyAlertRaised(alertLevel, alertDescription, message, cause); - byte[] error = new byte[2]; - error[0] = (byte)alertLevel; - error[1] = (byte)alertDescription; - +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ReadOnlySpan<byte> error = stackalloc byte[2]{ (byte)alertLevel, (byte)alertDescription }; + SendRecord(ContentType.alert, error); +#else + byte[] error = new byte[2]{ (byte)alertLevel, (byte)alertDescription }; SendRecord(ContentType.alert, error, 0, 2); +#endif } /// <exception cref="IOException"/> @@ -452,7 +573,6 @@ namespace Org.BouncyCastle.Tls { return -1; } -#if !PORTABLE || DOTNET catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) @@ -460,7 +580,6 @@ namespace Org.BouncyCastle.Tls throw e; } -#endif // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException e) //{ @@ -471,7 +590,11 @@ namespace Org.BouncyCastle.Tls // TODO Include 'currentTimeMillis' as an argument, use with Timeout, resetHeartbeat /// <exception cref="IOException"/> +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private int ProcessRecord(int received, byte[] record, Span<byte> buffer) +#else private int ProcessRecord(int received, byte[] record, byte[] buf, int off) +#endif { // NOTE: received < 0 (timeout) is covered by this first case if (received < RECORD_HEADER_LENGTH) @@ -704,7 +827,11 @@ namespace Org.BouncyCastle.Tls this.m_retransmitTimeout = null; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + decoded.buf.AsSpan(decoded.off, decoded.len).CopyTo(buffer); +#else Array.Copy(decoded.buf, decoded.off, buf, off, decoded.len); +#endif return decoded.len; } @@ -716,9 +843,7 @@ namespace Org.BouncyCastle.Tls int length = 0; if (m_recordQueue.Available >= RECORD_HEADER_LENGTH) { - byte[] lengthBytes = new byte[2]; - m_recordQueue.Read(lengthBytes, 0, 2, 11); - length = TlsUtilities.ReadUint16(lengthBytes, 0); + length = m_recordQueue.ReadUint16(11); } int received = System.Math.Min(m_recordQueue.Available, RECORD_HEADER_LENGTH + length); @@ -758,9 +883,16 @@ namespace Org.BouncyCastle.Tls { MemoryStream output = new MemoryStream(); heartbeatMessage.Encode(output); - byte[] buf = output.ToArray(); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + if (!output.TryGetBuffer(out var buffer)) + throw new InvalidOperationException(); + + SendRecord(ContentType.heartbeat, buffer); +#else + byte[] buf = output.ToArray(); SendRecord(ContentType.heartbeat, buf, 0, buf.Length); +#endif } /* @@ -770,12 +902,20 @@ namespace Org.BouncyCastle.Tls * be possible reordering of records (which might surprise a reliable transport implementation). */ /// <exception cref="IOException"/> +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void SendRecord(short contentType, ReadOnlySpan<byte> buffer) +#else private void SendRecord(short contentType, byte[] buf, int off, int len) +#endif { // Never send anything until a valid ClientHello has been received if (m_writeVersion == null) return; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + int len = buffer.Length; +#endif + if (len > m_plaintextLimit) throw new TlsFatalAlert(AlertDescription.internal_error); @@ -793,8 +933,13 @@ namespace Org.BouncyCastle.Tls long macSequenceNumber = GetMacSequenceNumber(recordEpoch, recordSequenceNumber); ProtocolVersion recordVersion = m_writeVersion; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + TlsEncodeResult encoded = m_writeEpoch.Cipher.EncodePlaintext(macSequenceNumber, contentType, + recordVersion, RECORD_HEADER_LENGTH, buffer); +#else TlsEncodeResult encoded = m_writeEpoch.Cipher.EncodePlaintext(macSequenceNumber, contentType, recordVersion, RECORD_HEADER_LENGTH, buf, off, len); +#endif int ciphertextLength = encoded.len - RECORD_HEADER_LENGTH; TlsUtilities.CheckUint16(ciphertextLength); diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs index b42f97b64..5edd5595e 100644 --- a/crypto/src/tls/DtlsServerProtocol.cs +++ b/crypto/src/tls/DtlsServerProtocol.cs @@ -381,7 +381,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.server.IgnoreCorruptDtlsRecords); } /// <exception cref="IOException"/> diff --git a/crypto/src/tls/DtlsTransport.cs b/crypto/src/tls/DtlsTransport.cs index a41cb7866..033e0af0b 100644 --- a/crypto/src/tls/DtlsTransport.cs +++ b/crypto/src/tls/DtlsTransport.cs @@ -1,8 +1,6 @@ using System; using System.IO; -#if !PORTABLE || DOTNET using System.Net.Sockets; -#endif namespace Org.BouncyCastle.Tls { @@ -10,10 +8,12 @@ namespace Org.BouncyCastle.Tls : DatagramTransport { private readonly DtlsRecordLayer m_recordLayer; + private readonly bool m_ignoreCorruptRecords; - internal DtlsTransport(DtlsRecordLayer recordLayer) + internal DtlsTransport(DtlsRecordLayer recordLayer, bool ignoreCorruptRecords) { - this.m_recordLayer = recordLayer; + m_recordLayer = recordLayer; + m_ignoreCorruptRecords = ignoreCorruptRecords; } /// <exception cref="IOException"/> @@ -37,6 +37,10 @@ namespace Org.BouncyCastle.Tls throw new ArgumentException("invalid offset: " + off, "off"); if (len < 0 || len > buf.Length - off) throw new ArgumentException("invalid length: " + len, "len"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Receive(buf.AsSpan(off, len), waitMillis); +#else if (waitMillis < 0) throw new ArgumentException("cannot be negative", "waitMillis"); @@ -46,6 +50,9 @@ namespace Org.BouncyCastle.Tls } catch (TlsFatalAlert fatalAlert) { + if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) + return -1; + m_recordLayer.Fail(fatalAlert.AlertDescription); throw fatalAlert; } @@ -53,7 +60,6 @@ namespace Org.BouncyCastle.Tls { throw e; } -#if !PORTABLE || DOTNET catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) @@ -62,7 +68,55 @@ namespace Org.BouncyCastle.Tls m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + // TODO[tls-port] Can we support interrupted IO on .NET? + //catch (InterruptedIOException e) + //{ + // throw e; + //} + catch (IOException e) + { + m_recordLayer.Fail(AlertDescription.internal_error); + throw e; + } + catch (Exception e) + { + m_recordLayer.Fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } #endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + public virtual int Receive(Span<byte> buffer, int waitMillis) + { + if (waitMillis < 0) + throw new ArgumentException("cannot be negative", nameof(waitMillis)); + + try + { + return m_recordLayer.Receive(buffer, waitMillis); + } + catch (TlsFatalAlert fatalAlert) + { + if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) + return -1; + + m_recordLayer.Fail(fatalAlert.AlertDescription); + throw fatalAlert; + } + catch (TlsTimeoutException e) + { + throw e; + } + catch (SocketException e) + { + if (TlsUtilities.IsTimeout(e)) + throw e; + + m_recordLayer.Fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException e) //{ @@ -79,6 +133,7 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.internal_error, e); } } +#endif /// <exception cref="IOException"/> public virtual void Send(byte[] buf, int off, int len) @@ -90,6 +145,9 @@ namespace Org.BouncyCastle.Tls if (len < 0 || len > buf.Length - off) throw new ArgumentException("invalid length: " + len, "len"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Send(buf.AsSpan(off, len)); +#else try { m_recordLayer.Send(buf, off, len); @@ -103,7 +161,6 @@ namespace Org.BouncyCastle.Tls { throw e; } -#if !PORTABLE || DOTNET catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) @@ -112,7 +169,48 @@ namespace Org.BouncyCastle.Tls m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + // TODO[tls-port] Can we support interrupted IO on .NET? + //catch (InterruptedIOException e) + //{ + // throw e; + //} + catch (IOException e) + { + m_recordLayer.Fail(AlertDescription.internal_error); + throw e; + } + catch (Exception e) + { + m_recordLayer.Fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } #endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual void Send(ReadOnlySpan<byte> buffer) + { + try + { + m_recordLayer.Send(buffer); + } + catch (TlsFatalAlert fatalAlert) + { + m_recordLayer.Fail(fatalAlert.AlertDescription); + throw fatalAlert; + } + catch (TlsTimeoutException e) + { + throw e; + } + catch (SocketException e) + { + if (TlsUtilities.IsTimeout(e)) + throw e; + + m_recordLayer.Fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException e) //{ @@ -129,6 +227,7 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.internal_error, e); } } +#endif /// <exception cref="IOException"/> public virtual void Close() diff --git a/crypto/src/tls/RecordStream.cs b/crypto/src/tls/RecordStream.cs index a97d34698..a5926d05b 100644 --- a/crypto/src/tls/RecordStream.cs +++ b/crypto/src/tls/RecordStream.cs @@ -258,6 +258,9 @@ namespace Org.BouncyCastle.Tls /// <exception cref="IOException"/> internal void WriteRecord(short contentType, byte[] plaintext, int plaintextOffset, int plaintextLength) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + WriteRecord(contentType, plaintext.AsSpan(plaintextOffset, plaintextLength)); +#else // Never send anything until a valid ClientHello has been received if (m_writeVersion == null) return; @@ -298,8 +301,56 @@ namespace Org.BouncyCastle.Tls //} m_output.Flush(); +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + internal void WriteRecord(short contentType, ReadOnlySpan<byte> plaintext) + { + // Never send anything until a valid ClientHello has been received + if (m_writeVersion == null) + return; + + /* + * RFC 5246 6.2.1 The length should not exceed 2^14. + */ + CheckLength(plaintext.Length, m_plaintextLimit, AlertDescription.internal_error); + + /* + * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * or ChangeCipherSpec content types. + */ + if (plaintext.Length < 1 && contentType != ContentType.application_data) + throw new TlsFatalAlert(AlertDescription.internal_error); + + long seqNo = m_writeSeqNo.NextValue(AlertDescription.internal_error); + ProtocolVersion recordVersion = m_writeVersion; + + TlsEncodeResult encoded = m_writeCipher.EncodePlaintext(seqNo, contentType, recordVersion, + RecordFormat.FragmentOffset, plaintext); + + int ciphertextLength = encoded.len - RecordFormat.FragmentOffset; + TlsUtilities.CheckUint16(ciphertextLength); + + TlsUtilities.WriteUint8(encoded.recordType, encoded.buf, encoded.off + RecordFormat.TypeOffset); + TlsUtilities.WriteVersion(recordVersion, encoded.buf, encoded.off + RecordFormat.VersionOffset); + TlsUtilities.WriteUint16(ciphertextLength, encoded.buf, encoded.off + RecordFormat.LengthOffset); + + // TODO[tls-port] Can we support interrupted IO on .NET? + //try + //{ + m_output.Write(encoded.buf, encoded.off, encoded.len); + //} + //catch (InterruptedIOException e) + //{ + // throw new TlsFatalAlert(AlertDescription.internal_error, e); + //} + + m_output.Flush(); + } +#endif + /// <exception cref="IOException"/> internal void Close() { diff --git a/crypto/src/tls/TlsPeer.cs b/crypto/src/tls/TlsPeer.cs index ef2837135..04d66d38f 100644 --- a/crypto/src/tls/TlsPeer.cs +++ b/crypto/src/tls/TlsPeer.cs @@ -119,5 +119,12 @@ namespace Org.BouncyCastle.Tls /// </remarks> /// <returns>the <see cref="HeartbeatMode"/> value.</returns> short GetHeartbeatPolicy(); + + /// <summary>Indicates whether a DTLS connection should ignore corrupt records (bad_record_mac) instead of + /// failing the connection.</summary> + /// <remarks>Called only once at the start of a connection and applies throughout.</remarks> + /// <returns>The value <c>true</c> to ignore corrupt DTLS records, or <c>false</c> to fail the connection. + /// </returns> + bool IgnoreCorruptDtlsRecords { get; } } } diff --git a/crypto/src/tls/TlsProtocol.cs b/crypto/src/tls/TlsProtocol.cs index 3461e9b58..437a51447 100644 --- a/crypto/src/tls/TlsProtocol.cs +++ b/crypto/src/tls/TlsProtocol.cs @@ -707,6 +707,9 @@ namespace Org.BouncyCastle.Tls { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return ReadApplicationData(buffer.AsSpan(offset, count)); +#else if (!m_appDataReady) throw new InvalidOperationException("Cannot read application data until initial handshake completed."); @@ -733,8 +736,42 @@ namespace Org.BouncyCastle.Tls m_applicationDataQueue.RemoveData(buffer, offset, count, 0); } return count; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual int ReadApplicationData(Span<byte> buffer) + { + if (!m_appDataReady) + throw new InvalidOperationException("Cannot read application data until initial handshake completed."); + + while (m_applicationDataQueue.Available < 1) + { + if (this.m_closed) + { + if (this.m_failedWithError) + throw new IOException("Cannot read application data on failed TLS connection"); + + return 0; + } + + /* + * NOTE: Only called more than once when empty records are received, so no special + * InterruptedIOException handling is necessary. + */ + SafeReadRecord(); + } + + int count = buffer.Length; + if (count > 0) + { + count = System.Math.Min(count, m_applicationDataQueue.Available); + m_applicationDataQueue.RemoveData(buffer[..count], 0); + } + return count; + } +#endif + /// <exception cref="IOException"/> protected virtual RecordPreview SafePreviewRecordHeader(byte[] recordHeader) { @@ -850,6 +887,32 @@ namespace Org.BouncyCastle.Tls } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// <exception cref="IOException"/> + protected virtual void SafeWriteRecord(short type, ReadOnlySpan<byte> buffer) + { + try + { + m_recordStream.WriteRecord(type, buffer); + } + catch (TlsFatalAlert e) + { + HandleException(e.AlertDescription, "Failed to write record", e); + throw e; + } + catch (IOException e) + { + HandleException(AlertDescription.internal_error, "Failed to write record", e); + throw e; + } + catch (Exception e) + { + HandleException(AlertDescription.internal_error, "Failed to write record", e); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +#endif + /// <summary>Write some application data.</summary> /// <remarks> /// Fragmentation is handled internally. Usable in both blocking/non-blocking modes.<br/><br/> @@ -869,6 +932,9 @@ namespace Org.BouncyCastle.Tls { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + WriteApplicationData(buffer.AsSpan(offset, count)); +#else if (!m_appDataReady) throw new InvalidOperationException( "Cannot write application data until initial handshake completed."); @@ -938,7 +1004,82 @@ namespace Org.BouncyCastle.Tls count -= toWrite; } } +#endif + } + + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual void WriteApplicationData(ReadOnlySpan<byte> buffer) + { + if (!m_appDataReady) + throw new InvalidOperationException( + "Cannot write application data until initial handshake completed."); + + lock (m_recordWriteLock) + { + while (!buffer.IsEmpty) + { + if (m_closed) + throw new IOException("Cannot write application data on closed/failed TLS connection"); + + /* + * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are + * potentially useful as a traffic analysis countermeasure. + * + * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting. + */ + if (m_appDataSplitEnabled) + { + /* + * Protect against known IV attack! + * + * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE. + */ + switch (m_appDataSplitMode) + { + case ADS_MODE_0_N_FIRSTONLY: + { + this.m_appDataSplitEnabled = false; + SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0); + break; + } + case ADS_MODE_0_N: + { + SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0); + break; + } + case ADS_MODE_1_Nsub1: + default: + { + if (buffer.Length > 1) + { + SafeWriteRecord(ContentType.application_data, buffer[..1]); + buffer = buffer[1..]; + } + break; + } + } + } + else if (m_keyUpdateEnabled) + { + if (m_keyUpdatePendingSend) + { + Send13KeyUpdate(false); + } + else if (m_recordStream.NeedsKeyUpdate()) + { + Send13KeyUpdate(true); + } + } + + // Fragment data according to the current fragment limit. + int toWrite = System.Math.Min(buffer.Length, m_recordStream.PlaintextLimit); + SafeWriteRecord(ContentType.application_data, buffer[..toWrite]); + buffer = buffer[toWrite..]; + } + } } +#endif public virtual int AppDataSplitMode { diff --git a/crypto/src/tls/TlsStream.cs b/crypto/src/tls/TlsStream.cs index 01b990799..5c07da2bf 100644 --- a/crypto/src/tls/TlsStream.cs +++ b/crypto/src/tls/TlsStream.cs @@ -58,6 +58,13 @@ namespace Org.BouncyCastle.Tls return m_handler.ReadApplicationData(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + return m_handler.ReadApplicationData(buffer); + } +#endif + public override int ReadByte() { byte[] buf = new byte[1]; @@ -80,6 +87,13 @@ namespace Org.BouncyCastle.Tls m_handler.WriteApplicationData(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + m_handler.WriteApplicationData(buffer); + } +#endif + public override void WriteByte(byte value) { m_handler.WriteApplicationData(new byte[]{ value }, 0, 1); diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs index f12198082..463928ba6 100644 --- a/crypto/src/tls/TlsUtilities.cs +++ b/crypto/src/tls/TlsUtilities.cs @@ -747,9 +747,16 @@ namespace Org.BouncyCastle.Tls public static short ReadUint8(byte[] buf, int offset) { - return (short)(buf[offset] & 0xff); + return (short)buf[offset]; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static short ReadUint8(ReadOnlySpan<byte> buffer) + { + return (short)buffer[0]; + } +#endif + public static int ReadUint16(Stream input) { int i1 = input.ReadByte(); diff --git a/crypto/src/tls/crypto/TlsCipher.cs b/crypto/src/tls/crypto/TlsCipher.cs index 4c2147bf7..53a8141fd 100644 --- a/crypto/src/tls/crypto/TlsCipher.cs +++ b/crypto/src/tls/crypto/TlsCipher.cs @@ -38,6 +38,11 @@ namespace Org.BouncyCastle.Tls.Crypto TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, int headerAllocation, byte[] plaintext, int offset, int len); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, ReadOnlySpan<byte> plaintext); +#endif + /// <summary>Decode the passed in ciphertext using the current bulk cipher.</summary> /// <param name="seqNo">sequence number of the message represented by ciphertext.</param> /// <param name="recordType">content type used in the record for this message.</param> diff --git a/crypto/src/tls/crypto/TlsHash.cs b/crypto/src/tls/crypto/TlsHash.cs index 4732fc280..6fbaeceb9 100644 --- a/crypto/src/tls/crypto/TlsHash.cs +++ b/crypto/src/tls/crypto/TlsHash.cs @@ -11,6 +11,10 @@ namespace Org.BouncyCastle.Tls.Crypto /// <param name="length">the length of the input data.</param> void Update(byte[] input, int inOff, int length); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + void Update(ReadOnlySpan<byte> input); +#endif + /// <summary>Return calculated hash for any input passed in.</summary> /// <returns>the hash value.</returns> byte[] CalculateHash(); diff --git a/crypto/src/tls/crypto/TlsHashSink.cs b/crypto/src/tls/crypto/TlsHashSink.cs index a1681b0c8..3401eb60e 100644 --- a/crypto/src/tls/crypto/TlsHashSink.cs +++ b/crypto/src/tls/crypto/TlsHashSink.cs @@ -29,6 +29,16 @@ namespace Org.BouncyCastle.Tls.Crypto } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + if (!buffer.IsEmpty) + { + m_hash.Update(buffer); + } + } +#endif + public override void WriteByte(byte value) { m_hash.Update(new byte[]{ value }, 0, 1); diff --git a/crypto/src/tls/crypto/TlsMac.cs b/crypto/src/tls/crypto/TlsMac.cs index a898a9bcc..511e29d10 100644 --- a/crypto/src/tls/crypto/TlsMac.cs +++ b/crypto/src/tls/crypto/TlsMac.cs @@ -21,6 +21,10 @@ namespace Org.BouncyCastle.Tls.Crypto /// <param name="length">the length of the input data.</param> void Update(byte[] input, int inOff, int length); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + void Update(ReadOnlySpan<byte> input); +#endif + /// <summary>Return calculated MAC for any input passed in.</summary> /// <returns>the MAC value.</returns> byte[] CalculateMac(); diff --git a/crypto/src/tls/crypto/TlsMacSink.cs b/crypto/src/tls/crypto/TlsMacSink.cs index e7d5c70d7..fbb2e5893 100644 --- a/crypto/src/tls/crypto/TlsMacSink.cs +++ b/crypto/src/tls/crypto/TlsMacSink.cs @@ -29,6 +29,16 @@ namespace Org.BouncyCastle.Tls.Crypto } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + if (!buffer.IsEmpty) + { + m_mac.Update(buffer); + } + } +#endif + public override void WriteByte(byte value) { m_mac.Update(new byte[]{ value }, 0, 1); diff --git a/crypto/src/tls/crypto/TlsNullNullCipher.cs b/crypto/src/tls/crypto/TlsNullNullCipher.cs index 082dff358..13fe092f7 100644 --- a/crypto/src/tls/crypto/TlsNullNullCipher.cs +++ b/crypto/src/tls/crypto/TlsNullNullCipher.cs @@ -31,6 +31,16 @@ namespace Org.BouncyCastle.Tls.Crypto return new TlsEncodeResult(result, 0, result.Length, contentType); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, ReadOnlySpan<byte> plaintext) + { + byte[] result = new byte[headerAllocation + plaintext.Length]; + plaintext.CopyTo(result.AsSpan(headerAllocation)); + return new TlsEncodeResult(result, 0, result.Length, contentType); + } +#endif + public TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion, byte[] ciphertext, int offset, int len) { diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs index 046e6883f..594981210 100644 --- a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs +++ b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs @@ -161,6 +161,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, int headerAllocation, byte[] plaintext, int plaintextOffset, int plaintextLength) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return EncodePlaintext(seqNo, contentType, recordVersion, headerAllocation, + plaintext.AsSpan(plaintextOffset, plaintextLength)); +#else byte[] nonce = new byte[m_encryptNonce.Length + m_record_iv_length]; switch (m_nonceMode) @@ -229,7 +233,83 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl } return new TlsEncodeResult(output, 0, output.Length, recordType); +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, ReadOnlySpan<byte> plaintext) + { + byte[] nonce = new byte[m_encryptNonce.Length + m_record_iv_length]; + + switch (m_nonceMode) + { + case NONCE_RFC5288: + Array.Copy(m_encryptNonce, 0, nonce, 0, m_encryptNonce.Length); + // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number. + TlsUtilities.WriteUint64(seqNo, nonce, m_encryptNonce.Length); + break; + case NONCE_RFC7905: + TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8); + for (int i = 0; i < m_encryptNonce.Length; ++i) + { + nonce[i] ^= m_encryptNonce[i]; + } + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int extraLength = m_isTlsV13 ? 1 : 0; + + // TODO[tls13] If we support adding padding to TLSInnerPlaintext, this will need review + int encryptionLength = m_encryptCipher.GetOutputSize(plaintext.Length + extraLength); + int ciphertextLength = m_record_iv_length + encryptionLength; + + byte[] output = new byte[headerAllocation + ciphertextLength]; + int outputPos = headerAllocation; + + if (m_record_iv_length != 0) + { + Array.Copy(nonce, nonce.Length - m_record_iv_length, output, outputPos, m_record_iv_length); + outputPos += m_record_iv_length; + } + + short recordType = m_isTlsV13 ? ContentType.application_data : contentType; + + byte[] additionalData = GetAdditionalData(seqNo, recordType, recordVersion, ciphertextLength, + plaintext.Length); + + try + { + plaintext.CopyTo(output.AsSpan(outputPos)); + if (m_isTlsV13) + { + output[outputPos + plaintext.Length] = (byte)contentType; + } + + m_encryptCipher.Init(nonce, m_macSize, additionalData); + outputPos += m_encryptCipher.DoFinal(output, outputPos, plaintext.Length + extraLength, output, + outputPos); + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + + if (outputPos != output.Length) + { + // NOTE: The additional data mechanism for AEAD ciphers requires exact output size prediction. + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return new TlsEncodeResult(output, 0, output.Length, recordType); } +#endif public virtual TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion, byte[] ciphertext, int ciphertextOffset, int ciphertextLength) @@ -271,12 +351,21 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl outputPos = m_decryptCipher.DoFinal(ciphertext, encryptionOffset, encryptionLength, ciphertext, encryptionOffset); } + catch (TlsFatalAlert fatalAlert) + { + if (AlertDescription.bad_record_mac == fatalAlert.AlertDescription) + { + m_decryptCipher.Reset(); + } + throw fatalAlert; + } catch (IOException e) { throw e; } catch (Exception e) { + m_decryptCipher.Reset(); throw new TlsFatalAlert(AlertDescription.bad_record_mac, e); } diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs b/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs index 4c69c0b72..0cd2923c2 100644 --- a/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs +++ b/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs @@ -41,5 +41,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl /// <returns>the amount of data written to output.</returns> /// <exception cref="IOException">in case of failure.</exception> int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset); + + void Reset(); } } diff --git a/crypto/src/tls/crypto/impl/TlsBlockCipher.cs b/crypto/src/tls/crypto/impl/TlsBlockCipher.cs index ed9d68649..64a73bfea 100644 --- a/crypto/src/tls/crypto/impl/TlsBlockCipher.cs +++ b/crypto/src/tls/crypto/impl/TlsBlockCipher.cs @@ -199,6 +199,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, int headerAllocation, byte[] plaintext, int offset, int len) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return EncodePlaintext(seqNo, contentType, recordVersion, headerAllocation, plaintext.AsSpan(offset, len)); +#else int blockSize = m_encryptCipher.GetBlockSize(); int macSize = m_writeMac.Size; @@ -264,7 +267,80 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl throw new TlsFatalAlert(AlertDescription.internal_error); return new TlsEncodeResult(outBuf, 0, outBuf.Length, contentType); +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, ReadOnlySpan<byte> plaintext) + { + int blockSize = m_encryptCipher.GetBlockSize(); + int macSize = m_writeMac.Size; + + int enc_input_length = plaintext.Length; + if (!m_encryptThenMac) + { + enc_input_length += macSize; + } + + int padding_length = blockSize - (enc_input_length % blockSize); + if (m_useExtraPadding) + { + // Add a random number of extra blocks worth of padding + int maxExtraPadBlocks = (256 - padding_length) / blockSize; + int actualExtraPadBlocks = ChooseExtraPadBlocks(maxExtraPadBlocks); + padding_length += actualExtraPadBlocks * blockSize; + } + + int totalSize = plaintext.Length + macSize + padding_length; + if (m_useExplicitIV) + { + totalSize += blockSize; + } + + byte[] outBuf = new byte[headerAllocation + totalSize]; + int outOff = headerAllocation; + + if (m_useExplicitIV) + { + // Technically the explicit IV will be the encryption of this nonce + byte[] explicitIV = m_cryptoParams.NonceGenerator.GenerateNonce(blockSize); + Array.Copy(explicitIV, 0, outBuf, outOff, blockSize); + outOff += blockSize; + } + + plaintext.CopyTo(outBuf.AsSpan(outOff)); + outOff += plaintext.Length; + + if (!m_encryptThenMac) + { + byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext); + mac.CopyTo(outBuf.AsSpan(outOff)); + outOff += mac.Length; + } + + byte padByte = (byte)(padding_length - 1); + for (int i = 0; i < padding_length; ++i) + { + outBuf[outOff++] = padByte; + } + + m_encryptCipher.DoFinal(outBuf, headerAllocation, outOff - headerAllocation, outBuf, headerAllocation); + + if (m_encryptThenMac) + { + byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, outBuf, headerAllocation, + outOff - headerAllocation); + Array.Copy(mac, 0, outBuf, outOff, mac.Length); + outOff += mac.Length; + } + + if (outOff != outBuf.Length) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return new TlsEncodeResult(outBuf, 0, outBuf.Length, contentType); } +#endif public virtual TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion, byte[] ciphertext, int offset, int len) diff --git a/crypto/src/tls/crypto/impl/TlsNullCipher.cs b/crypto/src/tls/crypto/impl/TlsNullCipher.cs index 5b6b5663a..9bb08110a 100644 --- a/crypto/src/tls/crypto/impl/TlsNullCipher.cs +++ b/crypto/src/tls/crypto/impl/TlsNullCipher.cs @@ -81,6 +81,18 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, contentType); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, ReadOnlySpan<byte> plaintext) + { + byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext); + byte[] ciphertext = new byte[headerAllocation + plaintext.Length + mac.Length]; + plaintext.CopyTo(ciphertext.AsSpan(headerAllocation)); + mac.CopyTo(ciphertext.AsSpan(headerAllocation + plaintext.Length)); + return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, contentType); + } +#endif + public virtual TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion, byte[] ciphertext, int offset, int len) { diff --git a/crypto/src/tls/crypto/impl/TlsSuiteHmac.cs b/crypto/src/tls/crypto/impl/TlsSuiteHmac.cs index 9f43f4382..b4edde760 100644 --- a/crypto/src/tls/crypto/impl/TlsSuiteHmac.cs +++ b/crypto/src/tls/crypto/impl/TlsSuiteHmac.cs @@ -55,6 +55,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl public virtual byte[] CalculateMac(long seqNo, short type, byte[] msg, int msgOff, int msgLen) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return CalculateMac(seqNo, type, msg.AsSpan(msgOff, msgLen)); +#else ProtocolVersion serverVersion = m_cryptoParams.ServerVersion; bool isSsl = serverVersion.IsSsl; @@ -71,8 +74,31 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl m_mac.Update(msg, msgOff, msgLen); return Truncate(m_mac.CalculateMac()); +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual byte[] CalculateMac(long seqNo, short type, ReadOnlySpan<byte> message) + { + ProtocolVersion serverVersion = m_cryptoParams.ServerVersion; + bool isSsl = serverVersion.IsSsl; + + byte[] macHeader = new byte[isSsl ? 11 : 13]; + TlsUtilities.WriteUint64(seqNo, macHeader, 0); + TlsUtilities.WriteUint8(type, macHeader, 8); + if (!isSsl) + { + TlsUtilities.WriteVersion(serverVersion, macHeader, 9); + } + TlsUtilities.WriteUint16(message.Length, macHeader, macHeader.Length - 2); + + m_mac.Update(macHeader); + m_mac.Update(message); + + return Truncate(m_mac.CalculateMac()); + } +#endif + public virtual byte[] CalculateMacConstantTime(long seqNo, short type, byte[] msg, int msgOff, int msgLen, int fullLength, byte[] dummyData) { diff --git a/crypto/src/tls/crypto/impl/TlsSuiteMac.cs b/crypto/src/tls/crypto/impl/TlsSuiteMac.cs index 6e4942928..1a28eba81 100644 --- a/crypto/src/tls/crypto/impl/TlsSuiteMac.cs +++ b/crypto/src/tls/crypto/impl/TlsSuiteMac.cs @@ -18,6 +18,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl /// <returns>A new byte array containing the MAC value.</returns> byte[] CalculateMac(long seqNo, short type, byte[] message, int offset, int length); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + byte[] CalculateMac(long seqNo, short type, ReadOnlySpan<byte> message); +#endif + /// <summary>Constant time calculation of the MAC for some given data with a given expected length.</summary> /// <param name="seqNo">The sequence number of the record.</param> /// <param name="type">The content type of the message.</param> diff --git a/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs b/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs index 6b87c100a..06a09bbb1 100644 --- a/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs +++ b/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs @@ -96,6 +96,12 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC } } + public void Reset() + { + m_cipher.Reset(); + m_mac.Reset(); + } + public void SetKey(byte[] key, int keyOff, int keyLen) { KeyParameter cipherKey = new KeyParameter(key, keyOff, keyLen); @@ -106,16 +112,23 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC public void SetKey(ReadOnlySpan<byte> key) { KeyParameter cipherKey = new KeyParameter(key); - m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes[..12])); + m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes.AsSpan(0, 12))); } #endif private void InitMac() { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span<byte> firstBlock = stackalloc byte[64]; + m_cipher.ProcessBytes(firstBlock, firstBlock); + m_mac.Init(new KeyParameter(firstBlock[..32])); + firstBlock.Fill(0x00); +#else byte[] firstBlock = new byte[64]; m_cipher.ProcessBytes(firstBlock, 0, 64, firstBlock, 0); m_mac.Init(new KeyParameter(firstBlock, 0, 32)); Array.Clear(firstBlock, 0, firstBlock.Length); +#endif } private void UpdateMac(byte[] buf, int off, int len) diff --git a/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs b/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs index f26a50d46..a0378e334 100644 --- a/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs +++ b/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs @@ -66,6 +66,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_digest.BlockUpdate(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + m_digest.BlockUpdate(input); + } +#endif + public virtual byte[] CalculateMac() { byte[] result = new byte[m_digest.GetDigestSize()]; diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs b/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs index 0b2781326..4965c92bd 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs @@ -57,5 +57,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC return len; } + + public void Reset() + { + m_cipher.Reset(); + } } } diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs b/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs index 0b35831f3..0ad2576cb 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs @@ -28,6 +28,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_digest.BlockUpdate(data, offSet, length); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + m_digest.BlockUpdate(input); + } +#endif + public byte[] CalculateHash() { byte[] rv = new byte[m_digest.GetDigestSize()]; diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs b/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs index 7a2318a31..dbe7f4c69 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs @@ -32,6 +32,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_hmac.BlockUpdate(input, inOff, length); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan<byte> input) + { + m_hmac.BlockUpdate(input); + } +#endif + public byte[] CalculateMac() { byte[] rv = new byte[m_hmac.GetMacSize()]; diff --git a/crypto/src/tsp/TSPUtil.cs b/crypto/src/tsp/TSPUtil.cs index a9402ac6d..1ba289ae6 100644 --- a/crypto/src/tsp/TSPUtil.cs +++ b/crypto/src/tsp/TSPUtil.cs @@ -145,7 +145,7 @@ namespace Org.BouncyCastle.Tsp ExtendedKeyUsage extKey = ExtendedKeyUsage.GetInstance( Asn1Object.FromByteArray(ext.GetOctets())); - if (!extKey.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || extKey.Count != 1) + if (!extKey.HasKeyPurposeId(KeyPurposeID.id_kp_timeStamping) || extKey.Count != 1) throw new TspValidationException("ExtendedKeyUsage not solely time stamping."); } catch (IOException) diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs index 936e510be..bd2a4faea 100644 --- a/crypto/src/util/Arrays.cs +++ b/crypto/src/util/Arrays.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Utilities { /// <summary> General array utilities.</summary> - public abstract class Arrays + public static class Arrays { public static readonly byte[] EmptyBytes = new byte[0]; public static readonly int[] EmptyInts = new int[0]; @@ -884,6 +884,17 @@ namespace Org.BouncyCastle.Utilities return result; } + public static T[] Prepend<T>(T[] a, T b) + { + if (a == null) + return new T[1]{ b }; + + T[] result = new T[1 + a.Length]; + result[0] = b; + a.CopyTo(result, 1); + return result; + } + public static byte[] Reverse(byte[] a) { if (a == null) diff --git a/crypto/src/util/io/BaseInputStream.cs b/crypto/src/util/io/BaseInputStream.cs index ebe256632..eaaf9556d 100644 --- a/crypto/src/util/io/BaseInputStream.cs +++ b/crypto/src/util/io/BaseInputStream.cs @@ -45,5 +45,9 @@ namespace Org.BouncyCastle.Utilities.IO public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) { throw new NotSupportedException(); } +#endif } } diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs index dad9b19a4..0fc8e9681 100644 --- a/crypto/src/util/io/BaseOutputStream.cs +++ b/crypto/src/util/io/BaseOutputStream.cs @@ -21,6 +21,9 @@ namespace Org.BouncyCastle.Utilities.IO set { throw new NotSupportedException(); } } public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public sealed override int Read(Span<byte> buffer) { throw new NotSupportedException(); } +#endif public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } diff --git a/crypto/src/util/io/FilterStream.cs b/crypto/src/util/io/FilterStream.cs index d9bcbb8ef..38077edd2 100644 --- a/crypto/src/util/io/FilterStream.cs +++ b/crypto/src/util/io/FilterStream.cs @@ -10,10 +10,7 @@ namespace Org.BouncyCastle.Utilities.IO public FilterStream(Stream s) { - if (s == null) - throw new ArgumentNullException(nameof(s)); - - this.s = s; + this.s = s ?? throw new ArgumentNullException(nameof(s)); } public override bool CanRead { @@ -27,6 +24,12 @@ namespace Org.BouncyCastle.Utilities.IO { get { return s.CanWrite; } } +#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void CopyTo(Stream destination, int bufferSize) + { + s.CopyTo(destination, bufferSize); + } +#endif public override void Flush() { s.Flush(); @@ -44,6 +47,12 @@ namespace Org.BouncyCastle.Utilities.IO { return s.Read(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span<byte> buffer) + { + return s.Read(buffer); + } +#endif public override int ReadByte() { return s.ReadByte(); @@ -60,6 +69,12 @@ namespace Org.BouncyCastle.Utilities.IO { s.Write(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan<byte> buffer) + { + s.Write(buffer); + } +#endif public override void WriteByte(byte value) { s.WriteByte(value); |