diff --git a/crypto/src/asn1/pkcs/EncryptionScheme.cs b/crypto/src/asn1/pkcs/EncryptionScheme.cs
index 34d26e172..a073f8c17 100644
--- a/crypto/src/asn1/pkcs/EncryptionScheme.cs
+++ b/crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -1,13 +1,24 @@
-using System;
-
using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Asn1.Pkcs
{
public class EncryptionScheme
: AlgorithmIdentifier
{
+ public new static EncryptionScheme GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is EncryptionScheme encryptionScheme)
+ return encryptionScheme;
+ return new EncryptionScheme(Asn1Sequence.GetInstance(obj));
+ }
+
+ public new static EncryptionScheme GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+ }
+
public EncryptionScheme(
DerObjectIdentifier objectID)
: base(objectID)
@@ -27,21 +38,6 @@ namespace Org.BouncyCastle.Asn1.Pkcs
{
}
- public new static EncryptionScheme GetInstance(object obj)
- {
- if (obj is EncryptionScheme)
- {
- return (EncryptionScheme)obj;
- }
-
- if (obj is Asn1Sequence)
- {
- return new EncryptionScheme((Asn1Sequence)obj);
- }
-
- throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
- }
-
public Asn1Object Asn1Object
{
get { return Parameters.ToAsn1Object(); }
diff --git a/crypto/src/asn1/x509/NameConstraints.cs b/crypto/src/asn1/x509/NameConstraints.cs
index 031b71ceb..87db1e534 100644
--- a/crypto/src/asn1/x509/NameConstraints.cs
+++ b/crypto/src/asn1/x509/NameConstraints.cs
@@ -6,7 +6,7 @@ namespace Org.BouncyCastle.Asn1.X509
public class NameConstraints
: Asn1Encodable
{
- private Asn1Sequence m_permitted, m_excluded;
+ private readonly Asn1Sequence m_permitted, m_excluded;
public static NameConstraints GetInstance(object obj)
{
@@ -53,12 +53,12 @@ namespace Org.BouncyCastle.Asn1.X509
{
if (permitted != null)
{
- this.m_permitted = CreateSequence(permitted);
+ m_permitted = CreateSequence(permitted);
}
if (excluded != null)
{
- this.m_excluded = CreateSequence(excluded);
+ m_excluded = CreateSequence(excluded);
}
}
diff --git a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
index 4875152eb..234990fc7 100644
--- a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
+++ b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -49,7 +49,15 @@ namespace Org.BouncyCastle.Asn1.X509
this.algID = algID;
}
- private SubjectPublicKeyInfo(
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public SubjectPublicKeyInfo(AlgorithmIdentifier algID, ReadOnlySpan<byte> publicKey)
+ {
+ this.keyData = new DerBitString(publicKey);
+ this.algID = algID;
+ }
+#endif
+
+ private SubjectPublicKeyInfo(
Asn1Sequence seq)
{
if (seq.Count != 2)
diff --git a/crypto/src/bcpg/ContainedPacket.cs b/crypto/src/bcpg/ContainedPacket.cs
index e8f387ca4..ca39fd985 100644
--- a/crypto/src/bcpg/ContainedPacket.cs
+++ b/crypto/src/bcpg/ContainedPacket.cs
@@ -10,11 +10,11 @@ namespace Org.BouncyCastle.Bcpg
public byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
- BcpgOutputStream pOut = new BcpgOutputStream(bOut);
-
- pOut.WritePacket(this);
-
- return bOut.ToArray();
+ using (var pOut = new BcpgOutputStream(bOut))
+ {
+ pOut.WritePacket(this);
+ }
+ return bOut.ToArray();
}
public abstract void Encode(BcpgOutputStream bcpgOut);
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index 89177ce84..639d5595c 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -98,20 +98,19 @@ namespace Org.BouncyCastle.Bcpg
public virtual byte[] GetEncodedContents()
{
MemoryStream bOut = new MemoryStream();
- BcpgOutputStream pOut = new BcpgOutputStream(bOut);
-
- pOut.WriteByte((byte) version);
- pOut.WriteInt((int) time);
-
- if (version <= 3)
+ using (var pOut = new BcpgOutputStream(bOut))
{
- pOut.WriteShort((short) validDays);
- }
-
- pOut.WriteByte((byte) algorithm);
+ pOut.WriteByte((byte)version);
+ pOut.WriteInt((int)time);
- pOut.WriteObject((BcpgObject)key);
+ if (version <= 3)
+ {
+ pOut.WriteShort((short)validDays);
+ }
+ pOut.WriteByte((byte)algorithm);
+ pOut.WriteObject((BcpgObject)key);
+ }
return bOut.ToArray();
}
diff --git a/crypto/src/bcpg/SecretKeyPacket.cs b/crypto/src/bcpg/SecretKeyPacket.cs
index 1bc684a69..15b89b404 100644
--- a/crypto/src/bcpg/SecretKeyPacket.cs
+++ b/crypto/src/bcpg/SecretKeyPacket.cs
@@ -1,11 +1,10 @@
-using System;
using System.IO;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Bcpg
{
- /// <remarks>Basic packet for a PGP secret key.</remarks>
+ /// <remarks>Basic packet for a PGP secret key.</remarks>
public class SecretKeyPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
@@ -136,28 +135,27 @@ namespace Org.BouncyCastle.Bcpg
public byte[] GetEncodedContents()
{
MemoryStream bOut = new MemoryStream();
- BcpgOutputStream pOut = new BcpgOutputStream(bOut);
-
- pOut.Write(pubKeyPacket.GetEncodedContents());
-
- pOut.WriteByte((byte) s2kUsage);
-
- if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+ using (var pOut = new BcpgOutputStream(bOut))
{
- pOut.WriteByte((byte) encAlgorithm);
- pOut.WriteObject(s2k);
- }
+ pOut.Write(pubKeyPacket.GetEncodedContents());
+ pOut.WriteByte((byte)s2kUsage);
- if (iv != null)
- {
- pOut.Write(iv);
- }
+ if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+ {
+ pOut.WriteByte((byte)encAlgorithm);
+ pOut.WriteObject(s2k);
+ }
- if (secKeyData != null && secKeyData.Length > 0)
- {
- pOut.Write(secKeyData);
- }
+ if (iv != null)
+ {
+ pOut.Write(iv);
+ }
+ if (secKeyData != null && secKeyData.Length > 0)
+ {
+ pOut.Write(secKeyData);
+ }
+ }
return bOut.ToArray();
}
diff --git a/crypto/src/crypto/fpe/FpeFf3_1Engine.cs b/crypto/src/crypto/fpe/FpeFf3_1Engine.cs
index bc8d22fae..5e8148bb8 100644
--- a/crypto/src/crypto/fpe/FpeFf3_1Engine.cs
+++ b/crypto/src/crypto/fpe/FpeFf3_1Engine.cs
@@ -19,9 +19,7 @@ namespace Org.BouncyCastle.Crypto.Fpe
: base(baseCipher)
{
if (IsOverrideSet(SP80038G.FPE_DISABLED))
- {
throw new InvalidOperationException("FPE disabled");
- }
}
public override void Init(bool forEncryption, ICipherParameters parameters)
@@ -29,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Fpe
this.forEncryption = forEncryption;
this.fpeParameters = (FpeParameters)parameters;
- baseCipher.Init(!fpeParameters.UseInverseFunction, ReverseKey(fpeParameters.Key));
+ baseCipher.Init(!fpeParameters.UseInverseFunction, fpeParameters.Key.Reverse());
if (fpeParameters.GetTweak().Length != 7)
throw new ArgumentException("tweak should be 56 bits");
@@ -82,18 +80,5 @@ namespace Org.BouncyCastle.Crypto.Fpe
return length;
}
-
- private static KeyParameter ReverseKey(KeyParameter key)
- {
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- return KeyParameter.Create(key.KeyLength, key, (bytes, key) =>
- {
- key.Key.CopyTo(bytes);
- bytes.Reverse();
- });
-#else
- return new KeyParameter(Arrays.Reverse(key.GetKey()));
-#endif
- }
}
}
diff --git a/crypto/src/crypto/fpe/SP80038G.cs b/crypto/src/crypto/fpe/SP80038G.cs
index c57a34762..5488f20fd 100644
--- a/crypto/src/crypto/fpe/SP80038G.cs
+++ b/crypto/src/crypto/fpe/SP80038G.cs
@@ -358,11 +358,10 @@ namespace Org.BouncyCastle.Crypto.Fpe
// iii.
Array.Reverse(P);
cipher.ProcessBlock(P, 0, P, 0);
- Array.Reverse(P);
byte[] S = P;
// iv.
- return new BigInteger(1, S);
+ return new BigInteger(1, S, bigEndian: false);
}
private static void CheckArgs(IBlockCipher cipher, bool isFF1, int radix, ushort[] buf, int off, int len)
diff --git a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
index 9e14702d1..2b3fe702b 100644
--- a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
+++ b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Generators
public DesEdeKeyGenerator()
{
}
-
+
internal DesEdeKeyGenerator(
int defaultStrength)
: base(defaultStrength)
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Crypto.Generators
random.NextBytes(newKey);
DesEdeParameters.SetOddParity(newKey);
}
- while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length) || !DesEdeParameters.IsRealEdeKey(newKey, 0));
+ while (DesEdeParameters.IsWeakKey(newKey) || !DesEdeParameters.IsRealEdeKey(newKey, 0));
return newKey;
}
diff --git a/crypto/src/crypto/parameters/DesEdeParameters.cs b/crypto/src/crypto/parameters/DesEdeParameters.cs
index 19150c6bb..3185f6665 100644
--- a/crypto/src/crypto/parameters/DesEdeParameters.cs
+++ b/crypto/src/crypto/parameters/DesEdeParameters.cs
@@ -74,13 +74,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
* @param key bytes making up the key
* @param offset offset into the byte array the key starts at
*/
- public static new bool IsWeakKey(byte[] key, int offset)
+ public static new bool IsWeakKey(byte[] key, int offset)
{
return IsWeakKey(key, offset, key.Length - offset);
}
- public static new bool IsWeakKey(
- byte[] key)
+ public static new bool IsWeakKey(byte[] key)
{
return IsWeakKey(key, 0, key.Length);
}
diff --git a/crypto/src/crypto/parameters/DesParameters.cs b/crypto/src/crypto/parameters/DesParameters.cs
index dd575604c..6e6f5c62a 100644
--- a/crypto/src/crypto/parameters/DesParameters.cs
+++ b/crypto/src/crypto/parameters/DesParameters.cs
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
* @return true if the given DES key material is weak or semi-weak,
* false otherwise.
*/
- public static bool IsWeakKey(byte[] key, int offset)
+ public static bool IsWeakKey(byte[] key, int offset)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
return IsWeakKey(key.AsSpan(offset));
diff --git a/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
index 6d2e44937..3a760afc1 100644
--- a/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
@@ -70,6 +70,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
public Ed25519PublicKeyParameters GeneratePublicKey()
{
lock (data)
diff --git a/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
index a9d1d0e93..544dbf32d 100644
--- a/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
@@ -70,6 +70,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
public Ed448PublicKeyParameters GeneratePublicKey()
{
lock (data)
diff --git a/crypto/src/crypto/parameters/KeyParameter.cs b/crypto/src/crypto/parameters/KeyParameter.cs
index bd2482f22..c29dfe61b 100644
--- a/crypto/src/crypto/parameters/KeyParameter.cs
+++ b/crypto/src/crypto/parameters/KeyParameter.cs
@@ -85,5 +85,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
internal ReadOnlySpan<byte> Key => m_key;
#endif
+
+ internal KeyParameter Reverse()
+ {
+ var reversed = new KeyParameter(m_key.Length);
+ Arrays.Reverse(m_key, reversed.m_key);
+ return reversed;
+ }
}
}
diff --git a/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
index 8b263c861..ca989a8d3 100644
--- a/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
@@ -68,6 +68,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
public X25519PublicKeyParameters GeneratePublicKey()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
index 5d94ac10a..c68be3060 100644
--- a/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
@@ -60,6 +60,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
private static byte[] Validate(byte[] buf)
{
if (buf.Length != KeySize)
diff --git a/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
index 555773b10..712885875 100644
--- a/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
@@ -68,6 +68,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
public X448PublicKeyParameters GeneratePublicKey()
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/crypto/parameters/X448PublicKeyParameters.cs b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
index 94db22147..e66056f9c 100644
--- a/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
@@ -60,6 +60,12 @@ namespace Org.BouncyCastle.Crypto.Parameters
return Arrays.Clone(data);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal ReadOnlySpan<byte> DataSpan => data;
+
+ internal ReadOnlyMemory<byte> DataMemory => data;
+#endif
+
private static byte[] Validate(byte[] buf)
{
if (buf.Length != KeySize)
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index fd5fa4818..ba6969e39 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -68,8 +68,7 @@ namespace Org.BouncyCastle.Crypto.Signers
if (!forSigning)
throw new InvalidOperationException("not initialized for signing");
- byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
- BigInteger e = new BigInteger(1, mRev);
+ BigInteger e = new BigInteger(1, message, bigEndian: false);
ECDomainParameters ec = key.Parameters;
BigInteger n = ec.N;
@@ -113,8 +112,7 @@ namespace Org.BouncyCastle.Crypto.Signers
if (forSigning)
throw new InvalidOperationException("not initialized for verification");
- byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
- BigInteger e = new BigInteger(1, mRev);
+ BigInteger e = new BigInteger(1, message, bigEndian: false);
BigInteger n = key.Parameters.N;
// r in the range [1,n-1]
diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs
index 03aab0b04..0d80737d0 100644
--- a/crypto/src/crypto/signers/GOST3410Signer.cs
+++ b/crypto/src/crypto/signers/GOST3410Signer.cs
@@ -61,11 +61,9 @@ namespace Org.BouncyCastle.Crypto.Signers
*
* @param message the message that will be verified later.
*/
- public virtual BigInteger[] GenerateSignature(
- byte[] message)
+ public virtual BigInteger[] GenerateSignature(byte[] message)
{
- byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
- BigInteger m = new BigInteger(1, mRev);
+ BigInteger m = new BigInteger(1, message, bigEndian: false);
Gost3410Parameters parameters = key.Parameters;
BigInteger k;
@@ -89,13 +87,9 @@ namespace Org.BouncyCastle.Crypto.Signers
* the passed in message for standard Gost3410 the message should be a
* Gost3411 hash of the real message to be verified.
*/
- public virtual bool VerifySignature(
- byte[] message,
- BigInteger r,
- BigInteger s)
+ public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
{
- byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
- BigInteger m = new BigInteger(1, mRev);
+ BigInteger m = new BigInteger(1, message, bigEndian: false);
Gost3410Parameters parameters = key.Parameters;
if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0)
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 99c15484c..a4f8a834f 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -578,6 +578,25 @@ namespace Org.BouncyCastle.Crypto.Utilities
#endif
}
+ internal static uint LE_To_UInt32_High(byte[] bs, int off, int len)
+ {
+ return LE_To_UInt32_Low(bs, off, len) << ((4 - len) << 3);
+ }
+
+ internal static uint LE_To_UInt32_Low(byte[] bs, int off, int len)
+ {
+ Debug.Assert(1 <= len && len <= 4);
+
+ uint result = bs[off];
+ int pos = 0;
+ for (int i = 1; i < len; ++i)
+ {
+ pos += 8;
+ result |= (uint)bs[off + i] << pos;
+ }
+ return result;
+ }
+
internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
{
for (int i = 0; i < ns.Length; ++i)
@@ -826,6 +845,27 @@ namespace Org.BouncyCastle.Crypto.Utilities
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static uint LE_To_UInt32_High(ReadOnlySpan<byte> bs)
+ {
+ return LE_To_UInt32_Low(bs) << ((4 - bs.Length) << 3);
+ }
+
+ internal static uint LE_To_UInt32_Low(ReadOnlySpan<byte> bs)
+ {
+ int len = bs.Length;
+ Debug.Assert(1 <= len && len <= 4);
+
+ uint result = bs[0];
+ int pos = 0;
+ for (int i = 1; i < len; ++i)
+ {
+ pos += 8;
+ result |= (uint)bs[i] << pos;
+ }
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong LE_To_UInt64(ReadOnlySpan<byte> bs)
{
return BinaryPrimitives.ReadUInt64LittleEndian(bs);
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs
index d84680de5..7da886c4f 100644
--- a/crypto/src/math/BigInteger.cs
+++ b/crypto/src/math/BigInteger.cs
@@ -475,8 +475,15 @@ namespace Org.BouncyCastle.Math
}
public BigInteger(byte[] bytes)
- : this(bytes, 0, bytes.Length)
{
+ this.magnitude = InitBE(bytes, 0, bytes.Length, out this.sign);
+ }
+
+ public BigInteger(byte[] bytes, bool bigEndian)
+ {
+ this.magnitude = bigEndian
+ ? InitBE(bytes, 0, bytes.Length, out this.sign)
+ : InitLE(bytes, 0, bytes.Length, out this.sign);
}
public BigInteger(byte[] bytes, int offset, int length)
@@ -484,16 +491,30 @@ namespace Org.BouncyCastle.Math
if (length == 0)
throw new FormatException("Zero length BigInteger");
- // TODO Move this processing into MakeMagnitude (provide sign argument)
+ this.magnitude = InitBE(bytes, offset, length, out this.sign);
+ }
+
+ public BigInteger(byte[] bytes, int offset, int length, bool bigEndian)
+ {
+ if (length <= 0)
+ throw new FormatException("Zero length BigInteger");
+
+ this.magnitude = bigEndian
+ ? InitBE(bytes, offset, length, out this.sign)
+ : InitLE(bytes, offset, length, out this.sign);
+ }
+
+ private static uint[] InitBE(byte[] bytes, int offset, int length, out int sign)
+ {
+ // TODO Move this processing into MakeMagnitudeBE (provide sign argument)
if ((sbyte)bytes[offset] >= 0)
{
- // strip leading zero bytes and return magnitude bytes
- this.magnitude = MakeMagnitude(bytes, offset, length);
- this.sign = this.magnitude.Length > 0 ? 1 : 0;
- return;
+ uint[] magnitude = MakeMagnitudeBE(bytes, offset, length);
+ sign = magnitude.Length > 0 ? 1 : 0;
+ return magnitude;
}
- this.sign = -1;
+ sign = -1;
int end = offset + length;
@@ -504,10 +525,7 @@ namespace Org.BouncyCastle.Math
}
if (iBval >= end)
- {
- this.magnitude = One.magnitude;
- return;
- }
+ return One.magnitude;
int numBytes = end - iBval;
@@ -534,124 +552,210 @@ namespace Org.BouncyCastle.Math
inverse[index]++;
- this.magnitude = MakeMagnitude(inverse);
- }
-
- private static uint[] MakeMagnitude(byte[] bytes)
- {
- return MakeMagnitude(bytes, 0, bytes.Length);
+ return MakeMagnitudeBE(inverse);
}
- private static uint[] MakeMagnitude(byte[] bytes, int offset, int length)
+ private static uint[] InitLE(byte[] bytes, int offset, int length, out int sign)
{
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- return MakeMagnitude(bytes.AsSpan(offset, length));
-#else
int end = offset + length;
- // strip leading zeros
- int firstSignificant;
- for (firstSignificant = offset; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++)
+ // TODO Move this processing into MakeMagnitudeLE (provide sign argument)
+ if ((sbyte)bytes[end - 1] >= 0)
{
+ uint[] magnitude = MakeMagnitudeLE(bytes, offset, length);
+ sign = magnitude.Length > 0 ? 1 : 0;
+ return magnitude;
}
- if (firstSignificant >= end)
- return ZeroMagnitude;
+ sign = -1;
- int nInts = (end - firstSignificant + 3) / BytesPerInt;
- int bCount = (end - firstSignificant) % BytesPerInt;
- if (bCount == 0)
+ // strip leading sign bytes
+ int last = length;
+ while (--last >= 0 && bytes[offset + last] == byte.MaxValue)
{
- bCount = BytesPerInt;
}
- if (nInts < 1)
- return ZeroMagnitude;
+ if (last < 0)
+ return One.magnitude;
- uint[] mag = new uint[nInts];
+ int numBytes = last + 1;
- uint v = 0U;
- int magnitudeIndex = 0;
- for (int i = firstSignificant; i < end; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> inverse = numBytes <= 512
+ ? stackalloc byte[numBytes]
+ : new byte[numBytes];
+#else
+ byte[] inverse = new byte[numBytes];
+#endif
+
+ for (int i = 0; i < numBytes; ++i)
{
- v <<= 8;
- v |= bytes[i];
- bCount--;
- if (bCount <= 0)
- {
- mag[magnitudeIndex] = v;
- magnitudeIndex++;
- bCount = BytesPerInt;
- v = 0U;
- }
+ inverse[i] = (byte)~bytes[offset + i];
+ }
+
+ int index = 0;
+ while (inverse[index] == byte.MaxValue)
+ {
+ inverse[index++] = byte.MinValue;
}
- if (magnitudeIndex < mag.Length)
+ inverse[index]++;
+
+ return MakeMagnitudeLE(inverse);
+ }
+
+ private static uint[] MakeMagnitudeBE(byte[] bytes)
+ {
+ return MakeMagnitudeBE(bytes, 0, bytes.Length);
+ }
+
+ private static uint[] MakeMagnitudeBE(byte[] bytes, int offset, int length)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return MakeMagnitudeBE(bytes.AsSpan(offset, length));
+#else
+ int end = offset + length;
+
+ // strip leading zeros
+ int start;
+ for (start = offset; start < end && bytes[start] == 0; start++)
{
- mag[magnitudeIndex] = v;
}
- return mag;
+ int nBytes = end - start;
+ if (nBytes <= 0)
+ return ZeroMagnitude;
+
+ int nInts = (nBytes + BytesPerInt - 1) / BytesPerInt;
+ Debug.Assert(nInts > 0);
+
+ uint[] magnitude = new uint[nInts];
+
+ int first = ((nBytes - 1) % BytesPerInt) + 1;
+ magnitude[0] = Pack.BE_To_UInt32_Low(bytes, start, first);
+ Pack.BE_To_UInt32(bytes, start + first, magnitude, 1, nInts - 1);
+
+ return magnitude;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- private static uint[] MakeMagnitude(ReadOnlySpan<byte> bytes)
+ private static uint[] MakeMagnitudeBE(ReadOnlySpan<byte> bytes)
{
int end = bytes.Length;
// strip leading zeros
- int firstSignificant;
- for (firstSignificant = 0; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++)
+ int start;
+ for (start = 0; start < end && bytes[start] == 0; start++)
{
}
- if (firstSignificant >= end)
+ int nBytes = end - start;
+ if (nBytes <= 0)
return ZeroMagnitude;
- int nInts = (end - firstSignificant + 3) / BytesPerInt;
- int bCount = (end - firstSignificant) % BytesPerInt;
- if (bCount == 0)
+ int nInts = (nBytes + BytesPerInt - 1) / BytesPerInt;
+ Debug.Assert(nInts > 0);
+
+ uint[] magnitude = new uint[nInts];
+
+ int first = ((nBytes - 1) % BytesPerInt) + 1;
+ magnitude[0] = Pack.BE_To_UInt32_Low(bytes.Slice(start, first));
+ Pack.BE_To_UInt32(bytes.Slice(start + first), magnitude.AsSpan(1));
+
+ return magnitude;
+ }
+#endif
+
+ private static uint[] MakeMagnitudeLE(byte[] bytes)
+ {
+ return MakeMagnitudeLE(bytes, 0, bytes.Length);
+ }
+
+ private static uint[] MakeMagnitudeLE(byte[] bytes, int offset, int length)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return MakeMagnitudeLE(bytes.AsSpan(offset, length));
+#else
+ // strip leading zeros
+ int last = length;
+ while (--last >= 0 && bytes[offset + last] == 0)
{
- bCount = BytesPerInt;
}
- if (nInts < 1)
+ if (last < 0)
return ZeroMagnitude;
- uint[] mag = new uint[nInts];
+ int nInts = (last + BytesPerInt) / BytesPerInt;
+ Debug.Assert(nInts > 0);
- uint v = 0;
- int magnitudeIndex = 0;
- for (int i = firstSignificant; i < end; ++i)
+ uint[] magnitude = new uint[nInts];
+
+ int partial = last % BytesPerInt;
+ int first = partial + 1;
+ int pos = offset + last - partial;
+
+ magnitude[0] = Pack.LE_To_UInt32_Low(bytes, pos, first);
+ for (int i = 1; i < nInts; ++i)
+ {
+ pos -= BytesPerInt;
+ magnitude[i] = Pack.LE_To_UInt32(bytes, pos);
+ }
+ Debug.Assert(pos == offset);
+
+ return magnitude;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private static uint[] MakeMagnitudeLE(ReadOnlySpan<byte> bytes)
+ {
+ // strip leading zeros
+ int last = bytes.Length;
+ while (--last >= 0 && bytes[last] == 0)
{
- v <<= 8;
- v |= bytes[i];
- bCount--;
- if (bCount <= 0)
- {
- mag[magnitudeIndex] = v;
- magnitudeIndex++;
- bCount = BytesPerInt;
- v = 0U;
- }
}
- if (magnitudeIndex < mag.Length)
+ if (last < 0)
+ return ZeroMagnitude;
+
+ int nInts = (last + BytesPerInt) / BytesPerInt;
+ Debug.Assert(nInts > 0);
+
+ uint[] magnitude = new uint[nInts];
+
+ int partial = last % BytesPerInt;
+ int first = partial + 1;
+ int pos = last - partial;
+
+ magnitude[0] = Pack.LE_To_UInt32_Low(bytes.Slice(pos, first));
+ for (int i = 1; i < nInts; ++i)
{
- mag[magnitudeIndex] = v;
+ pos -= BytesPerInt;
+ magnitude[i] = Pack.LE_To_UInt32(bytes, pos);
}
+ Debug.Assert(pos == 0);
- return mag;
+ return magnitude;
}
#endif
public BigInteger(int sign, byte[] bytes)
- : this(sign, bytes, 0, bytes.Length)
+ : this(sign, bytes, 0, bytes.Length, true)
+ {
+ }
+
+ public BigInteger(int sign, byte[] bytes, bool bigEndian)
+ : this(sign, bytes, 0, bytes.Length, bigEndian)
{
}
public BigInteger(int sign, byte[] bytes, int offset, int length)
+ : this(sign, bytes, offset, length, true)
+ {
+ }
+
+ public BigInteger(int sign, byte[] bytes, int offset, int length, bool bigEndian)
{
if (sign < -1 || sign > 1)
throw new FormatException("Invalid sign value");
@@ -664,13 +768,20 @@ namespace Org.BouncyCastle.Math
else
{
// copy bytes
- this.magnitude = MakeMagnitude(bytes, offset, length);
+ this.magnitude = bigEndian
+ ? MakeMagnitudeBE(bytes, offset, length)
+ : MakeMagnitudeLE(bytes, offset, length);
this.sign = this.magnitude.Length < 1 ? 0 : sign;
}
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public BigInteger(int sign, ReadOnlySpan<byte> bytes)
+ : this(sign, bytes, true)
+ {
+ }
+
+ public BigInteger(int sign, ReadOnlySpan<byte> bytes, bool bigEndian)
{
if (sign < -1 || sign > 1)
throw new FormatException("Invalid sign value");
@@ -683,7 +794,9 @@ namespace Org.BouncyCastle.Math
else
{
// copy bytes
- this.magnitude = MakeMagnitude(bytes);
+ this.magnitude = bigEndian
+ ? MakeMagnitudeBE(bytes)
+ : MakeMagnitudeLE(bytes);
this.sign = this.magnitude.Length < 1 ? 0 : sign;
}
}
@@ -719,7 +832,7 @@ namespace Org.BouncyCastle.Math
int xBits = BitsPerByte * nBytes - sizeInBits;
b[0] &= (byte)(255U >> xBits);
- this.magnitude = MakeMagnitude(b);
+ this.magnitude = MakeMagnitudeBE(b);
this.sign = this.magnitude.Length < 1 ? 0 : 1;
}
@@ -766,7 +879,7 @@ namespace Org.BouncyCastle.Math
// ensure the trailing bit is 1 (i.e. must be odd)
b[nBytes - 1] |= 1;
- this.magnitude = MakeMagnitude(b);
+ this.magnitude = MakeMagnitudeBE(b);
this.nBits = -1;
if (certainty < 1)
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index 61d060b4e..f4d91b180 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -2747,14 +2747,9 @@ namespace Org.BouncyCastle.Math.Raw
? stackalloc byte[bsLen]
: new byte[bsLen];
- int xPos = len;
- Span<byte> t = bs;
- while (--xPos >= 0)
- {
- Pack.UInt32_To_BE(x[xPos], t);
- t = t[4..];
- }
- return new BigInteger(1, bs);
+ Pack.UInt32_To_LE(x, bs);
+
+ return new BigInteger(1, bs, bigEndian: false);
}
#endif
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
index a6482db6c..ac847ddb6 100644
--- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -149,9 +149,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
byte[] secret = new byte[agreement.AgreementSize];
agreement.CalculateAgreement(cryptoPublicKey, secret, 0);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> ephPubEncoding = stackalloc byte[1 + X25519PublicKeyParameters.KeySize];
+ ((X25519PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding[1..]);
+#else
byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KeySize];
- ephPubEncoding[0] = 0x40;
((X25519PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding, 1);
+#endif
+ ephPubEncoding[0] = 0x40;
return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random);
}
@@ -168,9 +173,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
byte[] secret = new byte[agreement.AgreementSize];
agreement.CalculateAgreement(cryptoPublicKey, secret, 0);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> ephPubEncoding = stackalloc byte[1 + X448PublicKeyParameters.KeySize];
+ ((X448PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding[1..]);
+#else
byte[] ephPubEncoding = new byte[1 + X448PublicKeyParameters.KeySize];
- ephPubEncoding[0] = 0x40;
((X448PublicKeyParameters)ephKp.Public).Encode(ephPubEncoding, 1);
+#endif
+ ephPubEncoding[0] = 0x40;
return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random);
}
@@ -188,13 +198,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
BigInteger S = agreement.CalculateAgreement(cryptoPublicKey);
byte[] secret = BigIntegers.AsUnsignedByteArray(agreement.GetFieldSize(), S);
- byte[] ephPubEncoding = ((ECPublicKeyParameters)ephKp.Public).Q.GetEncoded(false);
+ var q = ((ECPublicKeyParameters)ephKp.Public).Q;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int encodedLength = q.GetEncodedLength(false);
+ Span<byte> ephPubEncoding = encodedLength <= 512
+ ? stackalloc byte[encodedLength]
+ : new byte[encodedLength];
+ q.EncodeTo(false, ephPubEncoding);
+#else
+ byte[] ephPubEncoding = q.GetEncoded(false);
+#endif
+
return EncryptSessionInfo(ecPubKey, sessionInfo, secret, ephPubEncoding, random);
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private byte[] EncryptSessionInfo(ECDHPublicBcpgKey ecPubKey, byte[] sessionInfo, byte[] secret,
+ ReadOnlySpan<byte> ephPubEncoding, SecureRandom random)
+#else
private byte[] EncryptSessionInfo(ECDHPublicBcpgKey ecPubKey, byte[] sessionInfo, byte[] secret,
byte[] ephPubEncoding, SecureRandom random)
+#endif
{
var key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, secret));
@@ -402,14 +428,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
sessionInfo[sessionInfo.Length - 1] = (byte)(check);
}
- private byte[] CreateSessionInfo(
- SymmetricKeyAlgorithmTag algorithm,
- KeyParameter key)
+ private byte[] CreateSessionInfo(SymmetricKeyAlgorithmTag algorithm, KeyParameter key)
{
- byte[] keyBytes = key.GetKey();
- byte[] sessionInfo = new byte[keyBytes.Length + 3];
- sessionInfo[0] = (byte) algorithm;
- keyBytes.CopyTo(sessionInfo, 1);
+ int keyLength = key.KeyLength;
+ byte[] sessionInfo = new byte[keyLength + 3];
+ sessionInfo[0] = (byte)algorithm;
+ key.CopyTo(sessionInfo, 1, keyLength);
AddCheckSum(sessionInfo);
return sessionInfo;
}
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index 8b3575909..fa924ff37 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -575,8 +575,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(curveOid),
- // TODO Span variant
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ pEnc.AsSpan(1)));
+#else
Arrays.CopyOfRange(pEnc, 1, pEnc.Length)));
+#endif
}
else if (EdECObjectIdentifiers.id_X448.Equals(curveOid))
{
@@ -586,8 +589,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(curveOid),
- // TODO Span variant
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ pEnc.AsSpan(1)));
+#else
Arrays.CopyOfRange(pEnc, 1, pEnc.Length)));
+#endif
}
else
{
@@ -608,8 +614,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(curveOid),
- // TODO Span variant
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ pEnc.AsSpan(1)));
+#else
Arrays.CopyOfRange(pEnc, 1, pEnc.Length)));
+#endif
}
else if (EdECObjectIdentifiers.id_Ed448.Equals(curveOid))
{
@@ -619,8 +628,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return PublicKeyFactory.CreateKey(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(curveOid),
- // TODO Span variant
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ pEnc.AsSpan(1)));
+#else
Arrays.CopyOfRange(pEnc, 1, pEnc.Length)));
+#endif
}
else
{
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 627b6788a..184621b5c 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -67,9 +67,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
else
{
- // 'reverse' because the native format for X25519 private keys is little-endian
+ // 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())));
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ secKey = new ECSecretBcpgKey(new BigInteger(1, xK.DataSpan, bigEndian: false));
+#else
+ secKey = new ECSecretBcpgKey(new BigInteger(1, xK.GetEncoded(), bigEndian: false));
+#endif
}
break;
}
@@ -81,11 +85,19 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
{
if (privKey.Key is Ed25519PrivateKeyParameters ed25519K)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ secKey = new EdSecretBcpgKey(new BigInteger(1, ed25519K.DataSpan));
+#else
secKey = new EdSecretBcpgKey(new BigInteger(1, ed25519K.GetEncoded()));
+#endif
}
else if (privKey.Key is Ed448PrivateKeyParameters ed448K)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ secKey = new EdSecretBcpgKey(new BigInteger(1, ed448K.DataSpan));
+#else
secKey = new EdSecretBcpgKey(new BigInteger(1, ed448K.GetEncoded()));
+#endif
}
else
{
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index d56831f35..1bfeedb79 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -112,18 +112,28 @@ namespace Org.BouncyCastle.Pkcs
return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object(), attributes);
}
- if (privateKey is ECPrivateKeyParameters)
+ if (privateKey is ECPrivateKeyParameters priv)
{
- ECPrivateKeyParameters priv = (ECPrivateKeyParameters) privateKey;
- DerBitString publicKey = new DerBitString(ECKeyPairGenerator.GetCorrespondingPublicKey(priv).Q.GetEncoded(false));
+ var pub = ECKeyPairGenerator.GetCorrespondingPublicKey(priv);
+ var q = pub.Q;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int encodedLength = q.GetEncodedLength(false);
+ Span<byte> pubEncoding = encodedLength <= 512
+ ? stackalloc byte[encodedLength]
+ : new byte[encodedLength];
+ q.EncodeTo(false, pubEncoding);
+#else
+ byte[] pubEncoding = q.GetEncoded(false);
+#endif
+
+ DerBitString publicKey = new DerBitString(pubEncoding);
ECDomainParameters dp = priv.Parameters;
// ECGOST3410
- if (dp is ECGost3410Parameters)
+ if (dp is ECGost3410Parameters domainParameters)
{
- ECGost3410Parameters domainParameters = (ECGost3410Parameters) dp;
-
Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
(domainParameters).PublicKeyParamSet,
(domainParameters).DigestParamSet,
diff --git a/crypto/src/pqc/asn1/KyberPublicKey.cs b/crypto/src/pqc/asn1/KyberPublicKey.cs
new file mode 100644
index 000000000..9f162e334
--- /dev/null
+++ b/crypto/src/pqc/asn1/KyberPublicKey.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Asn1
+{
+ /**
+ * Crystal Kyber Public Key Format.
+ * See https://www.ietf.org/archive/id/draft-uni-qsckeys-kyber-00.html for details.
+ * <pre>
+ * KyberPublicKey ::= SEQUENCE {
+ * t OCTET STRING,
+ * rho OCTET STRING
+ * }
+ * </pre>
+ */
+ [Obsolete("Will be removed as this draft proposal was rejected")]
+ public sealed class KyberPublicKey
+ : Asn1Encodable
+ {
+ public static KyberPublicKey GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is KyberPublicKey kyberPublicKey)
+ return kyberPublicKey;
+ return new KyberPublicKey(Asn1Sequence.GetInstance(obj));
+ }
+
+ public static KyberPublicKey GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+ }
+
+ private readonly byte[] m_t;
+ private readonly byte[] m_rho;
+
+ public KyberPublicKey(byte[] t, byte[] rho)
+ {
+ m_t = t;
+ m_rho = rho;
+ }
+
+ private KyberPublicKey(Asn1Sequence seq)
+ {
+ m_t = Arrays.Clone(Asn1OctetString.GetInstance(seq[0]).GetOctets());
+ m_rho = Arrays.Clone(Asn1OctetString.GetInstance(seq[1]).GetOctets());
+ }
+
+ public byte[] T => Arrays.Clone(m_t);
+
+ public byte[] Rho => Arrays.Clone(m_rho);
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(new DerOctetString(m_t), new DerOctetString(m_rho));
+ }
+ }
+}
diff --git a/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs b/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
index 3c9849799..909b93577 100644
--- a/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
@@ -21,6 +21,7 @@ using Org.BouncyCastle.Pqc.Crypto.Saber;
using Org.BouncyCastle.Pqc.Crypto.Sike;
using Org.BouncyCastle.Pqc.Crypto.SphincsPlus;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Pqc.Crypto.Utilities
{
@@ -153,18 +154,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
/// <exception cref="IOException"> on an error decoding the key</exception>
public static AsymmetricKeyParameter CreateKey(SubjectPublicKeyInfo keyInfo, object defaultParams)
{
- AlgorithmIdentifier algId = keyInfo.AlgorithmID;
- SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)Converters[algId.Algorithm];
+ var algID = keyInfo.AlgorithmID;
+ var oid = algID.Algorithm;
- if (converter != null)
- {
- return converter.GetPublicKeyParameters(keyInfo, defaultParams);
- }
- else
- {
- throw new IOException("algorithm identifier in public key not recognised: " + algId.Algorithm);
- }
+ SubjectPublicKeyInfoConverter converter = CollectionUtilities.GetValueOrNull(Converters, oid)
+ ?? throw new IOException("algorithm identifier in public key not recognised: " + oid);
+
+ return converter.GetPublicKeyParameters(keyInfo, defaultParams);
}
+
private abstract class SubjectPublicKeyInfoConverter
{
internal abstract AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams);
@@ -294,24 +292,24 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
private class KyberConverter
: SubjectPublicKeyInfoConverter
{
- internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams)
+ internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo,
+ object defaultParams)
{
KyberParameters kyberParameters = PqcUtilities.KyberParamsLookup(keyInfo.AlgorithmID.Algorithm);
- Asn1Object obj = keyInfo.ParsePublicKey();
- if (obj is Asn1Sequence)
+ try
{
- Asn1Sequence keySeq = Asn1Sequence.GetInstance(obj);
+ Asn1Object obj = keyInfo.ParsePublicKey();
+#pragma warning disable CS0618 // Type or member is obsolete
+ KyberPublicKey kyberKey = KyberPublicKey.GetInstance(obj);
+#pragma warning restore CS0618 // Type or member is obsolete
- return new KyberPublicKeyParameters(kyberParameters,
- Asn1OctetString.GetInstance(keySeq[0]).GetOctets(),
- Asn1OctetString.GetInstance(keySeq[1]).GetOctets());
+ return new KyberPublicKeyParameters(kyberParameters, kyberKey.T, kyberKey.Rho);
}
- else
+ catch (Exception)
{
- byte[] encKey = Asn1OctetString.GetInstance(obj).GetOctets();
-
- return new KyberPublicKeyParameters(kyberParameters, encKey);
+ // we're a raw encoding
+ return new KyberPublicKeyParameters(kyberParameters, keyInfo.PublicKeyData.GetOctets());
}
}
}
diff --git a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
index 672108789..c13255c68 100644
--- a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
@@ -115,10 +115,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
{
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
PqcUtilities.KyberOidLookup(kyberPublicKeyParameters.Parameters));
- Asn1EncodableVector v = new Asn1EncodableVector(2);
- v.Add(new DerOctetString(kyberPublicKeyParameters.T));
- v.Add(new DerOctetString(kyberPublicKeyParameters.Rho));
- return new SubjectPublicKeyInfo(algorithmIdentifier, new DerSequence(v));
+
+ return new SubjectPublicKeyInfo(algorithmIdentifier, kyberPublicKeyParameters.GetEncoded());
}
if (publicKey is DilithiumPublicKeyParameters dilithiumPublicKeyParameters)
{
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index 38e571cd6..d6fa87943 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -151,7 +151,7 @@ namespace Org.BouncyCastle.Security
Asn1OctetString privEnc = keyInfo.PrivateKeyData;
if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64)
{
- d = new BigInteger(1, Arrays.Reverse(privEnc.GetOctets()));
+ d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false);
}
else
{
@@ -162,8 +162,8 @@ namespace Org.BouncyCastle.Security
}
else
{
- byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets());
- d = new BigInteger(1, dVal);
+ byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets();
+ d = new BigInteger(1, dVal, bigEndian: false);
}
}
}
@@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Security
}
else
{
- x = new BigInteger(1, Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()));
+ x = new BigInteger(1, Asn1OctetString.GetInstance(privKey).GetOctets(), bigEndian: false);
}
return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
@@ -280,8 +280,7 @@ namespace Org.BouncyCastle.Security
Asn1OctetString privEnc = keyInfo.PrivateKeyData;
if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64)
{
- byte[] dVal = Arrays.Reverse(privEnc.GetOctets());
- d = new BigInteger(1, dVal);
+ d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false);
}
else
{
@@ -292,8 +291,8 @@ namespace Org.BouncyCastle.Security
}
else
{
- byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets());
- d = new BigInteger(1, dVal);
+ byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets();
+ d = new BigInteger(1, dVal, bigEndian: false);
}
}
}
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index 03cabbb13..d3ecef5c7 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -203,9 +203,9 @@ namespace Org.BouncyCastle.Security
throw new ArgumentException("error recovering GOST3410_94 public key", e);
}
- byte[] keyBytes = Arrays.Reverse(key.GetOctets()); // was little endian
+ byte[] keyBytes = key.GetOctets();
- BigInteger y = new BigInteger(1, keyBytes);
+ BigInteger y = new BigInteger(1, keyBytes, bigEndian: false);
return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
}
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 83fafb388..f99065512 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -958,6 +958,15 @@ namespace Org.BouncyCastle.Utilities
return result;
}
+ internal static void Reverse<T>(T[] input, T[] output)
+ {
+ int last = input.Length - 1;
+ for (int i = 0; i <= last; ++i)
+ {
+ output[i] = input[last - i];
+ }
+ }
+
public static T[] ReverseInPlace<T>(T[] array)
{
if (null == array)
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index fc0492fe4..36facc3aa 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -174,7 +174,17 @@ namespace Org.BouncyCastle.X509
x962 = new X962Parameters(_key.PublicKeyParamSet);
}
- byte[] pubKey = _key.Q.GetEncoded(false);
+ var q = _key.Q;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int encodedLength = q.GetEncodedLength(false);
+ Span<byte> pubKey = encodedLength <= 512
+ ? stackalloc byte[encodedLength]
+ : new byte[encodedLength];
+ q.EncodeTo(false, pubKey);
+#else
+ byte[] pubKey = q.GetEncoded(false);
+#endif
AlgorithmIdentifier algID = new AlgorithmIdentifier(
X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
@@ -212,14 +222,22 @@ namespace Org.BouncyCastle.X509
{
X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.DataSpan);
+#else
return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.GetEncoded());
+#endif
}
if (publicKey is X25519PublicKeyParameters)
{
X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.DataSpan);
+#else
return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.GetEncoded());
+#endif
}
if (publicKey is Ed448PublicKeyParameters)
|