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/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/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/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/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)
|