summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/pkcs/EncryptionScheme.cs32
-rw-r--r--crypto/src/asn1/x509/NameConstraints.cs6
-rw-r--r--crypto/src/asn1/x509/SubjectPublicKeyInfo.cs10
-rw-r--r--crypto/src/bcpg/ContainedPacket.cs10
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs21
-rw-r--r--crypto/src/bcpg/SecretKeyPacket.cs38
-rw-r--r--crypto/src/crypto/fpe/FpeFf3_1Engine.cs17
-rw-r--r--crypto/src/crypto/fpe/SP80038G.cs3
-rw-r--r--crypto/src/crypto/generators/DesEdeKeyGenerator.cs4
-rw-r--r--crypto/src/crypto/parameters/DesEdeParameters.cs5
-rw-r--r--crypto/src/crypto/parameters/DesParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs6
-rw-r--r--crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs6
-rw-r--r--crypto/src/crypto/parameters/KeyParameter.cs7
-rw-r--r--crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs6
-rw-r--r--crypto/src/crypto/parameters/X25519PublicKeyParameters.cs6
-rw-r--r--crypto/src/crypto/parameters/X448PrivateKeyParameters.cs6
-rw-r--r--crypto/src/crypto/parameters/X448PublicKeyParameters.cs6
-rw-r--r--crypto/src/crypto/signers/ECGOST3410Signer.cs6
-rw-r--r--crypto/src/crypto/signers/GOST3410Signer.cs14
-rw-r--r--crypto/src/crypto/util/Pack.cs40
-rw-r--r--crypto/src/math/BigInteger.cs273
-rw-r--r--crypto/src/math/raw/Nat.cs11
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataGenerator.cs44
-rw-r--r--crypto/src/openpgp/PgpPublicKey.cs20
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs16
-rw-r--r--crypto/src/pkcs/PrivateKeyInfoFactory.cs22
-rw-r--r--crypto/src/pqc/asn1/KyberPublicKey.cs60
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs40
-rw-r--r--crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs6
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs15
-rw-r--r--crypto/src/security/PublicKeyFactory.cs4
-rw-r--r--crypto/src/util/Arrays.cs9
-rw-r--r--crypto/src/x509/SubjectPublicKeyInfoFactory.cs20
34 files changed, 549 insertions, 242 deletions
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)