diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index 52467fabe..a2d57bf9d 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -199,38 +199,27 @@ namespace Org.BouncyCastle.Asn1
{
int tagNo = input[0] & 0x1f;
int index = 1;
- //
- // with tagged object tag number is bottom 5 bits, or stored at the start of the content
- //
+
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
if (tagNo == 0x1f)
{
- tagNo = 0;
-
- int b = input[index++] & 0xff;
+ int b = input[index++];
- // X.690-0207 8.1.2.4.2
+ // X.690-0207 8.1.2.4.2
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
if ((b & 0x7f) == 0) // Note: -1 will pass
- {
- throw new InvalidOperationException("corrupted stream - invalid high tag number found");
- }
+ throw new IOException("corrupted stream - invalid high tag number found");
- while ((b >= 0) && ((b & 0x80) != 0))
+ while ((b & 0x80) != 0)
{
- tagNo |= (b & 0x7f);
- tagNo <<= 7;
- b = input[index++] & 0xff;
+ b = input[index++];
}
-
- tagNo |= (b & 0x7f);
}
- byte[] tmp = new byte[input.Length - index + 1];
-
- Array.Copy(input, index, tmp, 1, tmp.Length - 1);
-
- tmp[0] = (byte)newTag;
-
+ int remaining = input.Length - index;
+ byte[] tmp = new byte[1 + remaining];
+ tmp[0] = (byte)newTag;
+ Array.Copy(input, index, tmp, 1, remaining);
return tmp;
}
}
diff --git a/crypto/src/asn1/edec/EdECObjectIdentifiers.cs b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
new file mode 100644
index 000000000..f8c5713d8
--- /dev/null
+++ b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.EdEC
+{
+ /**
+ * Edwards Elliptic Curve Object Identifiers (RFC 8410)
+ */
+ public abstract class EdECObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier id_edwards_curve_algs = new DerObjectIdentifier("1.3.101");
+
+ public static readonly DerObjectIdentifier id_X25519 = id_edwards_curve_algs.Branch("110");
+ public static readonly DerObjectIdentifier id_X448 = id_edwards_curve_algs.Branch("111");
+ public static readonly DerObjectIdentifier id_Ed25519 = id_edwards_curve_algs.Branch("112");
+ public static readonly DerObjectIdentifier id_Ed448 = id_edwards_curve_algs.Branch("113");
+ }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptionScheme.cs b/crypto/src/asn1/pkcs/EncryptionScheme.cs
index 7b90ece53..34d26e172 100644
--- a/crypto/src/asn1/pkcs/EncryptionScheme.cs
+++ b/crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -8,7 +8,13 @@ namespace Org.BouncyCastle.Asn1.Pkcs
public class EncryptionScheme
: AlgorithmIdentifier
{
- public EncryptionScheme(
+ public EncryptionScheme(
+ DerObjectIdentifier objectID)
+ : base(objectID)
+ {
+ }
+
+ public EncryptionScheme(
DerObjectIdentifier objectID,
Asn1Encodable parameters)
: base(objectID, parameters)
diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
index c5be7a315..dfb332fdd 100644
--- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -4,15 +4,55 @@ using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Asn1.Pkcs
{
+ /**
+ * RFC 5958
+ *
+ * <pre>
+ * [IMPLICIT TAGS]
+ *
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] PublicKey OPTIONAL ]],
+ * ...
+ * }
+ *
+ * PrivateKeyInfo ::= OneAsymmetricKey
+ *
+ * Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
+ *
+ * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ * { PUBLIC-KEY,
+ * { PrivateKeyAlgorithms } }
+ *
+ * PrivateKey ::= OCTET STRING
+ * -- Content varies based on type of key. The
+ * -- algorithm identifier dictates the format of
+ * -- the key.
+ *
+ * PublicKey ::= BIT STRING
+ * -- Content varies based on type of key. The
+ * -- algorithm identifier dictates the format of
+ * -- the key.
+ *
+ * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ * </pre>
+ */
public class PrivateKeyInfo
: Asn1Encodable
{
- private readonly Asn1OctetString privKey;
- private readonly AlgorithmIdentifier algID;
- private readonly Asn1Set attributes;
+ private readonly DerInteger version;
+ private readonly AlgorithmIdentifier privateKeyAlgorithm;
+ private readonly Asn1OctetString privateKey;
+ private readonly Asn1Set attributes;
+ private readonly DerBitString publicKey;
public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly)
{
@@ -25,110 +65,139 @@ namespace Org.BouncyCastle.Asn1.Pkcs
if (obj == null)
return null;
if (obj is PrivateKeyInfo)
- return (PrivateKeyInfo) obj;
+ return (PrivateKeyInfo)obj;
return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
}
- public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Encodable privateKey)
- : this(algID, privateKey, null)
+ private static int GetVersionValue(DerInteger version)
+ {
+ BigInteger bigValue = version.Value;
+ if (bigValue.CompareTo(BigInteger.Zero) < 0 || bigValue.CompareTo(BigInteger.One) > 0)
+ throw new ArgumentException("invalid version for private key info", "version");
+
+ return bigValue.IntValue;
+ }
+
+ public PrivateKeyInfo(
+ AlgorithmIdentifier privateKeyAlgorithm,
+ Asn1Encodable privateKey)
+ : this(privateKeyAlgorithm, privateKey, null, null)
{
}
public PrivateKeyInfo(
- AlgorithmIdentifier algID,
- Asn1Encodable privateKey,
- Asn1Set attributes)
+ AlgorithmIdentifier privateKeyAlgorithm,
+ Asn1Encodable privateKey,
+ Asn1Set attributes)
+ : this(privateKeyAlgorithm, privateKey, attributes, null)
{
- this.algID = algID;
- this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der));
+ }
+
+ public PrivateKeyInfo(
+ AlgorithmIdentifier privateKeyAlgorithm,
+ Asn1Encodable privateKey,
+ Asn1Set attributes,
+ byte[] publicKey)
+ {
+ this.version = new DerInteger(publicKey != null ? BigInteger.One : BigInteger.Zero);
+ this.privateKeyAlgorithm = privateKeyAlgorithm;
+ this.privateKey = new DerOctetString(privateKey);
this.attributes = attributes;
+ this.publicKey = publicKey == null ? null : new DerBitString(publicKey);
}
private PrivateKeyInfo(Asn1Sequence seq)
{
IEnumerator e = seq.GetEnumerator();
- e.MoveNext();
- BigInteger version = ((DerInteger)e.Current).Value;
- if (version.IntValue != 0)
- {
- throw new ArgumentException("wrong version for private key info: " + version.IntValue);
- }
+ this.version = DerInteger.GetInstance(CollectionUtilities.RequireNext(e));
- e.MoveNext();
- algID = AlgorithmIdentifier.GetInstance(e.Current);
- e.MoveNext();
- privKey = Asn1OctetString.GetInstance(e.Current);
+ int versionValue = GetVersionValue(version);
- if (e.MoveNext())
+ this.privateKeyAlgorithm = AlgorithmIdentifier.GetInstance(CollectionUtilities.RequireNext(e));
+ this.privateKey = Asn1OctetString.GetInstance(CollectionUtilities.RequireNext(e));
+
+ int lastTag = -1;
+ while (e.MoveNext())
{
- attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+ Asn1TaggedObject tagged = (Asn1TaggedObject)e.Current;
+
+ int tag = tagged.TagNo;
+ if (tag <= lastTag)
+ throw new ArgumentException("invalid optional field in private key info", "seq");
+
+ lastTag = tag;
+
+ switch (tag)
+ {
+ case 0:
+ {
+ this.attributes = Asn1Set.GetInstance(tagged, false);
+ break;
+ }
+ case 1:
+ {
+ if (versionValue < 1)
+ throw new ArgumentException("'publicKey' requires version v2(1) or later", "seq");
+
+ this.publicKey = DerBitString.GetInstance(tagged, false);
+ break;
+ }
+ default:
+ {
+ throw new ArgumentException("unknown optional field in private key info", "seq");
+ }
+ }
}
}
- public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+ public virtual Asn1Set Attributes
{
- get { return algID; }
+ get { return attributes; }
}
- [Obsolete("Use 'PrivateKeyAlgorithm' property instead")]
- public virtual AlgorithmIdentifier AlgorithmID
+ /// <summary>Return true if a public key is present, false otherwise.</summary>
+ public virtual bool HasPublicKey
{
- get { return algID; }
+ get { return publicKey != null; }
+ }
+
+ public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+ {
+ get { return privateKeyAlgorithm; }
}
public virtual Asn1Object ParsePrivateKey()
{
- return Asn1Object.FromByteArray(privKey.GetOctets());
+ return Asn1Object.FromByteArray(privateKey.GetOctets());
}
- [Obsolete("Use 'ParsePrivateKey' instead")]
- public virtual Asn1Object PrivateKey
+ /// <summary>For when the public key is an ASN.1 encoding.</summary>
+ public virtual Asn1Object ParsePublicKey()
{
- get
- {
- try
- {
- return ParsePrivateKey();
- }
- catch (IOException)
- {
- throw new InvalidOperationException("unable to parse private key");
- }
- }
+ return publicKey == null ? null : Asn1Object.FromByteArray(publicKey.GetOctets());
}
- public virtual Asn1Set Attributes
+ /// <summary>Return the public key as a raw bit string.</summary>
+ public virtual DerBitString PublicKeyData
{
- get { return attributes; }
+ get { return publicKey; }
}
- /**
- * write out an RSA private key with its associated information
- * as described in Pkcs8.
- * <pre>
- * PrivateKeyInfo ::= Sequence {
- * version Version,
- * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
- * privateKey PrivateKey,
- * attributes [0] IMPLICIT Attributes OPTIONAL
- * }
- * Version ::= Integer {v1(0)} (v1,...)
- *
- * PrivateKey ::= OCTET STRING
- *
- * Attributes ::= Set OF Attr
- * </pre>
- */
public override Asn1Object ToAsn1Object()
{
- Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey);
+ Asn1EncodableVector v = new Asn1EncodableVector(version, privateKeyAlgorithm, privateKey);
if (attributes != null)
{
v.Add(new DerTaggedObject(false, 0, attributes));
}
+ if (publicKey != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, publicKey));
+ }
+
return new DerSequence(v);
}
}
diff --git a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
index 721299105..738a97eb4 100644
--- a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
+++ b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -9,14 +9,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
public class RsaPrivateKeyStructure
: Asn1Encodable
{
- private readonly BigInteger modulus;
- private readonly BigInteger publicExponent;
- private readonly BigInteger privateExponent;
- private readonly BigInteger prime1;
- private readonly BigInteger prime2;
- private readonly BigInteger exponent1;
- private readonly BigInteger exponent2;
- private readonly BigInteger coefficient;
+ private readonly BigInteger modulus;
+ private readonly BigInteger publicExponent;
+ private readonly BigInteger privateExponent;
+ private readonly BigInteger prime1;
+ private readonly BigInteger prime2;
+ private readonly BigInteger exponent1;
+ private readonly BigInteger exponent2;
+ private readonly BigInteger coefficient;
public static RsaPrivateKeyStructure GetInstance(Asn1TaggedObject obj, bool isExplicit)
{
@@ -33,14 +33,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
}
public RsaPrivateKeyStructure(
- BigInteger modulus,
- BigInteger publicExponent,
- BigInteger privateExponent,
- BigInteger prime1,
- BigInteger prime2,
- BigInteger exponent1,
- BigInteger exponent2,
- BigInteger coefficient)
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger prime1,
+ BigInteger prime2,
+ BigInteger exponent1,
+ BigInteger exponent2,
+ BigInteger coefficient)
{
this.modulus = modulus;
this.publicExponent = publicExponent;
@@ -56,18 +56,18 @@ namespace Org.BouncyCastle.Asn1.Pkcs
public RsaPrivateKeyStructure(
Asn1Sequence seq)
{
- BigInteger version = ((DerInteger) seq[0]).Value;
+ BigInteger version = ((DerInteger)seq[0]).Value;
if (version.IntValue != 0)
throw new ArgumentException("wrong version for RSA private key");
- modulus = ((DerInteger) seq[1]).Value;
- publicExponent = ((DerInteger) seq[2]).Value;
- privateExponent = ((DerInteger) seq[3]).Value;
- prime1 = ((DerInteger) seq[4]).Value;
- prime2 = ((DerInteger) seq[5]).Value;
- exponent1 = ((DerInteger) seq[6]).Value;
- exponent2 = ((DerInteger) seq[7]).Value;
- coefficient = ((DerInteger) seq[8]).Value;
+ modulus = ((DerInteger)seq[1]).Value;
+ publicExponent = ((DerInteger)seq[2]).Value;
+ privateExponent = ((DerInteger)seq[3]).Value;
+ prime1 = ((DerInteger)seq[4]).Value;
+ prime2 = ((DerInteger)seq[5]).Value;
+ exponent1 = ((DerInteger)seq[6]).Value;
+ exponent2 = ((DerInteger)seq[7]).Value;
+ coefficient = ((DerInteger)seq[8]).Value;
}
public BigInteger Modulus
diff --git a/crypto/src/asn1/x509/TBSCertificateStructure.cs b/crypto/src/asn1/x509/TBSCertificateStructure.cs
index 9df078539..e69e985f5 100644
--- a/crypto/src/asn1/x509/TBSCertificateStructure.cs
+++ b/crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -121,7 +121,7 @@ namespace Org.BouncyCastle.Asn1.X509
while (extras > 0)
{
- DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+ DerTaggedObject extra = (DerTaggedObject)seq[seqStart + 6 + extras];
switch (extra.TagNo)
{
@@ -140,9 +140,13 @@ namespace Org.BouncyCastle.Asn1.X509
if (isV2)
throw new ArgumentException("version 2 certificate cannot contain extensions");
- extensions = X509Extensions.GetInstance(extra);
+ extensions = X509Extensions.GetInstance(Asn1Sequence.GetInstance(extra, true));
break;
}
+ default:
+ {
+ throw new ArgumentException("Unknown tag encountered in structure: " + extra.TagNo);
+ }
}
extras--;
}
diff --git a/crypto/src/bcpg/ECPublicBCPGKey.cs b/crypto/src/bcpg/ECPublicBCPGKey.cs
index f328f9dc3..c473139e7 100644
--- a/crypto/src/bcpg/ECPublicBCPGKey.cs
+++ b/crypto/src/bcpg/ECPublicBCPGKey.cs
@@ -26,7 +26,7 @@ namespace Org.BouncyCastle.Bcpg
DerObjectIdentifier oid,
ECPoint point)
{
- this.point = new BigInteger(1, point.GetEncoded());
+ this.point = new BigInteger(1, point.GetEncoded(false));
this.oid = oid;
}
diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs
index dad128263..39ecfa6d3 100644
--- a/crypto/src/cms/SignerInformation.cs
+++ b/crypto/src/cms/SignerInformation.cs
@@ -84,6 +84,30 @@ namespace Org.BouncyCastle.Cms
this.digestCalculator = digestCalculator;
}
+ /**
+ * Protected constructor. In some cases clients have their own idea about how to encode
+ * the signed attributes and calculate the signature. This constructor is to allow developers
+ * to deal with that by extending off the class and overridng methods like getSignedAttributes().
+ *
+ * @param baseInfo the SignerInformation to base this one on.
+ */
+ protected SignerInformation(SignerInformation baseInfo)
+ {
+ this.info = baseInfo.info;
+ this.contentType = baseInfo.contentType;
+ this.isCounterSignature = baseInfo.IsCounterSignature;
+ this.sid = baseInfo.SignerID;
+ this.digestAlgorithm = info.DigestAlgorithm;
+ this.signedAttributeSet = info.AuthenticatedAttributes;
+ this.unsignedAttributeSet = info.UnauthenticatedAttributes;
+ this.encryptionAlgorithm = info.DigestEncryptionAlgorithm;
+ this.signature = info.EncryptedDigest.GetOctets();
+ this.content = baseInfo.content;
+ this.resultDigest = baseInfo.resultDigest;
+ this.signedAttributeTable = baseInfo.signedAttributeTable;
+ this.unsignedAttributeTable = baseInfo.unsignedAttributeTable;
+ }
+
public bool IsCounterSignature
{
get { return isCounterSignature; }
diff --git a/crypto/src/crypto/IRawAgreement.cs b/crypto/src/crypto/IRawAgreement.cs
new file mode 100644
index 000000000..63e664888
--- /dev/null
+++ b/crypto/src/crypto/IRawAgreement.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface IRawAgreement
+ {
+ void Init(ICipherParameters parameters);
+
+ int AgreementSize { get; }
+
+ void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off);
+ }
+}
diff --git a/crypto/src/crypto/agreement/X25519Agreement.cs b/crypto/src/crypto/agreement/X25519Agreement.cs
new file mode 100644
index 000000000..7e5890c16
--- /dev/null
+++ b/crypto/src/crypto/agreement/X25519Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public sealed class X25519Agreement
+ : IRawAgreement
+ {
+ private X25519PrivateKeyParameters privateKey;
+
+ public void Init(ICipherParameters parameters)
+ {
+ this.privateKey = (X25519PrivateKeyParameters)parameters;
+ }
+
+ public int AgreementSize
+ {
+ get { return X25519PrivateKeyParameters.SecretSize; }
+ }
+
+ public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+ {
+ privateKey.GenerateSecret((X25519PublicKeyParameters)publicKey, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/agreement/X448Agreement.cs b/crypto/src/crypto/agreement/X448Agreement.cs
new file mode 100644
index 000000000..26f608c26
--- /dev/null
+++ b/crypto/src/crypto/agreement/X448Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public sealed class X448Agreement
+ : IRawAgreement
+ {
+ private X448PrivateKeyParameters privateKey;
+
+ public void Init(ICipherParameters parameters)
+ {
+ this.privateKey = (X448PrivateKeyParameters)parameters;
+ }
+
+ public int AgreementSize
+ {
+ get { return X448PrivateKeyParameters.SecretSize; }
+ }
+
+ public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+ {
+ privateKey.GenerateSecret((X448PublicKeyParameters)publicKey, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/Blake2bDigest.cs b/crypto/src/crypto/digests/Blake2bDigest.cs
index b8e4f272e..770e35caf 100644
--- a/crypto/src/crypto/digests/Blake2bDigest.cs
+++ b/crypto/src/crypto/digests/Blake2bDigest.cs
@@ -136,8 +136,8 @@ namespace Org.BouncyCastle.Crypto.Digests
*/
public Blake2bDigest(int digestSize)
{
- if (digestSize != 160 && digestSize != 256 && digestSize != 384 && digestSize != 512)
- throw new ArgumentException("BLAKE2b digest restricted to one of [160, 256, 384, 512]");
+ if (digestSize < 8 || digestSize > 512 || digestSize % 8 != 0)
+ throw new ArgumentException("BLAKE2b digest bit length must be a multiple of 8 and not greater than 512");
buffer = new byte[BLOCK_LENGTH_BYTES];
keyLength = 0;
diff --git a/crypto/src/crypto/digests/Blake2sDigest.cs b/crypto/src/crypto/digests/Blake2sDigest.cs
index f31032874..432b0f4d2 100644
--- a/crypto/src/crypto/digests/Blake2sDigest.cs
+++ b/crypto/src/crypto/digests/Blake2sDigest.cs
@@ -152,13 +152,12 @@ namespace Org.BouncyCastle.Crypto.Digests
/**
* BLAKE2s for hashing.
*
- * @param digestBits the desired digest length in bits. Must be one of
- * [128, 160, 224, 256].
+ * @param digestBits the desired digest length in bits. Must be a multiple of 8 and less than 256.
*/
public Blake2sDigest(int digestBits)
{
- if (digestBits != 128 && digestBits != 160 && digestBits != 224 && digestBits != 256)
- throw new ArgumentException("BLAKE2s digest restricted to one of [128, 160, 224, 256]");
+ if (digestBits < 8 || digestBits > 256 || digestBits % 8 != 0)
+ throw new ArgumentException("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256");
buffer = new byte[BLOCK_LENGTH_BYTES];
keyLength = 0;
diff --git a/crypto/src/crypto/digests/NullDigest.cs b/crypto/src/crypto/digests/NullDigest.cs
index e598cb145..76b69afbf 100644
--- a/crypto/src/crypto/digests/NullDigest.cs
+++ b/crypto/src/crypto/digests/NullDigest.cs
@@ -1,6 +1,8 @@
using System;
using System.IO;
+using Org.BouncyCastle.Utilities.IO;
+
namespace Org.BouncyCastle.Crypto.Digests
{
public class NullDigest : IDigest
@@ -20,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Digests
public int GetDigestSize()
{
- return (int) bOut.Length;
+ return (int)bOut.Length;
}
public void Update(byte b)
@@ -33,15 +35,19 @@ namespace Org.BouncyCastle.Crypto.Digests
bOut.Write(inBytes, inOff, len);
}
- public int DoFinal(byte[] outBytes, int outOff)
+ public int DoFinal(byte[] outBytes, int outOff)
{
- byte[] res = bOut.ToArray();
- res.CopyTo(outBytes, outOff);
- Reset();
- return res.Length;
- }
-
- public void Reset()
+ try
+ {
+ return Streams.WriteBufTo(bOut, outBytes, outOff);
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+
+ public void Reset()
{
bOut.SetLength(0);
}
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index 4e3af5227..86480145c 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -32,10 +32,10 @@ namespace Org.BouncyCastle.Crypto.Engines
if (param is ParametersWithRandom)
{
- ParametersWithRandom p = (ParametersWithRandom) param;
+ ParametersWithRandom p = (ParametersWithRandom)param;
- this.rand = p.Random;
- this.param = (ParametersWithIV) p.Parameters;
+ this.rand = p.Random;
+ this.param = p.Parameters as ParametersWithIV;
}
else
{
@@ -44,9 +44,12 @@ namespace Org.BouncyCastle.Crypto.Engines
rand = new SecureRandom();
}
- this.param = (ParametersWithIV) param;
- }
- }
+ this.param = param as ParametersWithIV;
+ }
+
+ if (null == this.param)
+ throw new ArgumentException("RFC3211Wrap requires an IV", "param");
+ }
public virtual string AlgorithmName
{
@@ -59,11 +62,11 @@ namespace Org.BouncyCastle.Crypto.Engines
int inLen)
{
if (!forWrapping)
- {
throw new InvalidOperationException("not set for wrapping");
- }
+ if (inLen > 255 || inLen < 0)
+ throw new ArgumentException("input must be from 0 to 255 bytes", "inLen");
- engine.Init(true, param);
+ engine.Init(true, param);
int blockSize = engine.GetBlockSize();
byte[] cekBlock;
@@ -78,15 +81,16 @@ namespace Org.BouncyCastle.Crypto.Engines
}
cekBlock[0] = (byte)inLen;
- cekBlock[1] = (byte)~inBytes[inOff];
- cekBlock[2] = (byte)~inBytes[inOff + 1];
- cekBlock[3] = (byte)~inBytes[inOff + 2];
Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
- for (int i = 0; i < cekBlock.Length; i += blockSize)
+ cekBlock[1] = (byte)~cekBlock[4];
+ cekBlock[2] = (byte)~cekBlock[4 + 1];
+ cekBlock[3] = (byte)~cekBlock[4 + 2];
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
{
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
@@ -142,27 +146,34 @@ namespace Org.BouncyCastle.Crypto.Engines
engine.ProcessBlock(cekBlock, i, cekBlock, i);
}
- if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
- {
- throw new InvalidCipherTextException("wrapped key corrupted");
- }
+ bool invalidLength = (int)cekBlock[0] > (cekBlock.Length - 4);
- byte[] key = new byte[cekBlock[0] & 0xff];
+ byte[] key;
+ if (invalidLength)
+ {
+ key = new byte[cekBlock.Length - 4];
+ }
+ else
+ {
+ key = new byte[cekBlock[0]];
+ }
- Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
+ Array.Copy(cekBlock, 4, key, 0, key.Length);
// Note: Using constant time comparison
int nonEqual = 0;
for (int i = 0; i != 3; i++)
{
byte check = (byte)~cekBlock[1 + i];
- nonEqual |= (check ^ key[i]);
- }
+ nonEqual |= (check ^ cekBlock[4 + i]);
+ }
+
+ Array.Clear(cekBlock, 0, cekBlock.Length);
- if (nonEqual != 0)
- throw new InvalidCipherTextException("wrapped key fails checksum");
+ if (nonEqual != 0 | invalidLength)
+ throw new InvalidCipherTextException("wrapped key corrupted");
- return key;
+ return key;
}
}
}
diff --git a/crypto/src/crypto/engines/SM4Engine.cs b/crypto/src/crypto/engines/SM4Engine.cs
new file mode 100644
index 000000000..7477b070e
--- /dev/null
+++ b/crypto/src/crypto/engines/SM4Engine.cs
@@ -0,0 +1,189 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /// <summary>SM4 Block Cipher - SM4 is a 128 bit block cipher with a 128 bit key.</summary>
+ /// <remarks>
+ /// The implementation here is based on the document <a href="http://eprint.iacr.org/2008/329.pdf">http://eprint.iacr.org/2008/329.pdf</a>
+ /// by Whitfield Diffie and George Ledin, which is a translation of Prof. LU Shu-wang's original standard.
+ /// </remarks>
+ public class SM4Engine
+ : IBlockCipher
+ {
+ private const int BlockSize = 16;
+
+ private static readonly byte[] Sbox =
+ {
+ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
+ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
+ 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
+ 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
+ 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
+ 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
+ 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
+ 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
+ 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
+ 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
+ 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
+ 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
+ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
+ 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
+ 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
+ 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
+ };
+
+ private static readonly uint[] CK =
+ {
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
+ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
+ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
+ 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
+ 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
+ 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
+ 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
+ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
+ };
+
+ private static readonly uint[] FK =
+ {
+ 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
+ };
+
+ private uint[] rk;
+
+ // non-linear substitution tau.
+ private static uint tau(uint A)
+ {
+ uint b0 = Sbox[A >> 24];
+ uint b1 = Sbox[(A >> 16) & 0xFF];
+ uint b2 = Sbox[(A >> 8) & 0xFF];
+ uint b3 = Sbox[A & 0xFF];
+
+ return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+ }
+
+ private static uint L_ap(uint B)
+ {
+ return B ^ Integers.RotateLeft(B, 13) ^ Integers.RotateLeft(B, 23);
+ }
+
+ private uint T_ap(uint Z)
+ {
+ return L_ap(tau(Z));
+ }
+
+ // Key expansion
+ private void ExpandKey(bool forEncryption, byte[] key)
+ {
+ uint K0 = Pack.BE_To_UInt32(key, 0) ^ FK[0];
+ uint K1 = Pack.BE_To_UInt32(key, 4) ^ FK[1];
+ uint K2 = Pack.BE_To_UInt32(key, 8) ^ FK[2];
+ uint K3 = Pack.BE_To_UInt32(key, 12) ^ FK[3];
+
+ if (forEncryption)
+ {
+ rk[0] = K0 ^ T_ap(K1 ^ K2 ^ K3 ^ CK[0]);
+ rk[1] = K1 ^ T_ap(K2 ^ K3 ^ rk[0] ^ CK[1]);
+ rk[2] = K2 ^ T_ap(K3 ^ rk[0] ^ rk[1] ^ CK[2]);
+ rk[3] = K3 ^ T_ap(rk[0] ^ rk[1] ^ rk[2] ^ CK[3]);
+ for (int i = 4; i < 32; ++i)
+ {
+ rk[i] = rk[i - 4] ^ T_ap(rk[i - 3] ^ rk[i - 2] ^ rk[i - 1] ^ CK[i]);
+ }
+ }
+ else
+ {
+ rk[31] = K0 ^ T_ap(K1 ^ K2 ^ K3 ^ CK[0]);
+ rk[30] = K1 ^ T_ap(K2 ^ K3 ^ rk[31] ^ CK[1]);
+ rk[29] = K2 ^ T_ap(K3 ^ rk[31] ^ rk[30] ^ CK[2]);
+ rk[28] = K3 ^ T_ap(rk[31] ^ rk[30] ^ rk[29] ^ CK[3]);
+ for (int i = 27; i >= 0; --i)
+ {
+ rk[i] = rk[i + 4] ^ T_ap(rk[i + 3] ^ rk[i + 2] ^ rk[i + 1] ^ CK[31 - i]);
+ }
+ }
+ }
+
+ // Linear substitution L
+ private static uint L(uint B)
+ {
+ return B ^ Integers.RotateLeft(B, 2) ^ Integers.RotateLeft(B, 10) ^ Integers.RotateLeft(B, 18) ^ Integers.RotateLeft(B, 24);
+ }
+
+ // Mixer-substitution T
+ private static uint T(uint Z)
+ {
+ return L(tau(Z));
+ }
+
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+ if (null == keyParameter)
+ throw new ArgumentException("invalid parameter passed to SM4 init - " + Platform.GetTypeName(parameters), "parameters");
+
+ byte[] key = keyParameter.GetKey();
+ if (key.Length != 16)
+ throw new ArgumentException("SM4 requires a 128 bit key", "parameters");
+
+ if (null == rk)
+ {
+ rk = new uint[32];
+ }
+
+ ExpandKey(forEncryption, key);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "SM4"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ if (null == rk)
+ throw new InvalidOperationException("SM4 not initialised");
+
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ uint X0 = Pack.BE_To_UInt32(input, inOff);
+ uint X1 = Pack.BE_To_UInt32(input, inOff + 4);
+ uint X2 = Pack.BE_To_UInt32(input, inOff + 8);
+ uint X3 = Pack.BE_To_UInt32(input, inOff + 12);
+
+ for (int i = 0; i < 32; i += 4)
+ {
+ X0 ^= T(X1 ^ X2 ^ X3 ^ rk[i ]); // F0
+ X1 ^= T(X2 ^ X3 ^ X0 ^ rk[i + 1]); // F1
+ X2 ^= T(X3 ^ X0 ^ X1 ^ rk[i + 2]); // F2
+ X3 ^= T(X0 ^ X1 ^ X2 ^ rk[i + 3]); // F3
+ }
+
+ Pack.UInt32_To_BE(X3, output, outOff);
+ Pack.UInt32_To_BE(X2, output, outOff + 4);
+ Pack.UInt32_To_BE(X1, output, outOff + 8);
+ Pack.UInt32_To_BE(X0, output, outOff + 12);
+
+ return BlockSize;
+ }
+
+ public virtual void Reset()
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
new file mode 100644
index 000000000..266d111cf
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class Ed25519KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(random);
+ Ed25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
new file mode 100644
index 000000000..50aee631e
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class Ed448KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ Ed448PrivateKeyParameters privateKey = new Ed448PrivateKeyParameters(random);
+ Ed448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/X25519KeyPairGenerator.cs b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
new file mode 100644
index 000000000..94378448b
--- /dev/null
+++ b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class X25519KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ X25519PrivateKeyParameters privateKey = new X25519PrivateKeyParameters(random);
+ X25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/X448KeyPairGenerator.cs b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
new file mode 100644
index 000000000..4a203e4f1
--- /dev/null
+++ b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class X448KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ X448PrivateKeyParameters privateKey = new X448PrivateKeyParameters(random);
+ X448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..daf3856c3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Ed25519KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public Ed25519KeyGenerationParameters(SecureRandom random)
+ : base(random, 256)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..97902e093
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
@@ -0,0 +1,98 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed25519PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed25519.SecretKeySize;
+ public static readonly int SignatureSize = Ed25519.SignatureSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed25519PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public Ed25519PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed25519PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed25519 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public Ed25519PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[Ed25519.PublicKeySize];
+ Ed25519.GeneratePublicKey(data, 0, publicKey, 0);
+ return new Ed25519PublicKeyParameters(publicKey, 0);
+ }
+
+ public void Sign(Ed25519.Algorithm algorithm, Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+ byte[] sig, int sigOff)
+ {
+ byte[] pk = new byte[Ed25519.PublicKeySize];
+ if (null == publicKey)
+ {
+ Ed25519.GeneratePublicKey(data, 0, pk, 0);
+ }
+ else
+ {
+ publicKey.Encode(pk, 0);
+ }
+
+ switch (algorithm)
+ {
+ case Ed25519.Algorithm.Ed25519:
+ {
+ if (null != ctx)
+ throw new ArgumentException("ctx");
+
+ Ed25519.Sign(data, 0, pk, 0, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed25519.Algorithm.Ed25519ctx:
+ {
+ Ed25519.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed25519.Algorithm.Ed25519ph:
+ {
+ if (Ed25519.PrehashSize != msgLen)
+ throw new ArgumentException("msgLen");
+
+ Ed25519.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+ break;
+ }
+ default:
+ {
+ throw new ArgumentException("algorithm");
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
new file mode 100644
index 000000000..96e9ec21f
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed25519PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed25519.PublicKeySize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed25519PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed25519PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed25519 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
new file mode 100644
index 000000000..830d15a04
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Ed448KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public Ed448KeyGenerationParameters(SecureRandom random)
+ : base(random, 448)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
new file mode 100644
index 000000000..74b5d63f3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed448PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed448.SecretKeySize;
+ public static readonly int SignatureSize = Ed448.SignatureSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed448PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public Ed448PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed448PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed448 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public Ed448PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[Ed448.PublicKeySize];
+ Ed448.GeneratePublicKey(data, 0, publicKey, 0);
+ return new Ed448PublicKeyParameters(publicKey, 0);
+ }
+
+ public void Sign(Ed448.Algorithm algorithm, Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+ byte[] sig, int sigOff)
+ {
+ byte[] pk = new byte[Ed448.PublicKeySize];
+ if (null == publicKey)
+ {
+ Ed448.GeneratePublicKey(data, 0, pk, 0);
+ }
+ else
+ {
+ publicKey.Encode(pk, 0);
+ }
+
+ switch (algorithm)
+ {
+ case Ed448.Algorithm.Ed448:
+ {
+ Ed448.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed448.Algorithm.Ed448ph:
+ {
+ if (Ed448.PrehashSize != msgLen)
+ throw new ArgumentException("msgLen");
+
+ Ed448.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+ break;
+ }
+ default:
+ {
+ throw new ArgumentException("algorithm");
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
new file mode 100644
index 000000000..d7faac246
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed448PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed448.PublicKeySize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed448PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed448PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed448 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs b/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
index 7bd8abd76..557ee94e2 100644
--- a/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
+++ b/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
@@ -2,33 +2,34 @@ using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Asn1.Pkcs;
namespace Org.BouncyCastle.Crypto.Parameters
{
public class RsaPrivateCrtKeyParameters
- : RsaKeyParameters
+ : RsaKeyParameters
{
private readonly BigInteger e, p, q, dP, dQ, qInv;
- public RsaPrivateCrtKeyParameters(
- BigInteger modulus,
- BigInteger publicExponent,
- BigInteger privateExponent,
- BigInteger p,
- BigInteger q,
- BigInteger dP,
- BigInteger dQ,
- BigInteger qInv)
- : base(true, modulus, privateExponent)
+ public RsaPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ : base(true, modulus, privateExponent)
{
- ValidateValue(publicExponent, "publicExponent", "exponent");
- ValidateValue(p, "p", "P value");
- ValidateValue(q, "q", "Q value");
- ValidateValue(dP, "dP", "DP value");
- ValidateValue(dQ, "dQ", "DQ value");
- ValidateValue(qInv, "qInv", "InverseQ value");
-
- this.e = publicExponent;
+ ValidateValue(publicExponent, "publicExponent", "exponent");
+ ValidateValue(p, "p", "P value");
+ ValidateValue(q, "q", "Q value");
+ ValidateValue(dP, "dP", "DP value");
+ ValidateValue(dQ, "dQ", "DQ value");
+ ValidateValue(qInv, "qInv", "InverseQ value");
+
+ this.e = publicExponent;
this.p = p;
this.q = q;
this.dP = dP;
@@ -36,69 +37,82 @@ namespace Org.BouncyCastle.Crypto.Parameters
this.qInv = qInv;
}
- public BigInteger PublicExponent
+ public RsaPrivateCrtKeyParameters(RsaPrivateKeyStructure rsaPrivateKey)
+ : this(
+ rsaPrivateKey.Modulus,
+ rsaPrivateKey.PublicExponent,
+ rsaPrivateKey.PrivateExponent,
+ rsaPrivateKey.Prime1,
+ rsaPrivateKey.Prime2,
+ rsaPrivateKey.Exponent1,
+ rsaPrivateKey.Exponent2,
+ rsaPrivateKey.Coefficient)
+ {
+ }
+
+ public BigInteger PublicExponent
{
get { return e; }
- }
-
- public BigInteger P
- {
- get { return p; }
- }
-
- public BigInteger Q
- {
- get { return q; }
- }
-
- public BigInteger DP
- {
- get { return dP; }
- }
-
- public BigInteger DQ
- {
- get { return dQ; }
- }
-
- public BigInteger QInv
- {
- get { return qInv; }
- }
-
- public override bool Equals(
- object obj)
- {
- if (obj == this)
- return true;
-
- RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters;
-
- if (kp == null)
- return false;
-
- return kp.DP.Equals(dP)
- && kp.DQ.Equals(dQ)
- && kp.Exponent.Equals(this.Exponent)
- && kp.Modulus.Equals(this.Modulus)
- && kp.P.Equals(p)
- && kp.Q.Equals(q)
- && kp.PublicExponent.Equals(e)
- && kp.QInv.Equals(qInv);
- }
-
- public override int GetHashCode()
- {
- return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode()
- ^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode();
- }
-
- private static void ValidateValue(BigInteger x, string name, string desc)
- {
- if (x == null)
- throw new ArgumentNullException(name);
- if (x.SignValue <= 0)
- throw new ArgumentException("Not a valid RSA " + desc, name);
- }
- }
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger DP
+ {
+ get { return dP; }
+ }
+
+ public BigInteger DQ
+ {
+ get { return dQ; }
+ }
+
+ public BigInteger QInv
+ {
+ get { return qInv; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters;
+
+ if (kp == null)
+ return false;
+
+ return kp.DP.Equals(dP)
+ && kp.DQ.Equals(dQ)
+ && kp.Exponent.Equals(this.Exponent)
+ && kp.Modulus.Equals(this.Modulus)
+ && kp.P.Equals(p)
+ && kp.Q.Equals(q)
+ && kp.PublicExponent.Equals(e)
+ && kp.QInv.Equals(qInv);
+ }
+
+ public override int GetHashCode()
+ {
+ return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode()
+ ^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode();
+ }
+
+ private static void ValidateValue(BigInteger x, string name, string desc)
+ {
+ if (x == null)
+ throw new ArgumentNullException(name);
+ if (x.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA " + desc, name);
+ }
+ }
}
diff --git a/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..09972c7a2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class X25519KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public X25519KeyGenerationParameters(SecureRandom random)
+ : base(random, 256)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..fb49a02b3
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X25519PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X25519.ScalarSize;
+ public static readonly int SecretSize = X25519.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X25519PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public X25519PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X25519PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X25519 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public X25519PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[X25519.PointSize];
+ X25519.ScalarMultBase(data, 0, publicKey, 0);
+ return new X25519PublicKeyParameters(publicKey, 0);
+ }
+
+ public void GenerateSecret(X25519PublicKeyParameters publicKey, byte[] buf, int off)
+ {
+ byte[] encoded = new byte[X25519.PointSize];
+ publicKey.Encode(encoded, 0);
+ if (!X25519.CalculateAgreement(data, 0, encoded, 0, buf, off))
+ throw new InvalidOperationException("X25519 agreement failed");
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
new file mode 100644
index 000000000..7df5f624d
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X25519PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X25519.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X25519PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X25519PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X25519 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
new file mode 100644
index 000000000..a7cb55844
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class X448KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public X448KeyGenerationParameters(SecureRandom random)
+ : base(random, 448)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
new file mode 100644
index 000000000..d17aa7947
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X448PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X448.ScalarSize;
+ public static readonly int SecretSize = X448.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X448PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public X448PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X448PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X448 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public X448PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[X448.PointSize];
+ X448.ScalarMultBase(data, 0, publicKey, 0);
+ return new X448PublicKeyParameters(publicKey, 0);
+ }
+
+ public void GenerateSecret(X448PublicKeyParameters publicKey, byte[] buf, int off)
+ {
+ byte[] encoded = new byte[X448.PointSize];
+ publicKey.Encode(encoded, 0);
+ if (!X448.CalculateAgreement(data, 0, encoded, 0, buf, off))
+ throw new InvalidOperationException("X448 agreement failed");
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448PublicKeyParameters.cs b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
new file mode 100644
index 000000000..6c566ddf2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X448PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X448.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X448PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X448PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X448 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519Signer.cs b/crypto/src/crypto/signers/Ed25519Signer.cs
new file mode 100644
index 000000000..1b3142c7b
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519Signer.cs
@@ -0,0 +1,129 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519Signer
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519Signer()
+ {
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning || null == privateKey)
+ throw new InvalidOperationException("Ed25519Signer not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning || null == publicKey)
+ throw new InvalidOperationException("Ed25519Signer not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519, publicKey, null, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed25519.Verify(signature, 0, pk, 0, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+ long count = Position;
+#if PORTABLE
+ this.Position = 0L;
+ Streams.WriteZeroes(this, count);
+#else
+ Array.Clear(GetBuffer(), 0, (int)count);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519ctxSigner.cs b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
new file mode 100644
index 000000000..965453011
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
@@ -0,0 +1,131 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519ctxSigner
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519ctxSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519ctx"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning || null == privateKey)
+ throw new InvalidOperationException("Ed25519ctxSigner not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey, context);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning || null == publicKey)
+ throw new InvalidOperationException("Ed25519ctxSigner not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, context, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey, byte[] ctx)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519ctx, publicKey, ctx, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed25519.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+ long count = Position;
+#if PORTABLE
+ this.Position = 0L;
+ Streams.WriteZeroes(this, count);
+#else
+ Array.Clear(GetBuffer(), 0, (int)count);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519phSigner.cs b/crypto/src/crypto/signers/Ed25519phSigner.cs
new file mode 100644
index 000000000..3318f6438
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519phSigner
+ : ISigner
+ {
+ private readonly IDigest prehash = Ed25519.CreatePrehash();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519phSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519ph"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ prehash.Update(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ prehash.BlockUpdate(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning || null == privateKey)
+ throw new InvalidOperationException("Ed25519phSigner not initialised for signature generation.");
+
+ byte[] msg = new byte[Ed25519.PrehashSize];
+ if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
+ throw new InvalidOperationException("Prehash digest failed");
+
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519ph, publicKey, context, msg, 0, Ed25519.PrehashSize, signature, 0);
+ return signature;
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning || null == publicKey)
+ throw new InvalidOperationException("Ed25519phSigner not initialised for verification");
+
+ byte[] pk = publicKey.GetEncoded();
+ return Ed25519.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+ }
+
+ public void Reset()
+ {
+ prehash.Reset();
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed448Signer.cs b/crypto/src/crypto/signers/Ed448Signer.cs
new file mode 100644
index 000000000..d18f956a8
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448Signer.cs
@@ -0,0 +1,131 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed448Signer
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed448PrivateKeyParameters privateKey;
+ private Ed448PublicKeyParameters publicKey;
+
+ public Ed448Signer(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed448"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed448PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed448PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning || null == privateKey)
+ throw new InvalidOperationException("Ed448Signer not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey, context);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning || null == publicKey)
+ throw new InvalidOperationException("Ed448Signer not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, context, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed448PrivateKeyParameters privateKey, Ed448PublicKeyParameters publicKey, byte[] ctx)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed448.Algorithm.Ed448, publicKey, ctx, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed448.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+ long count = Position;
+#if PORTABLE
+ this.Position = 0L;
+ Streams.WriteZeroes(this, count);
+#else
+ Array.Clear(GetBuffer(), 0, (int)count);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed448phSigner.cs b/crypto/src/crypto/signers/Ed448phSigner.cs
new file mode 100644
index 000000000..b86d0855c
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed448phSigner
+ : ISigner
+ {
+ private readonly IXof prehash = Ed448.CreatePrehash();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed448PrivateKeyParameters privateKey;
+ private Ed448PublicKeyParameters publicKey;
+
+ public Ed448phSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed448ph"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+ this.privateKey = (Ed448PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed448PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ prehash.Update(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ prehash.BlockUpdate(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning || null == privateKey)
+ throw new InvalidOperationException("Ed448phSigner not initialised for signature generation.");
+
+ byte[] msg = new byte[Ed448.PrehashSize];
+ if (Ed448.PrehashSize != prehash.DoFinal(msg, 0, Ed448.PrehashSize))
+ throw new InvalidOperationException("Prehash digest failed");
+
+ byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed448.Algorithm.Ed448ph, publicKey, context, msg, 0, Ed448.PrehashSize, signature, 0);
+ return signature;
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning || null == publicKey)
+ throw new InvalidOperationException("Ed448phSigner not initialised for verification");
+
+ byte[] pk = publicKey.GetEncoded();
+ return Ed448.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+ }
+
+ public void Reset()
+ {
+ prehash.Reset();
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 72151d414..bbb76d53c 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -391,31 +391,30 @@ namespace Org.BouncyCastle.Crypto.Tls
if (queue.Available < totalLength)
break;
- CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
-
/*
* RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
* starting at client hello up to, but not including, this finished message.
* [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
*/
- switch (type)
- {
- case HandshakeType.hello_request:
- break;
- case HandshakeType.finished:
- default:
+ if (HandshakeType.hello_request != type)
{
- TlsContext ctx = Context;
- if (type == HandshakeType.finished
- && this.mExpectedVerifyData == null
- && ctx.SecurityParameters.MasterSecret != null)
+ if (HandshakeType.finished == type)
{
- this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
+ CheckReceivedChangeCipherSpec(true);
+
+ TlsContext ctx = Context;
+ if (this.mExpectedVerifyData == null
+ && ctx.SecurityParameters.MasterSecret != null)
+ {
+ this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
+ }
+ }
+ else
+ {
+ CheckReceivedChangeCipherSpec(mConnectionState == CS_END);
}
queue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength);
- break;
- }
}
queue.RemoveData(4);
diff --git a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
index 505832442..37e5b5c29 100644
--- a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
@@ -37,15 +37,17 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
int top = fullComb - 1;
for (int i = 0; i < d; ++i)
{
- int secretIndex = 0;
+ uint secretIndex = 0;
for (int j = top - i; j >= 0; j -= d)
{
+ uint secretBit = K[j >> 5] >> (j & 0x1F);
+ secretIndex ^= secretBit >> 1;
secretIndex <<= 1;
- secretIndex |= (int)Nat.GetBit(K, j);
+ secretIndex ^= secretBit;
}
- ECPoint add = lookupTable.Lookup(secretIndex);
+ ECPoint add = lookupTable.Lookup((int)secretIndex);
R = R.TwicePlus(add);
}
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
index e893abd49..24646deb2 100644
--- a/crypto/src/math/ec/multiplier/WNafUtilities.cs
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Math.EC.Multiplier
{
public abstract class WNafUtilities
@@ -8,8 +10,6 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
- private static readonly byte[] EMPTY_BYTES = new byte[0];
- private static readonly int[] EMPTY_INTS = new int[0];
private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0];
public static int[] GenerateCompactNaf(BigInteger k)
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
if ((k.BitLength >> 16) != 0)
throw new ArgumentException("must have bitlength < 2^16", "k");
if (k.SignValue == 0)
- return EMPTY_INTS;
+ return Arrays.EmptyInts;
BigInteger _3k = k.ShiftLeft(1).Add(k);
@@ -63,7 +63,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
if ((k.BitLength >> 16) != 0)
throw new ArgumentException("must have bitlength < 2^16", "k");
if (k.SignValue == 0)
- return EMPTY_INTS;
+ return Arrays.EmptyInts;
int[] wnaf = new int[k.BitLength / width + 1];
@@ -176,7 +176,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
public static byte[] GenerateNaf(BigInteger k)
{
if (k.SignValue == 0)
- return EMPTY_BYTES;
+ return Arrays.EmptyBytes;
BigInteger _3k = k.ShiftLeft(1).Add(k);
@@ -221,7 +221,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
if (width < 2 || width > 8)
throw new ArgumentException("must be in the range [2, 8]", "width");
if (k.SignValue == 0)
- return EMPTY_BYTES;
+ return Arrays.EmptyBytes;
byte[] wnaf = new byte[k.BitLength + 1];
diff --git a/crypto/src/math/ec/rfc7748/X25519.cs b/crypto/src/math/ec/rfc7748/X25519.cs
index a10d53da5..6b6acdecd 100644
--- a/crypto/src/math/ec/rfc7748/X25519.cs
+++ b/crypto/src/math/ec/rfc7748/X25519.cs
@@ -2,10 +2,15 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Math.EC.Rfc7748
{
public abstract class X25519
{
+ public const int PointSize = 32;
+ public const int ScalarSize = 32;
+
private const int C_A = 486662;
private const int C_A24 = (C_A + 2)/4;
@@ -18,6 +23,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
private static int[] precompBase = null;
+ public static bool CalculateAgreement(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff)
+ {
+ ScalarMult(k, kOff, u, uOff, r, rOff);
+ return !Arrays.AreAllZeroes(r, rOff, PointSize);
+ }
+
private static uint Decode32(byte[] bs, int off)
{
uint n = bs[off];
diff --git a/crypto/src/math/ec/rfc7748/X448.cs b/crypto/src/math/ec/rfc7748/X448.cs
index 88e8a5d76..b93cb24c5 100644
--- a/crypto/src/math/ec/rfc7748/X448.cs
+++ b/crypto/src/math/ec/rfc7748/X448.cs
@@ -2,10 +2,15 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Math.EC.Rfc7748
{
public abstract class X448
{
+ public const int PointSize = 56;
+ public const int ScalarSize = 56;
+
private const uint C_A = 156326;
private const uint C_A24 = (C_A + 2)/4;
@@ -21,6 +26,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
private static uint[] precompBase = null;
+ public static bool CalculateAgreement(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff)
+ {
+ ScalarMult(k, kOff, u, uOff, r, rOff);
+ return !Arrays.AreAllZeroes(r, rOff, PointSize);
+ }
+
private static uint Decode32(byte[] bs, int off)
{
uint n = bs[off];
diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs
index ff4587cb2..f9ba1ff97 100644
--- a/crypto/src/math/ec/rfc8032/Ed25519.cs
+++ b/crypto/src/math/ec/rfc8032/Ed25519.cs
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Math.EC.Rfc7748;
using Org.BouncyCastle.Math.Raw;
@@ -11,6 +12,13 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
{
public abstract class Ed25519
{
+ public enum Algorithm
+ {
+ Ed25519 = 0,
+ Ed25519ctx = 1,
+ Ed25519ph = 2,
+ }
+
private const long M28L = 0x0FFFFFFFL;
private const long M32L = 0xFFFFFFFFL;
@@ -18,11 +26,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
private const int ScalarUints = 8;
private const int ScalarBytes = ScalarUints * 4;
+ public static readonly int PrehashSize = 64;
public static readonly int PublicKeySize = PointBytes;
public static readonly int SecretKeySize = 32;
public static readonly int SignatureSize = PointBytes + ScalarBytes;
- //private static readonly byte[] Dom2Prefix = Strings.ToByteArray("SigEd25519 no Ed25519 collisions");
+ private static readonly byte[] Dom2Prefix = Strings.ToByteArray("SigEd25519 no Ed25519 collisions");
private static readonly uint[] P = { 0xFFFFFFEDU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU };
private static readonly uint[] L = { 0x5CF5D3EDU, 0x5812631AU, 0xA2F79CD6U, 0x14DEF9DEU, 0x00000000U, 0x00000000U, 0x00000000U, 0x10000000U };
@@ -96,6 +105,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
return ReduceScalar(result);
}
+ private static bool CheckContextVar(byte[] ctx, byte phflag)
+ {
+ return ctx == null && phflag == 0x00
+ || ctx != null && ctx.Length < 256;
+ }
+
private static bool CheckPointVar(byte[] p)
{
uint[] t = new uint[8];
@@ -111,6 +126,16 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
return !Nat256.Gte(n, L);
}
+ private static IDigest CreateDigest()
+ {
+ return new Sha512Digest();
+ }
+
+ public static IDigest CreatePrehash()
+ {
+ return CreateDigest();
+ }
+
private static uint Decode24(byte[] bs, int off)
{
uint n = bs[off];
@@ -140,9 +165,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
{
byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes);
if (!CheckPointVar(py))
- {
return false;
- }
int x_0 = (py[PointBytes - 1] & 0x80) >> 7;
py[PointBytes - 1] &= 0x7F;
@@ -158,15 +181,11 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
X25519Field.AddOne(v);
if (!X25519Field.SqrtRatioVar(u, v, r.x))
- {
return false;
- }
X25519Field.Normalize(r.x);
if (x_0 == 1 && X25519Field.IsZeroVar(r.x))
- {
return false;
- }
if (negate ^ (x_0 != (r.x[0] & 1)))
{
@@ -182,6 +201,17 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Decode32(k, kOff, n, 0, ScalarUints);
}
+ private static void Dom2(IDigest d, byte phflag, byte[] ctx)
+ {
+ if (ctx != null)
+ {
+ d.BlockUpdate(Dom2Prefix, 0, Dom2Prefix.Length);
+ d.Update(phflag);
+ d.Update((byte)ctx.Length);
+ d.BlockUpdate(ctx, 0, ctx.Length);
+ }
+ }
+
private static void Encode24(uint n, byte[] bs, int off)
{
bs[off] = (byte)(n);
@@ -220,7 +250,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)
{
- Sha512Digest d = new Sha512Digest();
+ IDigest d = CreateDigest();
byte[] h = new byte[d.GetDigestSize()];
d.BlockUpdate(sk, skOff, SecretKeySize);
@@ -286,8 +316,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
return ws;
}
- private static void ImplSign(Sha512Digest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ private static void ImplSign(IDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
+ Dom2(d, phflag, ctx);
d.BlockUpdate(h, ScalarBytes, ScalarBytes);
d.BlockUpdate(m, mOff, mLen);
d.DoFinal(h, 0);
@@ -296,8 +328,9 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
byte[] R = new byte[PointBytes];
ScalarMultBaseEncoded(r, R, 0);
+ Dom2(d, phflag, ctx);
d.BlockUpdate(R, 0, PointBytes);
- d.BlockUpdate(pk, 0, PointBytes);
+ d.BlockUpdate(pk, pkOff, PointBytes);
d.BlockUpdate(m, mOff, mLen);
d.DoFinal(h, 0);
@@ -308,6 +341,90 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes);
}
+ private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen,
+ byte[] sig, int sigOff)
+ {
+ if (!CheckContextVar(ctx, phflag))
+ throw new ArgumentException("ctx");
+
+ IDigest d = CreateDigest();
+ byte[] h = new byte[d.GetDigestSize()];
+
+ d.BlockUpdate(sk, skOff, SecretKeySize);
+ d.DoFinal(h, 0);
+
+ byte[] s = new byte[ScalarBytes];
+ PruneScalar(h, 0, s);
+
+ byte[] pk = new byte[PointBytes];
+ ScalarMultBaseEncoded(s, pk, 0);
+
+ ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
+
+ private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ {
+ if (!CheckContextVar(ctx, phflag))
+ throw new ArgumentException("ctx");
+
+ IDigest d = CreateDigest();
+ byte[] h = new byte[d.GetDigestSize()];
+
+ d.BlockUpdate(sk, skOff, SecretKeySize);
+ d.DoFinal(h, 0);
+
+ byte[] s = new byte[ScalarBytes];
+ PruneScalar(h, 0, s);
+
+ ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
+
+ private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen)
+ {
+ if (!CheckContextVar(ctx, phflag))
+ throw new ArgumentException("ctx");
+
+ byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes);
+ byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize);
+
+ if (!CheckPointVar(R))
+ return false;
+
+ if (!CheckScalarVar(S))
+ return false;
+
+ PointExt pA = new PointExt();
+ if (!DecodePointVar(pk, pkOff, true, pA))
+ return false;
+
+ IDigest d = CreateDigest();
+ byte[] h = new byte[d.GetDigestSize()];
+
+ Dom2(d, phflag, ctx);
+ d.BlockUpdate(R, 0, PointBytes);
+ d.BlockUpdate(pk, pkOff, PointBytes);
+ d.BlockUpdate(m, mOff, mLen);
+ d.DoFinal(h, 0);
+
+ byte[] k = ReduceScalar(h);
+
+ uint[] nS = new uint[ScalarUints];
+ DecodeScalar(S, 0, nS);
+
+ uint[] nA = new uint[ScalarUints];
+ DecodeScalar(k, 0, nA);
+
+ PointAccum pR = new PointAccum();
+ ScalarMultStraussVar(nS, nA, pA, pR);
+
+ byte[] check = new byte[PointBytes];
+ EncodePoint(pR, check, 0);
+
+ return Arrays.AreEqual(check, R);
+ }
+
private static void PointAddVar(bool negate, PointExt p, PointAccum r)
{
int[] A = X25519Field.Create();
@@ -518,9 +635,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void Precompute()
{
if (precompBase != null)
- {
return;
- }
// Precomputed table for the base point in verification ladder
{
@@ -555,9 +670,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
ds[t] = PointCopy(p);
- for (int s = 1; s < PrecompSpacing; ++s)
+ if (b + t != PrecompBlocks + PrecompTeeth - 2)
{
- PointDouble(p);
+ for (int s = 1; s < PrecompSpacing; ++s)
+ {
+ PointDouble(p);
+ }
}
}
@@ -795,9 +913,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
}
if ((cOff -= PrecompTeeth) < 0)
- {
break;
- }
PointDouble(r);
}
@@ -850,9 +966,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
}
if (--bit < 0)
- {
break;
- }
PointDouble(r);
}
@@ -860,78 +974,101 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void Sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
- Sha512Digest d = new Sha512Digest();
- byte[] h = new byte[d.GetDigestSize()];
+ byte[] ctx = null;
+ byte phflag = 0x00;
- d.BlockUpdate(sk, skOff, SecretKeySize);
- d.DoFinal(h, 0);
+ ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
- byte[] s = new byte[ScalarBytes];
- PruneScalar(h, 0, s);
+ public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ {
+ byte[] ctx = null;
+ byte phflag = 0x00;
- byte[] pk = new byte[PointBytes];
- ScalarMultBaseEncoded(s, pk, 0);
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
+
+ public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ {
+ byte phflag = 0x00;
- ImplSign(d, h, s, pk, 0, m, mOff, mLen, sig, sigOff);
+ ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
- public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
- Sha512Digest d = new Sha512Digest();
- byte[] h = new byte[d.GetDigestSize()];
+ byte phflag = 0x00;
- d.BlockUpdate(sk, skOff, SecretKeySize);
- d.DoFinal(h, 0);
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
- byte[] s = new byte[ScalarBytes];
- PruneScalar(h, 0, s);
+ public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
+ {
+ byte phflag = 0x01;
- ImplSign(d, h, s, pk, pkOff, m, mOff, mLen, sig, sigOff);
+ ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
}
- public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen)
+ public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
{
- byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes);
- byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize);
+ byte phflag = 0x01;
- if (!CheckPointVar(R))
- {
- return false;
- }
- if (!CheckScalarVar(S))
- {
- return false;
- }
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
+ }
- PointExt pA = new PointExt();
- if (!DecodePointVar(pk, pkOff, true, pA))
- {
- return false;
- }
+ public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff)
+ {
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0))
+ throw new ArgumentException("ph");
- Sha512Digest d = new Sha512Digest();
- byte[] h = new byte[d.GetDigestSize()];
+ byte phflag = 0x01;
- d.BlockUpdate(R, 0, PointBytes);
- d.BlockUpdate(pk, pkOff, PointBytes);
- d.BlockUpdate(m, mOff, mLen);
- d.DoFinal(h, 0);
+ ImplSign(sk, skOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
+ }
- byte[] k = ReduceScalar(h);
+ public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff)
+ {
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0))
+ throw new ArgumentException("ph");
- uint[] nS = new uint[ScalarUints];
- DecodeScalar(S, 0, nS);
+ byte phflag = 0x01;
- uint[] nA = new uint[ScalarUints];
- DecodeScalar(k, 0, nA);
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
+ }
- PointAccum pR = new PointAccum();
- ScalarMultStraussVar(nS, nA, pA, pR);
+ public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen)
+ {
+ byte[] ctx = null;
+ byte phflag = 0x00;
- byte[] check = new byte[PointBytes];
- EncodePoint(pR, check, 0);
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
+ }
- return Arrays.AreEqual(check, R);
+ public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)
+ {
+ byte phflag = 0x00;
+
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
+ }
+
+ public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff)
+ {
+ byte phflag = 0x01;
+
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize);
+ }
+
+ public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph)
+ {
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0))
+ throw new ArgumentException("ph");
+
+ byte phflag = 0x01;
+
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.Length);
}
}
}
diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs
index 52c215160..a1f0e93b0 100644
--- a/crypto/src/math/ec/rfc8032/Ed448.cs
+++ b/crypto/src/math/ec/rfc8032/Ed448.cs
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Math.EC.Rfc7748;
using Org.BouncyCastle.Math.Raw;
@@ -11,6 +12,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
{
public abstract class Ed448
{
+ public enum Algorithm
+ {
+ Ed448 = 0,
+ Ed448ph = 1,
+ }
+
private const ulong M26UL = 0x03FFFFFFUL;
private const ulong M28UL = 0x0FFFFFFFUL;
@@ -18,6 +25,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
private const int ScalarUints = 14;
private const int ScalarBytes = ScalarUints * 4 + 1;
+ public static readonly int PrehashSize = 64;
public static readonly int PublicKeySize = PointBytes;
public static readonly int SecretKeySize = 57;
public static readonly int SignatureSize = PointBytes + ScalarBytes;
@@ -103,9 +111,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
private static bool CheckPointVar(byte[] p)
{
if ((p[PointBytes - 1] & 0x7F) != 0x00)
- {
return false;
- }
uint[] t = new uint[14];
Decode32(p, 0, t, 0, 14);
@@ -115,15 +121,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
private static bool CheckScalarVar(byte[] s)
{
if (s[ScalarBytes - 1] != 0x00)
- {
return false;
- }
uint[] n = new uint[ScalarUints];
DecodeScalar(s, 0, n);
return !Nat.Gte(ScalarUints, n, L);
}
+ public static IXof CreatePrehash()
+ {
+ return CreateXof();
+ }
+
+ private static IXof CreateXof()
+ {
+ return new ShakeDigest(256);
+ }
+
private static uint Decode16(byte[] bs, int off)
{
uint n = bs[off];
@@ -160,9 +174,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
{
byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes);
if (!CheckPointVar(py))
- {
return false;
- }
int x_0 = (py[PointBytes - 1] & 0x80) >> 7;
py[PointBytes - 1] &= 0x7F;
@@ -179,15 +191,11 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
X448Field.AddOne(v);
if (!X448Field.SqrtRatioVar(u, v, r.x))
- {
return false;
- }
X448Field.Normalize(r.x);
if (x_0 == 1 && X448Field.IsZeroVar(r.x))
- {
return false;
- }
if (negate ^ (x_0 != (r.x[0] & 1)))
{
@@ -205,7 +213,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Decode32(k, kOff, n, 0, ScalarUints);
}
- private static void Dom4(ShakeDigest d, byte x, byte[] y)
+ private static void Dom4(IXof d, byte x, byte[] y)
{
d.BlockUpdate(Dom4Prefix, 0, Dom4Prefix.Length);
d.Update(x);
@@ -251,7 +259,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)
{
- ShakeDigest d = new ShakeDigest(256);
+ IXof d = CreateXof();
byte[] h = new byte[ScalarBytes * 2];
d.BlockUpdate(sk, skOff, SecretKeySize);
@@ -317,10 +325,9 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
return ws;
}
- private static void ImplSign(ShakeDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ private static void ImplSign(IXof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
- byte phflag = 0x00;
-
Dom4(d, phflag, ctx);
d.BlockUpdate(h, ScalarBytes, ScalarBytes);
d.BlockUpdate(m, mOff, mLen);
@@ -343,6 +350,90 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes);
}
+ private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen,
+ byte[] sig, int sigOff)
+ {
+ if (!CheckContextVar(ctx))
+ throw new ArgumentException("ctx");
+
+ IXof d = CreateXof();
+ byte[] h = new byte[ScalarBytes * 2];
+
+ d.BlockUpdate(sk, skOff, SecretKeySize);
+ d.DoFinal(h, 0, h.Length);
+
+ byte[] s = new byte[ScalarBytes];
+ PruneScalar(h, 0, s);
+
+ byte[] pk = new byte[PointBytes];
+ ScalarMultBaseEncoded(s, pk, 0);
+
+ ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
+
+ private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ {
+ if (!CheckContextVar(ctx))
+ throw new ArgumentException("ctx");
+
+ IXof d = CreateXof();
+ byte[] h = new byte[ScalarBytes * 2];
+
+ d.BlockUpdate(sk, skOff, SecretKeySize);
+ d.DoFinal(h, 0, h.Length);
+
+ byte[] s = new byte[ScalarBytes];
+ PruneScalar(h, 0, s);
+
+ ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
+
+ private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag,
+ byte[] m, int mOff, int mLen)
+ {
+ if (!CheckContextVar(ctx))
+ throw new ArgumentException("ctx");
+
+ byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes);
+ byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize);
+
+ if (!CheckPointVar(R))
+ return false;
+
+ if (!CheckScalarVar(S))
+ return false;
+
+ PointExt pA = new PointExt();
+ if (!DecodePointVar(pk, pkOff, true, pA))
+ return false;
+
+ IXof d = CreateXof();
+ byte[] h = new byte[ScalarBytes * 2];
+
+ Dom4(d, phflag, ctx);
+ d.BlockUpdate(R, 0, PointBytes);
+ d.BlockUpdate(pk, pkOff, PointBytes);
+ d.BlockUpdate(m, mOff, mLen);
+ d.DoFinal(h, 0, h.Length);
+
+ byte[] k = ReduceScalar(h);
+
+ uint[] nS = new uint[ScalarUints];
+ DecodeScalar(S, 0, nS);
+
+ uint[] nA = new uint[ScalarUints];
+ DecodeScalar(k, 0, nA);
+
+ PointExt pR = new PointExt();
+ ScalarMultStraussVar(nS, nA, pA, pR);
+
+ byte[] check = new byte[PointBytes];
+ EncodePoint(pR, check, 0);
+
+ return Arrays.AreEqual(check, R);
+ }
+
private static void PointAddVar(bool negate, PointExt p, PointExt r)
{
uint[] A = X448Field.Create();
@@ -505,9 +596,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void Precompute()
{
if (precompBase != null)
- {
return;
- }
PointExt p = new PointExt();
X448Field.Copy(B_x, 0, p.x, 0);
@@ -533,9 +622,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
ds[t] = PointCopy(p);
- for (int s = 1; s < PrecompSpacing; ++s)
+ if (b + t != PrecompBlocks + PrecompTeeth - 2)
{
- PointDouble(p);
+ for (int s = 1; s < PrecompSpacing; ++s)
+ {
+ PointDouble(p);
+ }
}
}
@@ -888,8 +980,9 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
uint w = 0;
for (int t = 0; t < PrecompTeeth; ++t)
{
- uint tBit = (n[tPos >> 5] >> (tPos & 0x1F)) & 1U;
- w |= tBit << t;
+ uint tBit = n[tPos >> 5] >> (tPos & 0x1F);
+ w &= ~(1U << t);
+ w ^= (tBit << t);
tPos += PrecompSpacing;
}
@@ -907,9 +1000,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
}
if (--cOff < 0)
- {
break;
- }
PointDouble(r);
}
@@ -962,9 +1053,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
}
if (--bit < 0)
- {
break;
- }
PointDouble(r);
}
@@ -972,96 +1061,77 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
- if (!CheckContextVar(ctx))
- {
- throw new ArgumentException("ctx");
- }
+ byte phflag = 0x00;
- ShakeDigest d = new ShakeDigest(256);
- byte[] h = new byte[ScalarBytes * 2];
+ ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
- d.BlockUpdate(sk, skOff, SecretKeySize);
- d.DoFinal(h, 0, h.Length);
+ public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ {
+ byte phflag = 0x00;
- byte[] s = new byte[ScalarBytes];
- PruneScalar(h, 0, s);
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
+ }
- byte[] pk = new byte[PointBytes];
- ScalarMultBaseEncoded(s, pk, 0);
+ public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
+ {
+ byte phflag = 0x01;
- ImplSign(d, h, s, pk, 0, ctx, m, mOff, mLen, sig, sigOff);
+ ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
}
- public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
+ public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
{
- if (!CheckContextVar(ctx))
- {
- throw new ArgumentException("ctx");
- }
+ byte phflag = 0x01;
- ShakeDigest d = new ShakeDigest(256);
- byte[] h = new byte[ScalarBytes * 2];
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
+ }
- d.BlockUpdate(sk, skOff, SecretKeySize);
- d.DoFinal(h, 0, h.Length);
+ public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IXof ph, byte[] sig, int sigOff)
+ {
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0, PrehashSize))
+ throw new ArgumentException("ph");
- byte[] s = new byte[ScalarBytes];
- PruneScalar(h, 0, s);
+ byte phflag = 0x01;
- ImplSign(d, h, s, pk, pkOff, ctx, m, mOff, mLen, sig, sigOff);
+ ImplSign(sk, skOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
}
- public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)
+ public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IXof ph, byte[] sig, int sigOff)
{
- if (!CheckContextVar(ctx))
- {
- throw new ArgumentException("ctx");
- }
-
- byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes);
- byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize);
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0, PrehashSize))
+ throw new ArgumentException("ph");
- if (!CheckPointVar(R))
- {
- return false;
- }
- if (!CheckScalarVar(S))
- {
- return false;
- }
+ byte phflag = 0x01;
- PointExt pA = new PointExt();
- if (!DecodePointVar(pk, pkOff, true, pA))
- {
- return false;
- }
+ ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
+ }
+ public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)
+ {
byte phflag = 0x00;
- ShakeDigest d = new ShakeDigest(256);
- byte[] h = new byte[ScalarBytes * 2];
-
- Dom4(d, phflag, ctx);
- d.BlockUpdate(R, 0, PointBytes);
- d.BlockUpdate(pk, pkOff, PointBytes);
- d.BlockUpdate(m, mOff, mLen);
- d.DoFinal(h, 0, h.Length);
-
- byte[] k = ReduceScalar(h);
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
+ }
- uint[] nS = new uint[ScalarUints];
- DecodeScalar(S, 0, nS);
+ public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff)
+ {
+ byte phflag = 0x01;
- uint[] nA = new uint[ScalarUints];
- DecodeScalar(k, 0, nA);
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize);
+ }
- PointExt pR = new PointExt();
- ScalarMultStraussVar(nS, nA, pA, pR);
+ public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IXof ph)
+ {
+ byte[] m = new byte[PrehashSize];
+ if (PrehashSize != ph.DoFinal(m, 0, PrehashSize))
+ throw new ArgumentException("ph");
- byte[] check = new byte[PointBytes];
- EncodePoint(pR, check, 0);
+ byte phflag = 0x01;
- return Arrays.AreEqual(check, R);
+ return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.Length);
}
}
}
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index 7ca60278a..040ade74f 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -488,21 +488,31 @@ namespace Org.BouncyCastle.Math.Raw
public static void Mul(int len, uint[] x, uint[] y, uint[] zz)
{
- zz[len] = (uint)MulWord(len, x[0], y, zz);
+ zz[len] = MulWord(len, x[0], y, zz);
for (int i = 1; i < len; ++i)
{
- zz[i + len] = (uint)MulWordAddTo(len, x[i], y, 0, zz, i);
+ zz[i + len] = MulWordAddTo(len, x[i], y, 0, zz, i);
}
}
public static void Mul(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
{
- zz[zzOff + len] = (uint)MulWord(len, x[xOff], y, yOff, zz, zzOff);
+ zz[zzOff + len] = MulWord(len, x[xOff], y, yOff, zz, zzOff);
for (int i = 1; i < len; ++i)
{
- zz[zzOff + i + len] = (uint)MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+ zz[zzOff + i + len] = MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, int xLen, uint[] y, int yOff, int yLen, uint[] zz, int zzOff)
+ {
+ zz[zzOff + yLen] = MulWord(yLen, x[xOff], y, yOff, zz, zzOff);
+
+ for (int i = 1; i < xLen; ++i)
+ {
+ zz[zzOff + i + yLen] = MulWordAddTo(yLen, x[xOff + i], y, yOff, zz, zzOff + i);
}
}
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
index 156243f4e..1d3d75941 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return result;
}
- public NotationData[] GetNotationDataOccurences()
+ public NotationData[] GetNotationDataOccurrences()
{
SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData);
NotationData[] vals = new NotationData[notations.Length];
@@ -87,6 +87,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
return vals;
}
+ [Obsolete("Use 'GetNotationDataOccurrences' instead")]
+ public NotationData[] GetNotationDataOccurences()
+ {
+ return GetNotationDataOccurrences();
+ }
+
public long GetIssuerKeyId()
{
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index a349a11d2..69eb3fa67 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -2,6 +2,7 @@ using System;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
@@ -22,59 +23,68 @@ namespace Org.BouncyCastle.Pkcs
}
public static PrivateKeyInfo CreatePrivateKeyInfo(
- AsymmetricKeyParameter key)
+ AsymmetricKeyParameter privateKey)
{
- if (key == null)
- throw new ArgumentNullException("key");
- if (!key.IsPrivate)
- throw new ArgumentException("Public key passed - private key expected", "key");
+ return CreatePrivateKeyInfo(privateKey, null);
+ }
+
+ /**
+ * Create a PrivateKeyInfo representation of a private key with attributes.
+ *
+ * @param privateKey the key to be encoded into the info object.
+ * @param attributes the set of attributes to be included.
+ * @return the appropriate PrivateKeyInfo
+ * @throws java.io.IOException on an error encoding the key
+ */
+ public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey, Asn1Set attributes)
+ {
+ if (privateKey == null)
+ throw new ArgumentNullException("privateKey");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("Public key passed - private key expected", "privateKey");
- if (key is ElGamalPrivateKeyParameters)
+ if (privateKey is ElGamalPrivateKeyParameters)
{
- ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
+ ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)privateKey;
+ ElGamalParameters egp = _key.Parameters;
return new PrivateKeyInfo(
- new AlgorithmIdentifier(
- OiwObjectIdentifiers.ElGamalAlgorithm,
- new ElGamalParameter(
- _key.Parameters.P,
- _key.Parameters.G).ToAsn1Object()),
- new DerInteger(_key.X));
+ new AlgorithmIdentifier(OiwObjectIdentifiers.ElGamalAlgorithm, new ElGamalParameter(egp.P, egp.G).ToAsn1Object()),
+ new DerInteger(_key.X),
+ attributes);
}
- if (key is DsaPrivateKeyParameters)
+ if (privateKey is DsaPrivateKeyParameters)
{
- DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
+ DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)privateKey;
+ DsaParameters dp = _key.Parameters;
return new PrivateKeyInfo(
- new AlgorithmIdentifier(
- X9ObjectIdentifiers.IdDsa,
- new DsaParameter(
- _key.Parameters.P,
- _key.Parameters.Q,
- _key.Parameters.G).ToAsn1Object()),
- new DerInteger(_key.X));
+ new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, new DsaParameter(dp.P, dp.Q, dp.G).ToAsn1Object()),
+ new DerInteger(_key.X),
+ attributes);
}
- if (key is DHPrivateKeyParameters)
+ if (privateKey is DHPrivateKeyParameters)
{
- DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
+ DHPrivateKeyParameters _key = (DHPrivateKeyParameters)privateKey;
DHParameter p = new DHParameter(
_key.Parameters.P, _key.Parameters.G, _key.Parameters.L);
return new PrivateKeyInfo(
new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()),
- new DerInteger(_key.X));
+ new DerInteger(_key.X),
+ attributes);
}
- if (key is RsaKeyParameters)
+ if (privateKey is RsaKeyParameters)
{
AlgorithmIdentifier algID = new AlgorithmIdentifier(
PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
RsaPrivateKeyStructure keyStruct;
- if (key is RsaPrivateCrtKeyParameters)
+ if (privateKey is RsaPrivateCrtKeyParameters)
{
- RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+ RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)privateKey;
keyStruct = new RsaPrivateKeyStructure(
_key.Modulus,
@@ -88,7 +98,7 @@ namespace Org.BouncyCastle.Pkcs
}
else
{
- RsaKeyParameters _key = (RsaKeyParameters) key;
+ RsaKeyParameters _key = (RsaKeyParameters) privateKey;
keyStruct = new RsaPrivateKeyStructure(
_key.Modulus,
@@ -101,12 +111,12 @@ namespace Org.BouncyCastle.Pkcs
BigInteger.Zero);
}
- return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+ return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object(), attributes);
}
- if (key is ECPrivateKeyParameters)
+ if (privateKey is ECPrivateKeyParameters)
{
- ECPrivateKeyParameters priv = (ECPrivateKeyParameters)key;
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)privateKey;
ECDomainParameters dp = priv.Parameters;
int orderBitLength = dp.N.BitLength;
@@ -145,12 +155,12 @@ namespace Org.BouncyCastle.Pkcs
algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962);
}
- return new PrivateKeyInfo(algID, ec);
+ return new PrivateKeyInfo(algID, ec, attributes);
}
- if (key is Gost3410PrivateKeyParameters)
+ if (privateKey is Gost3410PrivateKeyParameters)
{
- Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
+ Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)privateKey;
if (_key.PublicKeyParamSet == null)
throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
@@ -170,10 +180,42 @@ namespace Org.BouncyCastle.Pkcs
CryptoProObjectIdentifiers.GostR3410x94,
algParams.ToAsn1Object());
- return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
+ return new PrivateKeyInfo(algID, new DerOctetString(keyBytes), attributes);
+ }
+
+ if (privateKey is X448PrivateKeyParameters)
+ {
+ X448PrivateKeyParameters key = (X448PrivateKeyParameters)privateKey;
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
+ new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+ }
+
+ if (privateKey is X25519PrivateKeyParameters)
+ {
+ X25519PrivateKeyParameters key = (X25519PrivateKeyParameters)privateKey;
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
+ new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+ }
+
+ if (privateKey is Ed448PrivateKeyParameters)
+ {
+ Ed448PrivateKeyParameters key = (Ed448PrivateKeyParameters)privateKey;
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
+ new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+ }
+
+ if (privateKey is Ed25519PrivateKeyParameters)
+ {
+ Ed25519PrivateKeyParameters key = (Ed25519PrivateKeyParameters)privateKey;
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
+ new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
}
- throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(key));
+ throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(privateKey));
}
public static PrivateKeyInfo CreatePrivateKeyInfo(
diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs
index 12d427c8c..26d1628cc 100644
--- a/crypto/src/security/AgreementUtilities.cs
+++ b/crypto/src/security/AgreementUtilities.cs
@@ -1,6 +1,7 @@
using System.Collections;
using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
@@ -27,7 +28,10 @@ namespace Org.BouncyCastle.Security
algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF";
algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
- }
+
+ algorithms[EdECObjectIdentifiers.id_X25519.Id] = "X25519";
+ algorithms[EdECObjectIdentifiers.id_X448.Id] = "X448";
+ }
public static IBasicAgreement GetBasicAgreement(
DerObjectIdentifier oid)
@@ -38,15 +42,9 @@ namespace Org.BouncyCastle.Security
public static IBasicAgreement GetBasicAgreement(
string algorithm)
{
- string upper = Platform.ToUpperInvariant(algorithm);
- string mechanism = (string) algorithms[upper];
-
- if (mechanism == null)
- {
- mechanism = upper;
- }
+ string mechanism = GetMechanism(algorithm);
- if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
+ if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
return new DHBasicAgreement();
if (mechanism == "ECDH")
@@ -72,15 +70,9 @@ namespace Org.BouncyCastle.Security
string agreeAlgorithm,
string wrapAlgorithm)
{
- string upper = Platform.ToUpperInvariant(agreeAlgorithm);
- string mechanism = (string) algorithms[upper];
+ string mechanism = GetMechanism(agreeAlgorithm);
- if (mechanism == null)
- {
- mechanism = upper;
- }
-
- // 'DHWITHSHA1KDF' retained for backward compatibility
+ // 'DHWITHSHA1KDF' retained for backward compatibility
if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF")
return new ECDHWithKdfBasicAgreement(
wrapAlgorithm,
@@ -96,10 +88,37 @@ namespace Org.BouncyCastle.Security
throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised.");
}
+ public static IRawAgreement GetRawAgreement(
+ DerObjectIdentifier oid)
+ {
+ return GetRawAgreement(oid.Id);
+ }
+
+ public static IRawAgreement GetRawAgreement(
+ string algorithm)
+ {
+ string mechanism = GetMechanism(algorithm);
+
+ if (mechanism == "X25519")
+ return new X25519Agreement();
+
+ if (mechanism == "X448")
+ return new X448Agreement();
+
+ throw new SecurityUtilityException("Raw Agreement " + algorithm + " not recognised.");
+ }
+
public static string GetAlgorithmName(
DerObjectIdentifier oid)
{
- return (string) algorithms[oid.Id];
+ return (string)algorithms[oid.Id];
}
+
+ private static string GetMechanism(string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ string mechanism = (string)algorithms[upper];
+ return mechanism == null ? upper : mechanism;
+ }
}
}
diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs
index de05bc9ef..eb10baec8 100644
--- a/crypto/src/security/CipherUtilities.cs
+++ b/crypto/src/security/CipherUtilities.cs
@@ -53,6 +53,7 @@ namespace Org.BouncyCastle.Security
SEED,
SERPENT,
SKIPJACK,
+ SM4,
TEA,
THREEFISH_256,
THREEFISH_512,
@@ -433,6 +434,9 @@ namespace Org.BouncyCastle.Security
case CipherAlgorithm.SKIPJACK:
blockCipher = new SkipjackEngine();
break;
+ case CipherAlgorithm.SM4:
+ blockCipher = new SM4Engine();
+ break;
case CipherAlgorithm.TEA:
blockCipher = new TeaEngine();
break;
@@ -740,6 +744,7 @@ namespace Org.BouncyCastle.Security
case CipherAlgorithm.SEED: return new SeedEngine();
case CipherAlgorithm.SERPENT: return new SerpentEngine();
case CipherAlgorithm.SKIPJACK: return new SkipjackEngine();
+ case CipherAlgorithm.SM4: return new SM4Engine();
case CipherAlgorithm.TEA: return new TeaEngine();
case CipherAlgorithm.THREEFISH_256: return new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256);
case CipherAlgorithm.THREEFISH_512: return new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512);
diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs
index db1929c16..08281493a 100644
--- a/crypto/src/security/GeneratorUtilities.cs
+++ b/crypto/src/security/GeneratorUtilities.cs
@@ -2,6 +2,7 @@ using System.Collections;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Iana;
using Org.BouncyCastle.Asn1.Kisa;
using Org.BouncyCastle.Asn1.Nist;
@@ -109,6 +110,7 @@ namespace Org.BouncyCastle.Security
KisaObjectIdentifiers.IdSeedCbc);
AddKgAlgorithm("SERPENT");
AddKgAlgorithm("SKIPJACK");
+ AddKgAlgorithm("SM4");
AddKgAlgorithm("TEA");
AddKgAlgorithm("THREEFISH-256");
AddKgAlgorithm("THREEFISH-512");
@@ -180,18 +182,29 @@ namespace Org.BouncyCastle.Security
AddKpgAlgorithm("ECGOST3410",
"ECGOST-3410",
"GOST-3410-2001");
+ AddKpgAlgorithm("Ed25519",
+ "Ed25519ctx",
+ "Ed25519ph",
+ EdECObjectIdentifiers.id_Ed25519);
+ AddKpgAlgorithm("Ed448",
+ "Ed448ph",
+ EdECObjectIdentifiers.id_Ed448);
AddKpgAlgorithm("ELGAMAL");
AddKpgAlgorithm("GOST3410",
"GOST-3410",
"GOST-3410-94");
AddKpgAlgorithm("RSA",
"1.2.840.113549.1.1.1");
+ AddKpgAlgorithm("X25519",
+ EdECObjectIdentifiers.id_X25519);
+ AddKpgAlgorithm("X448",
+ EdECObjectIdentifiers.id_X448);
AddDefaultKeySizeEntries(64, "DES");
AddDefaultKeySizeEntries(80, "SKIPJACK");
AddDefaultKeySizeEntries(128, "AES128", "BLOWFISH", "CAMELLIA128", "CAST5", "DESEDE",
"HC128", "HMACMD2", "HMACMD4", "HMACMD5", "HMACRIPEMD128", "IDEA", "NOEKEON",
- "RC2", "RC4", "RC5", "SALSA20", "SEED", "TEA", "XTEA", "VMPC", "VMPC-KSA3");
+ "RC2", "RC4", "RC5", "SALSA20", "SEED", "SM4", "TEA", "XTEA", "VMPC", "VMPC-KSA3");
AddDefaultKeySizeEntries(160, "HMACRIPEMD160", "HMACSHA1");
AddDefaultKeySizeEntries(192, "AES", "AES192", "CAMELLIA192", "DESEDE3", "HMACTIGER",
"RIJNDAEL", "SERPENT", "TNEPRES");
@@ -216,11 +229,11 @@ namespace Org.BouncyCastle.Security
string canonicalName,
params object[] aliases)
{
- kgAlgorithms[canonicalName] = canonicalName;
+ kgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName;
foreach (object alias in aliases)
{
- kgAlgorithms[alias.ToString()] = canonicalName;
+ kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName;
}
}
@@ -228,11 +241,11 @@ namespace Org.BouncyCastle.Security
string canonicalName,
params object[] aliases)
{
- kpgAlgorithms[canonicalName] = canonicalName;
+ kpgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName;
foreach (object alias in aliases)
{
- kpgAlgorithms[alias.ToString()] = canonicalName;
+ kpgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName;
}
}
@@ -248,7 +261,7 @@ namespace Org.BouncyCastle.Security
foreach (object alias in aliases)
{
- kgAlgorithms[alias.ToString()] = mainName;
+ kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = mainName;
}
}
@@ -318,6 +331,12 @@ namespace Org.BouncyCastle.Security
if (Platform.StartsWith(canonicalName, "EC"))
return new ECKeyPairGenerator(canonicalName);
+ if (canonicalName == "Ed25519")
+ return new Ed25519KeyPairGenerator();
+
+ if (canonicalName == "Ed448")
+ return new Ed448KeyPairGenerator();
+
if (canonicalName == "ELGAMAL")
return new ElGamalKeyPairGenerator();
@@ -327,6 +346,12 @@ namespace Org.BouncyCastle.Security
if (canonicalName == "RSA")
return new RsaKeyPairGenerator();
+ if (canonicalName == "X25519")
+ return new X25519KeyPairGenerator();
+
+ if (canonicalName == "X448")
+ return new X448KeyPairGenerator();
+
throw new SecurityUtilityException("KeyPairGenerator " + algorithm
+ " (" + canonicalName + ") not supported.");
}
diff --git a/crypto/src/security/ParameterUtilities.cs b/crypto/src/security/ParameterUtilities.cs
index c12155878..792067bba 100644
--- a/crypto/src/security/ParameterUtilities.cs
+++ b/crypto/src/security/ParameterUtilities.cs
@@ -103,6 +103,7 @@ namespace Org.BouncyCastle.Security
KisaObjectIdentifiers.IdSeedCbc);
AddAlgorithm("SERPENT");
AddAlgorithm("SKIPJACK");
+ AddAlgorithm("SM4");
AddAlgorithm("TEA");
AddAlgorithm("THREEFISH-256");
AddAlgorithm("THREEFISH-512");
@@ -115,7 +116,8 @@ namespace Org.BouncyCastle.Security
AddBasicIVSizeEntries(8, "BLOWFISH", "DES", "DESEDE", "DESEDE3");
AddBasicIVSizeEntries(16, "AES", "AES128", "AES192", "AES256",
- "CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "NOEKEON", "SEED");
+ "CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256",
+ "NOEKEON", "SEED", "SM4");
// TODO These algorithms support an IV
// but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index c9e19cc7d..0b07d0659 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -5,6 +5,7 @@ using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
@@ -170,12 +171,37 @@ namespace Org.BouncyCastle.Security
return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
}
+ else if (algOid.Equals(EdECObjectIdentifiers.id_X25519))
+ {
+ return new X25519PrivateKeyParameters(GetRawKey(keyInfo, X25519PrivateKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_X448))
+ {
+ return new X448PrivateKeyParameters(GetRawKey(keyInfo, X448PrivateKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519))
+ {
+ return new Ed25519PrivateKeyParameters(GetRawKey(keyInfo, Ed25519PrivateKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448))
+ {
+ return new Ed448PrivateKeyParameters(GetRawKey(keyInfo, Ed448PrivateKeyParameters.KeySize), 0);
+ }
else
{
- throw new SecurityUtilityException("algorithm identifier in key not recognised");
+ throw new SecurityUtilityException("algorithm identifier in private key not recognised");
}
}
+ private static byte[] GetRawKey(PrivateKeyInfo keyInfo, int expectedSize)
+ {
+ byte[] result = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
+ if (expectedSize != result.Length)
+ throw new SecurityUtilityException("private key encoding has incorrect length");
+
+ return result;
+ }
+
public static AsymmetricKeyParameter DecryptKey(
char[] passPhrase,
EncryptedPrivateKeyInfo encInfo)
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index f1b28b774..e39748e45 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -5,6 +5,7 @@ using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
@@ -218,12 +219,41 @@ namespace Org.BouncyCastle.Security
return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
}
+ else if (algOid.Equals(EdECObjectIdentifiers.id_X25519))
+ {
+ return new X25519PublicKeyParameters(GetRawKey(keyInfo, X25519PublicKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_X448))
+ {
+ return new X448PublicKeyParameters(GetRawKey(keyInfo, X448PublicKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519))
+ {
+ return new Ed25519PublicKeyParameters(GetRawKey(keyInfo, Ed25519PublicKeyParameters.KeySize), 0);
+ }
+ else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448))
+ {
+ return new Ed448PublicKeyParameters(GetRawKey(keyInfo, Ed448PublicKeyParameters.KeySize), 0);
+ }
else
{
- throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
+ throw new SecurityUtilityException("algorithm identifier in public key not recognised: " + algOid);
}
}
+ private static byte[] GetRawKey(SubjectPublicKeyInfo keyInfo, int expectedSize)
+ {
+ /*
+ * TODO[RFC 8422]
+ * - Require keyInfo.Algorithm.Parameters == null?
+ */
+ byte[] result = keyInfo.PublicKeyData.GetOctets();
+ if (expectedSize != result.Length)
+ throw new SecurityUtilityException("public key encoding has incorrect length");
+
+ return result;
+ }
+
private static bool IsPkcsDHParam(Asn1Sequence seq)
{
if (seq.Count == 2)
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 44281503a..a9045ae6e 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -4,6 +4,7 @@ using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
@@ -231,7 +232,13 @@ namespace Org.BouncyCastle.Security
algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
-
+ algorithms["ED25519"] = "Ed25519";
+ algorithms[EdECObjectIdentifiers.id_Ed25519.Id] = "Ed25519";
+ algorithms["ED25519CTX"] = "Ed25519ctx";
+ algorithms["ED25519PH"] = "Ed25519ph";
+ algorithms["ED448"] = "Ed448";
+ algorithms[EdECObjectIdentifiers.id_Ed448.Id] = "Ed448";
+ algorithms["ED448PH"] = "Ed448ph";
oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
@@ -264,6 +271,9 @@ namespace Org.BouncyCastle.Security
oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+
+ oids["Ed25519"] = EdECObjectIdentifiers.id_Ed25519;
+ oids["Ed448"] = EdECObjectIdentifiers.id_Ed448;
}
/// <summary>
@@ -361,6 +371,30 @@ namespace Org.BouncyCastle.Security
if (mechanism == null)
mechanism = algorithm;
+ if (Platform.StartsWith(mechanism, "Ed"))
+ {
+ if (mechanism.Equals("Ed25519"))
+ {
+ return new Ed25519Signer();
+ }
+ if (mechanism.Equals("Ed25519ctx"))
+ {
+ return new Ed25519ctxSigner(Arrays.EmptyBytes);
+ }
+ if (mechanism.Equals("Ed25519ph"))
+ {
+ return new Ed25519phSigner(Arrays.EmptyBytes);
+ }
+ if (mechanism.Equals("Ed448"))
+ {
+ return new Ed448Signer(Arrays.EmptyBytes);
+ }
+ if (mechanism.Equals("Ed448ph"))
+ {
+ return new Ed448phSigner(Arrays.EmptyBytes);
+ }
+ }
+
if (mechanism.Equals("RSA"))
{
return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null));
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index df9b4e7ee..a9a574dbf 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -8,6 +8,19 @@ namespace Org.BouncyCastle.Utilities
/// <summary> General array utilities.</summary>
public abstract class Arrays
{
+ public static readonly byte[] EmptyBytes = new byte[0];
+ public static readonly int[] EmptyInts = new int[0];
+
+ public static bool AreAllZeroes(byte[] buf, int off, int len)
+ {
+ uint bits = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ bits |= buf[off + i];
+ }
+ return bits == 0;
+ }
+
public static bool AreEqual(
bool[] a,
bool[] b)
diff --git a/crypto/src/util/Integers.cs b/crypto/src/util/Integers.cs
index ccbf872c4..e746b0ef4 100644
--- a/crypto/src/util/Integers.cs
+++ b/crypto/src/util/Integers.cs
@@ -9,9 +9,21 @@ namespace Org.BouncyCastle.Utilities
return (i << distance) ^ (int)((uint)i >> -distance);
}
+ [CLSCompliantAttribute(false)]
+ public static uint RotateLeft(uint i, int distance)
+ {
+ return (i << distance) ^ (i >> -distance);
+ }
+
public static int RotateRight(int i, int distance)
{
return (int)((uint)i >> distance) ^ (i << -distance);
}
+
+ [CLSCompliantAttribute(false)]
+ public static uint RotateRight(uint i, int distance)
+ {
+ return (i >> distance) ^ (i << -distance);
+ }
}
}
diff --git a/crypto/src/util/collections/CollectionUtilities.cs b/crypto/src/util/collections/CollectionUtilities.cs
index 18fcb6774..cac158226 100644
--- a/crypto/src/util/collections/CollectionUtilities.cs
+++ b/crypto/src/util/collections/CollectionUtilities.cs
@@ -39,6 +39,14 @@ namespace Org.BouncyCastle.Utilities.Collections
return new UnmodifiableSetProxy(s);
}
+ public static object RequireNext(IEnumerator e)
+ {
+ if (!e.MoveNext())
+ throw new InvalidOperationException();
+
+ return e.Current;
+ }
+
public static string ToString(IEnumerable c)
{
StringBuilder sb = new StringBuilder("[");
diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs
index cc7fa924c..503a1b4f1 100644
--- a/crypto/src/util/io/Streams.cs
+++ b/crypto/src/util/io/Streams.cs
@@ -96,5 +96,30 @@ namespace Org.BouncyCastle.Utilities.IO
{
buf.WriteTo(output);
}
+
+ /// <exception cref="IOException"></exception>
+ public static int WriteBufTo(MemoryStream buf, byte[] output, int offset)
+ {
+#if PORTABLE
+ byte[] bytes = buf.ToArray();
+ bytes.CopyTo(output, offset);
+ return bytes.Length;
+#else
+ int size = (int)buf.Length;
+ buf.WriteTo(new MemoryStream(output, offset, size, true));
+ return size;
+#endif
+ }
+
+ public static void WriteZeroes(Stream outStr, long count)
+ {
+ byte[] zeroes = new byte[BufferSize];
+ while (count > BufferSize)
+ {
+ outStr.Write(zeroes, 0, BufferSize);
+ count -= BufferSize;
+ }
+ outStr.Write(zeroes, 0, (int)count);
+ }
}
}
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index 7614321d4..fca5da3f5 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -3,6 +3,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
@@ -26,20 +27,20 @@ namespace Org.BouncyCastle.X509
/// <summary>
/// Create a Subject Public Key Info object for a given public key.
/// </summary>
- /// <param name="key">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
+ /// <param name="publicKey">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
/// <returns>A subject public key info object.</returns>
/// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception>
public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
- AsymmetricKeyParameter key)
+ AsymmetricKeyParameter publicKey)
{
- if (key == null)
- throw new ArgumentNullException("key");
- if (key.IsPrivate)
- throw new ArgumentException("Private key passed - public key expected.", "key");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("Private key passed - public key expected.", "publicKey");
- if (key is ElGamalPublicKeyParameters)
+ if (publicKey is ElGamalPublicKeyParameters)
{
- ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+ ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)publicKey;
ElGamalParameters kp = _key.Parameters;
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
@@ -51,9 +52,9 @@ namespace Org.BouncyCastle.X509
return info;
}
- if (key is DsaPublicKeyParameters)
+ if (publicKey is DsaPublicKeyParameters)
{
- DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
+ DsaPublicKeyParameters _key = (DsaPublicKeyParameters) publicKey;
DsaParameters kp = _key.Parameters;
Asn1Encodable ae = kp == null
? null
@@ -64,9 +65,9 @@ namespace Org.BouncyCastle.X509
new DerInteger(_key.Y));
}
- if (key is DHPublicKeyParameters)
+ if (publicKey is DHPublicKeyParameters)
{
- DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+ DHPublicKeyParameters _key = (DHPublicKeyParameters) publicKey;
DHParameters kp = _key.Parameters;
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
@@ -78,9 +79,9 @@ namespace Org.BouncyCastle.X509
return info;
} // End of DH
- if (key is RsaKeyParameters)
+ if (publicKey is RsaKeyParameters)
{
- RsaKeyParameters _key = (RsaKeyParameters) key;
+ RsaKeyParameters _key = (RsaKeyParameters) publicKey;
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
@@ -89,9 +90,9 @@ namespace Org.BouncyCastle.X509
return info;
} // End of RSA.
- if (key is ECPublicKeyParameters)
+ if (publicKey is ECPublicKeyParameters)
{
- ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
+ ECPublicKeyParameters _key = (ECPublicKeyParameters) publicKey;
if (_key.AlgorithmName == "ECGOST3410")
{
@@ -139,9 +140,9 @@ namespace Org.BouncyCastle.X509
}
} // End of EC
- if (key is Gost3410PublicKeyParameters)
+ if (publicKey is Gost3410PublicKeyParameters)
{
- Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+ Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) publicKey;
if (_key.PublicKeyParamSet == null)
throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
@@ -164,7 +165,35 @@ namespace Org.BouncyCastle.X509
return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
}
- throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(key));
+ if (publicKey is X448PublicKeyParameters)
+ {
+ X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.GetEncoded());
+ }
+
+ if (publicKey is X25519PublicKeyParameters)
+ {
+ X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.GetEncoded());
+ }
+
+ if (publicKey is Ed448PublicKeyParameters)
+ {
+ Ed448PublicKeyParameters key = (Ed448PublicKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), key.GetEncoded());
+ }
+
+ if (publicKey is Ed25519PublicKeyParameters)
+ {
+ Ed25519PublicKeyParameters key = (Ed25519PublicKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.GetEncoded());
+ }
+
+ throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(publicKey));
}
private static void ExtractBytes(
|