diff --git a/Component_Tests/Classes/Crypto/Omemo/Test_KeyHelper.cs b/Component_Tests/Classes/Crypto/Omemo/Test_KeyHelper.cs
index 3c55217d..caa44c5f 100644
--- a/Component_Tests/Classes/Crypto/Omemo/Test_KeyHelper.cs
+++ b/Component_Tests/Classes/Crypto/Omemo/Test_KeyHelper.cs
@@ -63,5 +63,37 @@ public void Test_SignPreKey()
Assert.AreEqual(sigBase64, sigRefBase64);
}
}
+
+ [TestCategory("Crypto")]
+ [TestMethod]
+ public void Test_Signing()
+ {
+ ECPrivKeyModel identityPriv = new ECPrivKeyModel(SharedUtils.HexStringToByteArray("1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93"));
+ ECPubKeyModel identityPub = new ECPubKeyModel(SharedUtils.HexStringToByteArray("05b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde"));
+
+ ECPrivKeyModel prePriv = new ECPrivKeyModel(SharedUtils.HexStringToByteArray("181c0ed79c361f2d773f3aa8d5934569395a1c1b4a8514d140a7dcde92688579"));
+ ECPubKeyModel prePub = new ECPubKeyModel(SharedUtils.HexStringToByteArray("05b30aad2471f7186bdb34951747cf81a67245144260e20ffe5bf7748202d6572c"));
+ PreKeyModel preKey = new PreKeyModel(prePriv, prePub, 2);
+
+ byte[] sig = KeyHelper.SignPreKey(preKey, identityPriv);
+ string sig16 = SharedUtils.ToHexString(sig);
+ Assert.IsTrue(KeyHelper.VerifySignature(identityPub, prePub, sig));
+ }
+
+ [TestCategory("Crypto")]
+ [TestMethod]
+ public void Test_VerifySignature()
+ {
+ ECPubKeyModel identityPub = new ECPubKeyModel(SharedUtils.HexStringToByteArray("05b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde"));
+ ECPubKeyModel prePub = new ECPubKeyModel(SharedUtils.HexStringToByteArray("05b30aad2471f7186bdb34951747cf81a67245144260e20ffe5bf7748202d6572c"));
+ byte[][] sigs = {
+ SharedUtils.HexStringToByteArray("db0495131504b9acf87696613070088abff5310ad984f3b7623088af6310e2435381f2f726cfcc3edc754549d47e251d873d5b6777dd62a334b5d3fa8afb9f0a")
+ };
+
+ foreach (byte[] sig in sigs)
+ {
+ Assert.IsTrue(KeyHelper.VerifySignature(identityPub, prePub, sig));
+ }
+ }
}
}
diff --git a/Component_Tests/Classes/Crypto/Omemo/Test_Xeddsa25519.cs b/Component_Tests/Classes/Crypto/Omemo/Test_Xeddsa25519.cs
new file mode 100644
index 00000000..01def49e
--- /dev/null
+++ b/Component_Tests/Classes/Crypto/Omemo/Test_Xeddsa25519.cs
@@ -0,0 +1,22 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Omemo.Classes.Keys;
+using Omemo.Classes.Xeddsa;
+using Shared.Classes;
+
+namespace Component_Tests.Classes.Crypto.Omemo
+{
+ [TestClass]
+ public class Test_Xeddsa25519
+ {
+ [TestCategory("Crypto")]
+ [TestMethod]
+ public void Test_Signing()
+ {
+ ECPrivKeyModel priv = new ECPrivKeyModel(SharedUtils.HexStringToByteArray("1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93"));
+ ECPubKeyModel pub = new ECPubKeyModel(SharedUtils.HexStringToByteArray("b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde"));
+ IdentityKeyPairModel identityKeyPair = new IdentityKeyPairModel(priv, pub);
+ // Xeddsa25519.Sign(identityKeyPair.privKey, pub new );
+ Xeddsa25519.ToTwistedEdwardsKeyPair(priv);
+ }
+ }
+}
diff --git a/Component_Tests/Component_Tests.csproj b/Component_Tests/Component_Tests.csproj
index d47a13e3..a0340c84 100644
--- a/Component_Tests/Component_Tests.csproj
+++ b/Component_Tests/Component_Tests.csproj
@@ -131,6 +131,7 @@
+
diff --git a/Omemo/Classes/Keys/AbstractECKeyPairModel.cs b/Omemo/Classes/Keys/ECKeyPairModel.cs
similarity index 91%
rename from Omemo/Classes/Keys/AbstractECKeyPairModel.cs
rename to Omemo/Classes/Keys/ECKeyPairModel.cs
index 4fec3e58..d671790f 100644
--- a/Omemo/Classes/Keys/AbstractECKeyPairModel.cs
+++ b/Omemo/Classes/Keys/ECKeyPairModel.cs
@@ -6,7 +6,7 @@
namespace Omemo.Classes.Keys
{
- public abstract class AbstractECKeyPairModel: AbstractDataTemplate
+ public class ECKeyPairModel: AbstractDataTemplate
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
@@ -38,9 +38,9 @@ public ECPubKeyModel pubKey
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
- public AbstractECKeyPairModel() { }
+ public ECKeyPairModel() { }
- public AbstractECKeyPairModel(ECPrivKeyModel privKey, ECPubKeyModel pubKey)
+ public ECKeyPairModel(ECPrivKeyModel privKey, ECPubKeyModel pubKey)
{
this.privKey = privKey;
this.pubKey = pubKey;
@@ -86,7 +86,7 @@ private void SetPubKeyProperty(ECPubKeyModel value)
#region --Misc Methods (Public)--
public override bool Equals(object obj)
{
- return obj is AbstractECKeyPairModel pair && ((pair.privKey is null && privKey is null) || pair.privKey.Equals(privKey)) && ((pair.pubKey is null && pubKey is null) || pair.pubKey.Equals(pubKey));
+ return obj is ECKeyPairModel pair && ((pair.privKey is null && privKey is null) || pair.privKey.Equals(privKey)) && ((pair.pubKey is null && pubKey is null) || pair.pubKey.Equals(pubKey));
}
public override int GetHashCode()
diff --git a/Omemo/Classes/Keys/ECPrivKeyModel.cs b/Omemo/Classes/Keys/ECPrivKeyModel.cs
index 21773c0a..97edb4e7 100644
--- a/Omemo/Classes/Keys/ECPrivKeyModel.cs
+++ b/Omemo/Classes/Keys/ECPrivKeyModel.cs
@@ -16,14 +16,14 @@ public class ECPrivKeyModel: ECKeyModel
///
public ECPrivKeyModel() { }
- public ECPrivKeyModel(byte[] pubKey) : base(pubKey)
+ public ECPrivKeyModel(byte[] privKey) : base(privKey)
{
- if (pubKey.Length == KeyHelper.PUB_KEY_SIZE)
+ if (privKey.Length == KeyHelper.PUB_KEY_SIZE)
{
return;
}
- throw new OmemoKeyException($"Invalid key length {pubKey.Length} - expected {KeyHelper.PRIV_KEY_SIZE}.");
+ throw new OmemoKeyException($"Invalid key length {privKey.Length} - expected {KeyHelper.PRIV_KEY_SIZE}.");
}
#endregion
diff --git a/Omemo/Classes/Keys/EphemeralKeyPairModel.cs b/Omemo/Classes/Keys/EphemeralKeyPairModel.cs
index 9515a67c..8570b579 100644
--- a/Omemo/Classes/Keys/EphemeralKeyPairModel.cs
+++ b/Omemo/Classes/Keys/EphemeralKeyPairModel.cs
@@ -3,7 +3,7 @@
///
/// Represents a Ed25519 key pair.
///
- public class EphemeralKeyPairModel: AbstractECKeyPairModel
+ public class EphemeralKeyPairModel: ECKeyPairModel
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
diff --git a/Omemo/Classes/Keys/GenericECKeyPairModel.cs b/Omemo/Classes/Keys/GenericECKeyPairModel.cs
index 33a6f816..b7373121 100644
--- a/Omemo/Classes/Keys/GenericECKeyPairModel.cs
+++ b/Omemo/Classes/Keys/GenericECKeyPairModel.cs
@@ -3,7 +3,7 @@
///
/// Represents a generic EC key pair holding a and .
///
- public class GenericECKeyPairModel: AbstractECKeyPairModel
+ public class GenericECKeyPairModel: ECKeyPairModel
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
diff --git a/Omemo/Classes/Keys/IdentityKeyPairModel.cs b/Omemo/Classes/Keys/IdentityKeyPairModel.cs
index a2ee35ff..8f48fbc1 100644
--- a/Omemo/Classes/Keys/IdentityKeyPairModel.cs
+++ b/Omemo/Classes/Keys/IdentityKeyPairModel.cs
@@ -3,7 +3,7 @@
///
/// Represents a Ed25519 key pair.
///
- public class IdentityKeyPairModel: AbstractECKeyPairModel
+ public class IdentityKeyPairModel: ECKeyPairModel
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
diff --git a/Omemo/Classes/Keys/PreKeyModel.cs b/Omemo/Classes/Keys/PreKeyModel.cs
index 8d16e5db..d0f41328 100644
--- a/Omemo/Classes/Keys/PreKeyModel.cs
+++ b/Omemo/Classes/Keys/PreKeyModel.cs
@@ -3,7 +3,7 @@
namespace Omemo.Classes.Keys
{
- public class PreKeyModel: AbstractECKeyPairModel
+ public class PreKeyModel: ECKeyPairModel
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
diff --git a/Omemo/Classes/Xeddsa/ECPoint.cs b/Omemo/Classes/Xeddsa/ECPoint.cs
new file mode 100644
index 00000000..cb0e82a8
--- /dev/null
+++ b/Omemo/Classes/Xeddsa/ECPoint.cs
@@ -0,0 +1,69 @@
+using Org.BouncyCastle.Math;
+
+namespace Omemo.Classes.Xeddsa
+{
+ public class ECPoint
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ public BigInteger y;
+ public bool s;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+ public ECPoint(byte[] point)
+ {
+ // Decoding described in: https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.3
+ BigInteger tmp = new BigInteger(point);
+ s = ((point[31] & 0x80) >> 7) == 1;
+ y = tmp.ClearBit(255);
+ }
+
+ public ECPoint(BigInteger y, bool s)
+ {
+ this.y = y;
+ this.s = s;
+ }
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ public byte[] Encode()
+ {
+ // Encoding described in: https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2
+ BigInteger point = new BigInteger(y.ToByteArray());
+ if (s)
+ {
+ point.SetBit(255);
+ }
+ else
+ {
+ point.ClearBit(255);
+ }
+ return point.ToByteArray();
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Omemo/Classes/Xeddsa/Xeddsa25519.cs b/Omemo/Classes/Xeddsa/Xeddsa25519.cs
new file mode 100644
index 00000000..5ddcd903
--- /dev/null
+++ b/Omemo/Classes/Xeddsa/Xeddsa25519.cs
@@ -0,0 +1,114 @@
+using System.Diagnostics;
+using NSec.Cryptography;
+using Omemo.Classes.Keys;
+using Org.BouncyCastle.Math;
+
+namespace Omemo.Classes.Xeddsa
+{
+ ///
+ /// Notes:
+ /// Curve25519 -> Montgomery
+ /// edwards25519 (Ed25519) -> Twisted Edwards
+ /// Ed25519 is a public-key signature system with several attractive features (https://ed25519.cr.yp.to/)
+ /// Ed25519 as defined in:
+ /// https://tools.ietf.org/html/rfc7748
+ /// https://tools.ietf.org/html/rfc8032
+ ///
+ public class Xeddsa25519
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ private static readonly BigInteger p = BigInteger.Two.Pow(255).Subtract(BigInteger.ValueOf(19));
+
+ private static readonly byte[] MINUS_ONE = new byte[] {0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ ///
+ /// Signes the given and returns the result.
+ ///
+ /// The Curve25519 (Montgomery) private key used for signing.
+ /// The message that should be signed.
+ /// 64 bytes secure random data used for signing.
+ /// The generated signature for the given .
+ public static byte[] Sign(ECPrivKeyModel privKey, byte[] msg, byte[] random)
+ {
+ Debug.Assert(random.Length == 64);
+ Debug.Assert(msg.Length > 0);
+
+ ECKeyPairModel edKeyPair = ToTwistedEdwardsKeyPair(privKey);
+
+ Key key = Key.Import(SignatureAlgorithm.Ed25519, edKeyPair.privKey.key, KeyBlobFormat.RawPrivateKey);
+ return SignatureAlgorithm.Ed25519.Sign(key, msg);
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+ public static ECKeyPairModel ToTwistedEdwardsKeyPair(ECPrivKeyModel privKey)
+ {
+ byte[] A = new byte[Org.BouncyCastle.Math.EC.Rfc7748.X25519.PointSize];
+ byte[] A2 = new byte[Org.BouncyCastle.Math.EC.Rfc7748.X25519.PointSize];
+ Org.BouncyCastle.Math.EC.Rfc7748.X25519.ScalarMultBase(privKey.key, 0, A2, 0);
+ byte[] u = Shared.Classes.SharedUtils.HexStringToByteArray("5866666666666666666666666666666666666666666666666666666666666666");
+ Org.BouncyCastle.Math.EC.Rfc7748.X25519.ScalarMult(privKey.key, 0, u, 0, A, 0);
+
+ byte s = (byte)((A[31] & 0x80) >> 7);
+ byte[] a = new byte[Org.BouncyCastle.Math.EC.Rfc7748.X25519.PointSize];
+ privKey.key.CopyTo(a, 0);
+ byte[] aNeg = new byte[Org.BouncyCastle.Math.EC.Rfc7748.X25519.PointSize];
+
+ Org.BouncyCastle.Math.EC.Rfc7748.X25519.ScalarMult(MINUS_ONE, 0, a, 0, aNeg, 0);
+ sc_cmov(a, aNeg, s);
+ A[31] &= 0x7F;
+
+ return new ECKeyPairModel(new ECPrivKeyModel(a), new ECPubKeyModel(A));
+ }
+
+ private static void sc_cmov(byte[] f, byte[] g, byte b)
+ {
+ byte[] x = new byte[32];
+ for (int count = 0; count < 32; count++)
+ {
+ x[count] = (byte)(f[count] ^ g[count]);
+ }
+ b = (byte)-b;
+ for (int count = 0; count < 32; count++)
+ {
+ x[count] &= b;
+ }
+
+ for (int count = 0; count < 32; count++)
+ {
+ f[count] = (byte)(f[count] ^ x[count]);
+ }
+ }
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Omemo/Omemo.csproj b/Omemo/Omemo.csproj
index 88689cb5..ed299843 100644
--- a/Omemo/Omemo.csproj
+++ b/Omemo/Omemo.csproj
@@ -130,7 +130,7 @@
-
+
@@ -150,6 +150,8 @@
+
+
@@ -182,6 +184,7 @@
Visual C++ 2015-2019 UWP Desktop Runtime for native apps
+
14.0