public void TestAgreement() { using (RandomNumberGenerator random = RandomNumberGenerator.Create()) { byte[] clientPrivateKey = new byte[X25519.KeySize]; random.GetBytes(clientPrivateKey); byte[] clientPublicKey = new byte[X25519.KeySize]; X25519.Func(clientPublicKey, clientPrivateKey); byte[] serverPrivateKey = new byte[X25519.KeySize]; random.GetBytes(serverPrivateKey); byte[] serverPublickey = new byte[X25519.KeySize]; X25519.Func(serverPublickey, serverPrivateKey); // client key aggreement byte[] clientSharedSecret = new byte[X25519.KeySize]; Assert.IsTrue(X25519.Func(clientSharedSecret, clientPrivateKey, serverPublickey)); // server key agreement byte[] serverSharedSecret = new byte[X25519.KeySize]; Assert.IsTrue(X25519.Func(serverSharedSecret, serverPrivateKey, clientPublicKey)); CollectionAssert.AreEqual(clientSharedSecret, serverSharedSecret); } }
/// <inheritdoc /> public void EncodeServerKeyExchangeMessage(ByteSpan output, object privateKey) { RSA rsaPrivateKey = privateKey as RSA; if (rsaPrivateKey == null) { throw new ArgumentException("Invalid private key", nameof(privateKey)); } output[0] = (byte)ECCurveType.NamedCurve; output.WriteBigEndian16((ushort)NamedCurve.x25519, 1); output[3] = (byte)X25519.KeySize; X25519.Func(output.Slice(4, X25519.KeySize), this.privateAgreementKey); // Hash the key parameters byte[] paramterDigest = this.sha256.ComputeHash(output.GetUnderlyingArray(), output.Offset, 4 + X25519.KeySize); // Sign the paramter digest RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter(rsaPrivateKey); signer.SetHashAlgorithm("SHA256"); ByteSpan signature = signer.CreateSignature(paramterDigest); Debug.Assert(signature.Length == rsaPrivateKey.KeySize / 8); output[4 + X25519.KeySize] = (byte)HashAlgorithm.Sha256; output[5 + X25519.KeySize] = (byte)SignatureAlgorithm.RSA; output.Slice(6 + X25519.KeySize).WriteBigEndian16((ushort)signature.Length); signature.CopyTo(output.Slice(8 + X25519.KeySize)); }
public void TestVectors() { for (int ii = 0, nn = TestVectorData.Length; ii != nn; ++ii) { byte[] actual = new byte[32]; bool result = X25519.Func(actual, TestVectorData[ii].In, TestVectorData[ii].Base); Assert.IsTrue(result); CollectionAssert.AreEqual(TestVectorData[ii].Expect, actual, $"Test vector {ii} mismatch"); } }
/// <inheritdoc /> public bool VerifyClientMessageAndGenerateSharedKey(ByteSpan output, ByteSpan clientKeyExchangeMessage) { if (clientKeyExchangeMessage.Length != ClientMessageSize) { return(false); } else if (clientKeyExchangeMessage[0] != (byte)X25519.KeySize) { return(false); } ByteSpan othersPublicKey = clientKeyExchangeMessage.Slice(1); return(X25519.Func(output, this.privateAgreementKey, othersPublicKey)); }
public void TestLowOrderPoints() { using (RandomNumberGenerator random = RandomNumberGenerator.Create()) { byte[] scalar = new byte[X25519.KeySize]; random.GetBytes(scalar); for (int ii = 0, nn = LowOrderPoints.Length; ii != nn; ++ii) { ByteSpan output = new byte[X25519.KeySize]; bool result = X25519.Func(output, scalar, LowOrderPoints[ii]); Assert.IsFalse(result, $"Multiplication by low order point {ii} succeeded: should have failed"); } } }
/// <inheritdoc /> public void EncodeClientKeyExchangeMessage(ByteSpan output) { output[0] = (byte)X25519.KeySize; X25519.Func(output.Slice(1, X25519.KeySize), this.privateAgreementKey); }
/// <inheritdoc /> public bool VerifyServerMessageAndGenerateSharedKey(ByteSpan output, ByteSpan serverKeyExchangeMessage, object publicKey) { RSA rsaPublicKey = publicKey as RSA; if (rsaPublicKey == null) { return(false); } else if (output.Length != X25519.KeySize) { return(false); } // Verify message is compatible with this cipher suite if (serverKeyExchangeMessage.Length != CalculateServerMessageSize(rsaPublicKey.KeySize)) { return(false); } else if (serverKeyExchangeMessage[0] != (byte)ECCurveType.NamedCurve) { return(false); } else if (serverKeyExchangeMessage.ReadBigEndian16(1) != (ushort)NamedCurve.x25519) { return(false); } else if (serverKeyExchangeMessage[3] != X25519.KeySize) { return(false); } else if (serverKeyExchangeMessage[4 + X25519.KeySize] != (byte)HashAlgorithm.Sha256) { return(false); } else if (serverKeyExchangeMessage[5 + X25519.KeySize] != (byte)SignatureAlgorithm.RSA) { return(false); } ByteSpan keyParameters = serverKeyExchangeMessage.Slice(0, 4 + X25519.KeySize); ByteSpan othersPublicKey = keyParameters.Slice(4); ushort signatureSize = serverKeyExchangeMessage.ReadBigEndian16(6 + X25519.KeySize); ByteSpan signature = serverKeyExchangeMessage.Slice(4 + keyParameters.Length); if (signatureSize != signature.Length) { return(false); } // Hash the key parameters byte[] parameterDigest = this.sha256.ComputeHash(keyParameters.GetUnderlyingArray(), keyParameters.Offset, keyParameters.Length); // Verify the signature RSAPKCS1SignatureDeformatter verifier = new RSAPKCS1SignatureDeformatter(rsaPublicKey); verifier.SetHashAlgorithm("SHA256"); if (!verifier.VerifySignature(parameterDigest, signature.ToArray())) { return(false); } // Signature has been validated, generate the shared key return(X25519.Func(output, this.privateAgreementKey, othersPublicKey)); }