MontgomeryCurve25519
using Renci.SshNet.Security.Chaos.NaCl.Internal;
using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10;
using Renci.SshNet.Security.Chaos.NaCl.Internal.Salsa;
using System;
namespace Renci.SshNet.Security.Chaos.NaCl
{
internal static class MontgomeryCurve25519
{
internal static readonly int PublicKeySizeInBytes = 32;
internal static readonly int PrivateKeySizeInBytes = 32;
internal static readonly int = 32;
private static readonly byte[] _basePoint = new byte[32] {
9,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
private static readonly byte[] _zero16 = new byte[16];
internal static byte[] GetPublicKey(byte[] privateKey)
{
if (privateKey == null)
throw new ArgumentNullException("privateKey");
if (privateKey.Length != PrivateKeySizeInBytes)
throw new ArgumentException("privateKey.Length must be 32");
byte[] obj = new byte[32];
GetPublicKey(new ArraySegment<byte>(obj), new ArraySegment<byte>(privateKey));
return obj;
}
internal static void GetPublicKey(ArraySegment<byte> publicKey, ArraySegment<byte> privateKey)
{
if (publicKey.Array == null)
throw new ArgumentNullException("publicKey.Array");
if (privateKey.Array == null)
throw new ArgumentNullException("privateKey.Array");
if (publicKey.Count != PublicKeySizeInBytes)
throw new ArgumentException("privateKey.Count must be 32");
if (privateKey.Count != PrivateKeySizeInBytes)
throw new ArgumentException("privateKey.Count must be 32");
for (int i = 0; i < 32; i++) {
publicKey.Array[publicKey.Offset + i] = privateKey.Array[privateKey.Offset + i];
}
ScalarOperations.sc_clamp(publicKey.Array, publicKey.Offset);
GroupOperations.ge_scalarmult_base(out GroupElementP3 h, publicKey.Array, publicKey.Offset);
EdwardsToMontgomeryX(out FieldElement montgomeryX, ref h.Y, ref h.Z);
FieldOperations.fe_tobytes(publicKey.Array, publicKey.Offset, ref montgomeryX);
}
internal static void KeyExchangeOutputHashCurve25519Paper(byte[] sharedKey, int offset)
{
Array16<uint> output = default(Array16<uint>);
output.x0 = 1987212611;
output.x1 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset);
output.x2 = 0;
output.x3 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 4);
output.x4 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 8);
output.x5 = 892678757;
output.x6 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 12);
output.x7 = 0;
output.x8 = 0;
output.x9 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 16);
output.x10 = 1970223409;
output.x11 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 20);
output.x12 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 24);
output.x13 = 0;
output.x14 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 28);
output.x15 = 1953853556;
SalsaCore.Salsa(out output, ref output, 20);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset, output.x0);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 4, output.x1);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 8, output.x2);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 12, output.x3);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 16, output.x4);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 20, output.x5);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 24, output.x6);
ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 28, output.x7);
}
internal static void KeyExchangeOutputHashNaCl(byte[] sharedKey, int offset)
{
Salsa20.HSalsa20(sharedKey, offset, sharedKey, offset, _zero16, 0);
}
internal static byte[] KeyExchange(byte[] publicKey, byte[] privateKey)
{
byte[] obj = new byte[SharedKeySizeInBytes];
KeyExchange(new ArraySegment<byte>(obj), new ArraySegment<byte>(publicKey), new ArraySegment<byte>(privateKey));
return obj;
}
internal static void KeyExchange(ArraySegment<byte> sharedKey, ArraySegment<byte> publicKey, ArraySegment<byte> privateKey)
{
if (sharedKey.Array == null)
throw new ArgumentNullException("sharedKey.Array");
if (publicKey.Array == null)
throw new ArgumentNullException("publicKey.Array");
if (privateKey.Array == null)
throw new ArgumentNullException("privateKey");
if (sharedKey.Count != 32)
throw new ArgumentException("sharedKey.Count != 32");
if (publicKey.Count != 32)
throw new ArgumentException("publicKey.Count != 32");
if (privateKey.Count != 32)
throw new ArgumentException("privateKey.Count != 32");
MontgomeryOperations.scalarmult(sharedKey.Array, sharedKey.Offset, privateKey.Array, privateKey.Offset, publicKey.Array, publicKey.Offset);
KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset);
}
internal static void EdwardsToMontgomeryX(out FieldElement montgomeryX, ref FieldElement edwardsY, ref FieldElement edwardsZ)
{
FieldOperations.fe_add(out FieldElement h, ref edwardsZ, ref edwardsY);
FieldOperations.fe_sub(out FieldElement h2, ref edwardsZ, ref edwardsY);
FieldOperations.fe_invert(out h2, ref h2);
FieldOperations.fe_mul(out montgomeryX, ref h, ref h2);
}
}
}