# < Summary

Information

Class: | Renci.SshNet.Security.Chaos.NaCl.CryptoBytes
Assembly: | Renci.SshNet
File(s): | \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Chaos.NaCl\CryptoBytes.cs

Line coverage
20%

Covered lines: | 23
Uncovered lines: | 91
Coverable lines: | 114
Total lines: | 190
Line coverage: | 20.1%

Branch coverage
17%

Covered branches: | 10
Total branches: | 58
Branch coverage: | 17.2%

Method coverage

Feature is only available for sponsors

Upgrade to PRO version

# Metrics

Method | Branch coverage | Cyclomatic complexity | Line coverage
--- | --- | --- | ---
ConstantTimeEquals(...) | 0% | 6 | 0%
ConstantTimeEquals(...) | 0% | 6 | 0%
ConstantTimeEquals(...) | 50% | 14 | 58.82%
InternalConstantTimeEquals(...) | 100% | 2 | 100%
Wipe(...) | 50% | 2 | 80%
Wipe(...) | 0% | 8 | 0%
Wipe(...) | 0% | 2 | 0%
InternalWipe(...) | 100% | 1 | 100%
InternalWipe(...) | 100% | 1 | 0%
ToHexStringUpper(...) | 0% | 4 | 0%
ToHexStringLower(...) | 0% | 4 | 0%
FromHexString(...) | 0% | 6 | 0%
ToBase64String(...) | 0% | 2 | 0%
FromBase64String(...) | 0% | 2 | 0%

# File(s)

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

| # | Line |  | Line coverage
--- | --- | --- | --- | ---
|  | `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)`
| 0 | `9` |  | `{`
| 0 | `10` |  | `if (x == null)`
| 0 | `11` |  | `throw new ArgumentNullException("x");`
| 0 | `12` |  | `if (y == null)`
| 0 | `13` |  | `throw new ArgumentNullException("y");`
| 0 | `14` |  | `if (x.Length != y.Length)`
| 0 | `15` |  | `throw new ArgumentException("x.Length must equal y.Length");`
| 0 | `16` |  | `return InternalConstantTimeEquals(x, 0, y, 0, x.Length) != 0;`
| 0 | `17` |  | `}`
|  | `18` |  | ``
|  | `19` |  | `internal static bool ConstantTimeEquals(ArraySegment<byte> x, ArraySegment<byte> y)`
| 0 | `20` |  | `{`
| 0 | `21` |  | `if (x.Array == null)`
| 0 | `22` |  | `throw new ArgumentNullException("x.Array");`
| 0 | `23` |  | `if (y.Array == null)`
| 0 | `24` |  | `throw new ArgumentNullException("y.Array");`
| 0 | `25` |  | `if (x.Count != y.Count)`
| 0 | `26` |  | `throw new ArgumentException("x.Count must equal y.Count");`
|  | `27` |  | ``
| 0 | `28` |  | `return InternalConstantTimeEquals(x.Array, x.Offset, y.Array, y.Offset, x.Count) != 0;`
| 0 | `29` |  | `}`
|  | `30` |  | ``
|  | `31` |  | `internal static bool ConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length)`
| 3 | `32` |  | `{`
| 3 | `33` |  | `if (x == null)`
| 0 | `34` |  | `throw new ArgumentNullException("x");`
| 3 | `35` |  | `if (xOffset < 0)`
| 0 | `36` |  | `throw new ArgumentOutOfRangeException("xOffset", "xOffset < 0");`
| 3 | `37` |  | `if (y == null)`
| 0 | `38` |  | `throw new ArgumentNullException("y");`
| 3 | `39` |  | `if (yOffset < 0)`
| 0 | `40` |  | `throw new ArgumentOutOfRangeException("yOffset", "yOffset < 0");`
| 3 | `41` |  | `if (length < 0)`
| 0 | `42` |  | `throw new ArgumentOutOfRangeException("length", "length < 0");`
| 3 | `43` |  | `if (x.Length - xOffset < length)`
| 0 | `44` |  | `throw new ArgumentException("xOffset + length > x.Length");`
| 3 | `45` |  | `if (y.Length - yOffset < length)`
| 0 | `46` |  | `throw new ArgumentException("yOffset + length > y.Length");`
|  | `47` |  | ``
| 3 | `48` |  | `return InternalConstantTimeEquals(x, xOffset, y, yOffset, length) != 0;`
| 3 | `49` |  | `}`
|  | `50` |  | ``
|  | `51` |  | `private static uint InternalConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length)`
| 3 | `52` |  | `{`
| 3 | `53` |  | `int differentbits = 0;`
| 198 | `54` |  | `for (int i = 0; i < length; i++)`
| 96 | `55` |  | `differentbits |= x[xOffset + i] ^ y[yOffset + i];`
| 3 | `56` |  | `return (1 & (unchecked((uint)differentbits - 1) >> 8));`
| 3 | `57` |  | `}`
|  | `58` |  | ``
|  | `59` |  | `internal static void Wipe(byte[] data)`
| 2358 | `60` |  | `{`
| 2358 | `61` |  | `if (data == null)`
| 0 | `62` |  | `throw new ArgumentNullException("data");`
| 2358 | `63` |  | `InternalWipe(data, 0, data.Length);`
| 2358 | `64` |  | `}`
|  | `65` |  | ``
|  | `66` |  | `internal static void Wipe(byte[] data, int offset, int count)`
| 0 | `67` |  | `{`
| 0 | `68` |  | `if (data == null)`
| 0 | `69` |  | `throw new ArgumentNullException("data");`
| 0 | `70` |  | `if (offset < 0)`
| 0 | `71` |  | `throw new ArgumentOutOfRangeException("offset");`
| 0 | `72` |  | `if (count < 0)`
| 0 | `73` |  | `throw new ArgumentOutOfRangeException("count", "Requires count >= 0");`
| 0 | `74` |  | `if ((uint)offset + (uint)count > (uint)data.Length)`
| 0 | `75` |  | `throw new ArgumentException("Requires offset + count <= data.Length");`
| 0 | `76` |  | `InternalWipe(data, offset, count);`
| 0 | `77` |  | `}`
|  | `78` |  | ``
|  | `79` |  | `internal static void Wipe(ArraySegment<byte> data)`
| 0 | `80` |  | `{`
| 0 | `81` |  | `if (data.Array == null)`
| 0 | `82` |  | `throw new ArgumentNullException("data.Array");`
| 0 | `83` |  | `InternalWipe(data.Array, data.Offset, data.Count);`
| 0 | `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)`
| 2373 | `96` |  | `{`
| 2373 | `97` |  | `Array.Clear(data, offset, count);`
| 2373 | `98` |  | `}`
|  | `99` |  | ``
|  | `100` |  | `// shallow wipe of structs`
|  | `101` |  | `[MethodImpl(MethodImplOptions.NoInlining)]`
|  | `102` |  | `internal static void InternalWipe<T>(ref T data)`
|  | `103` |  | `where T : struct`
| 0 | `104` |  | `{`
| 0 | `105` |  | `data = default(T);`
| 0 | `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 t`
|  | `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`
|  | `123` |  | `// Now we could just multiply with 7. But since -1 is represented by all bits being 1, we can instead use `& -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``
|  | `128` |  | `// * Using exactly `i < bytes.Length` as upper bound of the loop allows the JITter to eliminate bounds checks on`
|  | `129` |  | `// * Making `b` an int avoids unnecessary conversions from and to byte.`
|  | `130` |  | `internal static string ToHexStringUpper(byte[] data)`
| 0 | `131` |  | `{`
| 0 | `132` |  | `if (data == null)`
| 0 | `133` |  | `return null;`
| 0 | `134` |  | `char[] c = new char[data.Length * 2];`
|  | `135` |  | `int b;`
| 0 | `136` |  | `for (int i = 0; i < data.Length; i++)`
| 0 | `137` |  | `{`
| 0 | `138` |  | `b = data[i] >> 4;`
| 0 | `139` |  | `c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));`
| 0 | `140` |  | `b = data[i] & 0xF;`
| 0 | `141` |  | `c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));`
| 0 | `142` |  | `}`
| 0 | `143` |  | `return new string(c);`
| 0 | `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)`
| 0 | `149` |  | `{`
| 0 | `150` |  | `if (data == null)`
| 0 | `151` |  | `return null;`
| 0 | `152` |  | `char[] c = new char[data.Length * 2];`
|  | `153` |  | `int b;`
| 0 | `154` |  | `for (int i = 0; i < data.Length; i++)`
| 0 | `155` |  | `{`
| 0 | `156` |  | `b = data[i] >> 4;`
| 0 | `157` |  | `c[i * 2] = (char)(87 + b + (((b - 10) >> 31) & -39));`
| 0 | `158` |  | `b = data[i] & 0xF;`
| 0 | `159` |  | `c[i * 2 + 1] = (char)(87 + b + (((b - 10) >> 31) & -39));`
| 0 | `160` |  | `}`
| 0 | `161` |  | `return new string(c);`
| 0 | `162` |  | `}`
|  | `163` |  | ``
|  | `164` |  | `internal static byte[] FromHexString(string hexString)`
| 0 | `165` |  | `{`
| 0 | `166` |  | `if (hexString == null)`
| 0 | `167` |  | `return null;`
| 0 | `168` |  | `if (hexString.Length % 2 != 0)`
| 0 | `169` |  | `throw new FormatException("The hex string is invalid because it has an odd length");`
| 0 | `170` |  | `var result = new byte[hexString.Length / 2];`
| 0 | `171` |  | `for (int i = 0; i < result.Length; i++)`
| 0 | `172` |  | `result[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);`
| 0 | `173` |  | `return result;`
| 0 | `174` |  | `}`
|  | `175` |  | ``
|  | `176` |  | `internal static string ToBase64String(byte[] data)`
| 0 | `177` |  | `{`
| 0 | `178` |  | `if (data == null)`
| 0 | `179` |  | `return null;`
| 0 | `180` |  | `return Convert.ToBase64String(data);`
| 0 | `181` |  | `}`
|  | `182` |  | ``
|  | `183` |  | `internal static byte[] FromBase64String(string s)`
| 0 | `184` |  | `{`
| 0 | `185` |  | `if (s == null)`
| 0 | `186` |  | `return null;`
| 0 | `187` |  | `return Convert.FromBase64String(s);`
| 0 | `188` |  | `}`
|  | `189` |  | `}`
|  | `190` |  | `}`

# Methods/Properties

ConstantTimeEquals(System.Byte[],System.Byte[])
ConstantTimeEquals(System.ArraySegment`1<System.Byte>,System.ArraySegment`1<System.Byte>)
ConstantTimeEquals(System.Byte[],System.Int32,System.Byte[],System.Int32,System.Int32)
InternalConstantTimeEquals(System.Byte[],System.Int32,System.Byte[],System.Int32,System.Int32)
Wipe(System.Byte[])
Wipe(System.Byte[],System.Int32,System.Int32)
Wipe(System.ArraySegment`1<System.Byte>)
InternalWipe(System.Byte[],System.Int32,System.Int32)
InternalWipe(T&)
ToHexStringUpper(System.Byte[])
ToHexStringLower(System.Byte[])
FromHexString(System.String)
ToBase64String(System.Byte[])
FromBase64String(System.String)