Skip to content

Commit 2fe968b

Browse files
committed
Import Chaos.NaCl for ED25519 and Curve25519
1 parent d24fe20 commit 2fe968b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+7356
-1
lines changed

THIRD-PARTY-NOTICES.TXT

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,32 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
2424
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
2525
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2626
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27+
28+
License notice for Chaos.NaCl
29+
-------------------------------
30+
31+
https://github.com/CodesInChaos/Chaos.NaCl
32+
33+
Public domain
34+
35+
C# port + code by Christian Winnerlein (CodesInChaos)
36+
37+
Poly1305 in c
38+
written by Andrew M. (floodyberry)
39+
original license: MIT or PUBLIC DOMAIN
40+
https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-unrolled.c
41+
42+
Curve25519 and Ed25519 in c
43+
written by Dan Bernstein (djb)
44+
public domain
45+
from Ref10 in SUPERCOP http://bench.cr.yp.to/supercop.html
46+
47+
(H)Salsa20 in c
48+
written by Dan Bernstein (djb)
49+
public domain
50+
from SUPERCOP http://bench.cr.yp.to/supercop.html
51+
52+
SHA512
53+
written by Christian Winnerlein (CodesInChaos)
54+
public domain
55+
directly from the specification

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,67 @@
240240
<Compile Include="Security\BouncyCastle\util\Integers.cs" />
241241
<Compile Include="Security\BouncyCastle\util\MemoableResetException.cs" />
242242
<Compile Include="Security\BouncyCastle\util\Times.cs" />
243+
<Compile Include="Security\Chaos.NaCl\CryptoBytes.cs" />
244+
<Compile Include="Security\Chaos.NaCl\Ed25519.cs" />
245+
<Compile Include="Security\Chaos.NaCl\Internal\Array16.cs" />
246+
<Compile Include="Security\Chaos.NaCl\Internal\Array8.cs" />
247+
<Compile Include="Security\Chaos.NaCl\Internal\ByteIntegerConverter.cs" />
248+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\base.cs" />
249+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs" />
250+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\d.cs" />
251+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs" />
252+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs" />
253+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs" />
254+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs" />
255+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs" />
256+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs" />
257+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs" />
258+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs" />
259+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs" />
260+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs" />
261+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs" />
262+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs" />
263+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs" />
264+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs" />
265+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs" />
266+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs" />
267+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs" />
268+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs" />
269+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs" />
270+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs" />
271+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs" />
272+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs" />
273+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs" />
274+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs" />
275+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs" />
276+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs" />
277+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs" />
278+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs" />
279+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs" />
280+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs" />
281+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs" />
282+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs" />
283+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs" />
284+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs" />
285+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs" />
286+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs" />
287+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs" />
288+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs" />
289+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs" />
290+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\open.cs" />
291+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs" />
292+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs" />
293+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs" />
294+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs" />
295+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs" />
296+
<Compile Include="Security\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs" />
297+
<Compile Include="Security\Chaos.NaCl\Internal\InternalAssert.cs" />
298+
<Compile Include="Security\Chaos.NaCl\Internal\Poly1305Donna.cs" />
299+
<Compile Include="Security\Chaos.NaCl\Internal\Salsa\Salsa20.cs" />
300+
<Compile Include="Security\Chaos.NaCl\Internal\Salsa\SalsaCore.cs" />
301+
<Compile Include="Security\Chaos.NaCl\Internal\Sha512Internal.cs" />
302+
<Compile Include="Security\Chaos.NaCl\MontgomeryCurve25519.cs" />
303+
<Compile Include="Security\Chaos.NaCl\Sha512.cs" />
243304
<Compile Include="Security\Cryptography\HMACMD5.cs" />
244305
<Compile Include="Security\Cryptography\HMACSHA1.cs" />
245306
<Compile Include="Security\Cryptography\HMACSHA256.cs" />
@@ -540,6 +601,8 @@
540601
</ItemGroup>
541602
<ItemGroup>
542603
<Content Include="Documentation\SshNet.shfbproj" />
604+
<Content Include="Security\Chaos.NaCl\Internal\Salsa\replace regex.txt" />
605+
<Content Include="Security\Chaos.NaCl\License.txt" />
543606
</ItemGroup>
544607
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
545608
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -549,4 +612,4 @@
549612
<Target Name="AfterBuild">
550613
</Target>
551614
-->
552-
</Project>
615+
</Project>
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Renci.SshNet.Security.Chaos.NaCl
5+
{
6+
internal static class CryptoBytes
7+
{
8+
internal static bool ConstantTimeEquals(byte[] x, byte[] y)
9+
{
10+
if (x == null)
11+
throw new ArgumentNullException("x");
12+
if (y == null)
13+
throw new ArgumentNullException("y");
14+
if (x.Length != y.Length)
15+
throw new ArgumentException("x.Length must equal y.Length");
16+
return InternalConstantTimeEquals(x, 0, y, 0, x.Length) != 0;
17+
}
18+
19+
internal static bool ConstantTimeEquals(ArraySegment<byte> x, ArraySegment<byte> y)
20+
{
21+
if (x.Array == null)
22+
throw new ArgumentNullException("x.Array");
23+
if (y.Array == null)
24+
throw new ArgumentNullException("y.Array");
25+
if (x.Count != y.Count)
26+
throw new ArgumentException("x.Count must equal y.Count");
27+
28+
return InternalConstantTimeEquals(x.Array, x.Offset, y.Array, y.Offset, x.Count) != 0;
29+
}
30+
31+
internal static bool ConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length)
32+
{
33+
if (x == null)
34+
throw new ArgumentNullException("x");
35+
if (xOffset < 0)
36+
throw new ArgumentOutOfRangeException("xOffset", "xOffset < 0");
37+
if (y == null)
38+
throw new ArgumentNullException("y");
39+
if (yOffset < 0)
40+
throw new ArgumentOutOfRangeException("yOffset", "yOffset < 0");
41+
if (length < 0)
42+
throw new ArgumentOutOfRangeException("length", "length < 0");
43+
if (x.Length - xOffset < length)
44+
throw new ArgumentException("xOffset + length > x.Length");
45+
if (y.Length - yOffset < length)
46+
throw new ArgumentException("yOffset + length > y.Length");
47+
48+
return InternalConstantTimeEquals(x, xOffset, y, yOffset, length) != 0;
49+
}
50+
51+
private static uint InternalConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length)
52+
{
53+
int differentbits = 0;
54+
for (int i = 0; i < length; i++)
55+
differentbits |= x[xOffset + i] ^ y[yOffset + i];
56+
return (1 & (unchecked((uint)differentbits - 1) >> 8));
57+
}
58+
59+
internal static void Wipe(byte[] data)
60+
{
61+
if (data == null)
62+
throw new ArgumentNullException("data");
63+
InternalWipe(data, 0, data.Length);
64+
}
65+
66+
internal static void Wipe(byte[] data, int offset, int count)
67+
{
68+
if (data == null)
69+
throw new ArgumentNullException("data");
70+
if (offset < 0)
71+
throw new ArgumentOutOfRangeException("offset");
72+
if (count < 0)
73+
throw new ArgumentOutOfRangeException("count", "Requires count >= 0");
74+
if ((uint)offset + (uint)count > (uint)data.Length)
75+
throw new ArgumentException("Requires offset + count <= data.Length");
76+
InternalWipe(data, offset, count);
77+
}
78+
79+
internal static void Wipe(ArraySegment<byte> data)
80+
{
81+
if (data.Array == null)
82+
throw new ArgumentNullException("data.Array");
83+
InternalWipe(data.Array, data.Offset, data.Count);
84+
}
85+
86+
// Secure wiping is hard
87+
// * the GC can move around and copy memory
88+
// Perhaps this can be avoided by using unmanaged memory or by fixing the position of the array in memory
89+
// * Swap files and error dumps can contain secret information
90+
// It seems possible to lock memory in RAM, no idea about error dumps
91+
// * Compiler could optimize out the wiping if it knows that data won't be read back
92+
// I hope this is enough, suppressing inlining
93+
// but perhaps `RtlSecureZeroMemory` is needed
94+
[MethodImpl(MethodImplOptions.NoInlining)]
95+
internal static void InternalWipe(byte[] data, int offset, int count)
96+
{
97+
Array.Clear(data, offset, count);
98+
}
99+
100+
// shallow wipe of structs
101+
[MethodImpl(MethodImplOptions.NoInlining)]
102+
internal static void InternalWipe<T>(ref T data)
103+
where T : struct
104+
{
105+
data = default(T);
106+
}
107+
108+
// constant time hex conversion
109+
// see http://stackoverflow.com/a/14333437/445517
110+
//
111+
// An explanation of the weird bit fiddling:
112+
//
113+
// 1. `bytes[i] >> 4` extracts the high nibble of a byte
114+
// `bytes[i] & 0xF` extracts the low nibble of a byte
115+
// 2. `b - 10`
116+
// is `< 0` for values `b < 10`, which will become a decimal digit
117+
// is `>= 0` for values `b > 10`, which will become a letter from `A` to `F`.
118+
// 3. Using `i >> 31` on a signed 32 bit integer extracts the sign, thanks to sign extension.
119+
// It will be `-1` for `i < 0` and `0` for `i >= 0`.
120+
// 4. Combining 2) and 3), shows that `(b-10)>>31` will be `0` for letters and `-1` for digits.
121+
// 5. Looking at the case for letters, the last summand becomes `0`, and `b` is in the range 10 to 15. We want to map it to `A`(65) to `F`(70), which implies adding 55 (`'A'-10`).
122+
// 6. Looking at the case for digits, we want to adapt the last summand so it maps `b` from the range 0 to 9 to the range `0`(48) to `9`(57). This means it needs to become -7 (`'0' - 55`).
123+
// Now we could just multiply with 7. But since -1 is represented by all bits being 1, we can instead use `& -7` since `(0 & -7) == 0` and `(-1 & -7) == -7`.
124+
//
125+
// Some further considerations:
126+
//
127+
// * I didn't use a second loop variable to index into `c`, since measurement shows that calculating it from `i` is cheaper.
128+
// * Using exactly `i < bytes.Length` as upper bound of the loop allows the JITter to eliminate bounds checks on `bytes[i]`, so I chose that variant.
129+
// * Making `b` an int avoids unnecessary conversions from and to byte.
130+
internal static string ToHexStringUpper(byte[] data)
131+
{
132+
if (data == null)
133+
return null;
134+
char[] c = new char[data.Length * 2];
135+
int b;
136+
for (int i = 0; i < data.Length; i++)
137+
{
138+
b = data[i] >> 4;
139+
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
140+
b = data[i] & 0xF;
141+
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
142+
}
143+
return new string(c);
144+
}
145+
146+
// Explanation is similar to ToHexStringUpper
147+
// constant 55 -> 87 and -7 -> -39 to compensate for the offset 32 between lowercase and uppercase letters
148+
internal static string ToHexStringLower(byte[] data)
149+
{
150+
if (data == null)
151+
return null;
152+
char[] c = new char[data.Length * 2];
153+
int b;
154+
for (int i = 0; i < data.Length; i++)
155+
{
156+
b = data[i] >> 4;
157+
c[i * 2] = (char)(87 + b + (((b - 10) >> 31) & -39));
158+
b = data[i] & 0xF;
159+
c[i * 2 + 1] = (char)(87 + b + (((b - 10) >> 31) & -39));
160+
}
161+
return new string(c);
162+
}
163+
164+
internal static byte[] FromHexString(string hexString)
165+
{
166+
if (hexString == null)
167+
return null;
168+
if (hexString.Length % 2 != 0)
169+
throw new FormatException("The hex string is invalid because it has an odd length");
170+
var result = new byte[hexString.Length / 2];
171+
for (int i = 0; i < result.Length; i++)
172+
result[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
173+
return result;
174+
}
175+
176+
internal static string ToBase64String(byte[] data)
177+
{
178+
if (data == null)
179+
return null;
180+
return Convert.ToBase64String(data);
181+
}
182+
183+
internal static byte[] FromBase64String(string s)
184+
{
185+
if (s == null)
186+
return null;
187+
return Convert.FromBase64String(s);
188+
}
189+
}
190+
}

0 commit comments

Comments
 (0)