< Summary

Information
Class: Renci.SshNet.Security.Chaos.NaCl.MontgomeryCurve25519
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Chaos.NaCl\MontgomeryCurve25519.cs
Line coverage
11%
Covered lines: 11
Uncovered lines: 84
Coverable lines: 95
Total lines: 142
Line coverage: 11.5%
Branch coverage
0%
Covered branches: 0
Total branches: 26
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.cctor()100%1100%
GetPublicKey(...)0%40%
GetPublicKey(...)0%100%
KeyExchangeOutputHashCurve25519Paper(...)100%10%
KeyExchangeOutputHashNaCl(...)100%10%
KeyExchange(...)100%10%
KeyExchange(...)0%120%
EdwardsToMontgomeryX(...)100%10%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Chaos.NaCl\MontgomeryCurve25519.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using Renci.SshNet.Security.Chaos.NaCl.Internal;
 4using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10;
 5using Renci.SshNet.Security.Chaos.NaCl.Internal.Salsa;
 6
 7namespace Renci.SshNet.Security.Chaos.NaCl
 8{
 9    // This class is mainly for compatibility with NaCl's Curve25519 implementation
 10    // If you don't need that compatibility, use Ed25519.KeyExchange
 11    internal static class MontgomeryCurve25519
 12    {
 113        internal static readonly int PublicKeySizeInBytes = 32;
 114        internal static readonly int PrivateKeySizeInBytes = 32;
 115        internal static readonly int SharedKeySizeInBytes = 32;
 16
 17        internal static byte[] GetPublicKey(byte[] privateKey)
 018        {
 019            if (privateKey == null)
 020                throw new ArgumentNullException("privateKey");
 021            if (privateKey.Length != PrivateKeySizeInBytes)
 022                throw new ArgumentException("privateKey.Length must be 32");
 023            var publicKey = new byte[32];
 024            GetPublicKey(new ArraySegment<byte>(publicKey), new ArraySegment<byte>(privateKey));
 025            return publicKey;
 026        }
 27
 128        static readonly byte[] _basePoint = new byte[32]
 129    {
 130      9, 0, 0, 0, 0, 0, 0, 0,
 131      0, 0, 0 ,0, 0, 0, 0, 0,
 132      0, 0, 0 ,0, 0, 0, 0, 0,
 133      0, 0, 0 ,0, 0, 0, 0, 0
 134    };
 35
 36        internal static void GetPublicKey(ArraySegment<byte> publicKey, ArraySegment<byte> privateKey)
 037        {
 038            if (publicKey.Array == null)
 039                throw new ArgumentNullException("publicKey.Array");
 040            if (privateKey.Array == null)
 041                throw new ArgumentNullException("privateKey.Array");
 042            if (publicKey.Count != PublicKeySizeInBytes)
 043                throw new ArgumentException("privateKey.Count must be 32");
 044            if (privateKey.Count != PrivateKeySizeInBytes)
 045                throw new ArgumentException("privateKey.Count must be 32");
 46
 47            // hack: abusing publicKey as temporary storage
 48            // todo: remove hack
 049            for (int i = 0; i < 32; i++)
 050            {
 051                publicKey.Array[publicKey.Offset + i] = privateKey.Array[privateKey.Offset + i];
 052            }
 053            ScalarOperations.sc_clamp(publicKey.Array, publicKey.Offset);
 54
 55            GroupElementP3 A;
 056            GroupOperations.ge_scalarmult_base(out A, publicKey.Array, publicKey.Offset);
 57            FieldElement publicKeyFE;
 058            EdwardsToMontgomeryX(out publicKeyFE, ref A.Y, ref A.Z);
 059            FieldOperations.fe_tobytes(publicKey.Array, publicKey.Offset, ref publicKeyFE);
 060        }
 61
 62        // hashes like the Curve25519 paper says
 63        internal static void KeyExchangeOutputHashCurve25519Paper(byte[] sharedKey, int offset)
 064        {
 65            //c = Curve25519output
 66            const UInt32 c0 = 'C' | 'u' << 8 | 'r' << 16 | (UInt32)'v' << 24;
 67            const UInt32 c1 = 'e' | '2' << 8 | '5' << 16 | (UInt32)'5' << 24;
 68            const UInt32 c2 = '1' | '9' << 8 | 'o' << 16 | (UInt32)'u' << 24;
 69            const UInt32 c3 = 't' | 'p' << 8 | 'u' << 16 | (UInt32)'t' << 24;
 70
 71            Array16<UInt32> salsaState;
 072            salsaState.x0 = c0;
 073            salsaState.x1 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 0);
 074            salsaState.x2 = 0;
 075            salsaState.x3 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 4);
 076            salsaState.x4 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 8);
 077            salsaState.x5 = c1;
 078            salsaState.x6 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 12);
 079            salsaState.x7 = 0;
 080            salsaState.x8 = 0;
 081            salsaState.x9 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 16);
 082            salsaState.x10 = c2;
 083            salsaState.x11 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 20);
 084            salsaState.x12 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 24);
 085            salsaState.x13 = 0;
 086            salsaState.x14 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 28);
 087            salsaState.x15 = c3;
 088            SalsaCore.Salsa(out salsaState, ref salsaState, 20);
 89
 090            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 0, salsaState.x0);
 091            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 4, salsaState.x1);
 092            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 8, salsaState.x2);
 093            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 12, salsaState.x3);
 094            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 16, salsaState.x4);
 095            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 20, salsaState.x5);
 096            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 24, salsaState.x6);
 097            ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 28, salsaState.x7);
 098        }
 99
 1100        private static readonly byte[] _zero16 = new byte[16];
 101
 102        // hashes like the NaCl paper says instead i.e. HSalsa(x,0)
 103        internal static void KeyExchangeOutputHashNaCl(byte[] sharedKey, int offset)
 0104        {
 0105            Salsa20.HSalsa20(sharedKey, offset, sharedKey, offset, _zero16, 0);
 0106        }
 107
 108        internal static byte[] KeyExchange(byte[] publicKey, byte[] privateKey)
 0109        {
 0110            var sharedKey = new byte[SharedKeySizeInBytes];
 0111            KeyExchange(new ArraySegment<byte>(sharedKey), new ArraySegment<byte>(publicKey), new ArraySegment<byte>(pri
 0112            return sharedKey;
 0113        }
 114
 115        internal static void KeyExchange(ArraySegment<byte> sharedKey, ArraySegment<byte> publicKey, ArraySegment<byte> 
 0116        {
 0117            if (sharedKey.Array == null)
 0118                throw new ArgumentNullException("sharedKey.Array");
 0119            if (publicKey.Array == null)
 0120                throw new ArgumentNullException("publicKey.Array");
 0121            if (privateKey.Array == null)
 0122                throw new ArgumentNullException("privateKey");
 0123            if (sharedKey.Count != 32)
 0124                throw new ArgumentException("sharedKey.Count != 32");
 0125            if (publicKey.Count != 32)
 0126                throw new ArgumentException("publicKey.Count != 32");
 0127            if (privateKey.Count != 32)
 0128                throw new ArgumentException("privateKey.Count != 32");
 0129            MontgomeryOperations.scalarmult(sharedKey.Array, sharedKey.Offset, privateKey.Array, privateKey.Offset, publ
 0130            KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset);
 0131        }
 132
 133        internal static void EdwardsToMontgomeryX(out FieldElement montgomeryX, ref FieldElement edwardsY, ref FieldElem
 0134        {
 135            FieldElement tempX, tempZ;
 0136            FieldOperations.fe_add(out tempX, ref edwardsZ, ref edwardsY);
 0137            FieldOperations.fe_sub(out tempZ, ref edwardsZ, ref edwardsY);
 0138            FieldOperations.fe_invert(out tempZ, ref tempZ);
 0139            FieldOperations.fe_mul(out montgomeryX, ref tempX, ref tempZ);
 0140        }
 141    }
 142}