Adding all users SID's from Active Directory in C# - c#
I have an issue not able to add all Sid's to my current loop. Everything else is working as I expected. I just need help adding in my code to add the SID for each user my code is displaying. The SID will now show.
new error message:
Here is my current code:
namespace ActiveDirectoryDisplayNamesApp
{
class Program
{
static void Main(string[] args)
{
using (var context = new PrincipalContext(ContextType.Domain, "nor-amcoldcorp.local"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
var sidByte = ObjectToByteArray(de.Properties["objectSId"].Value);
Console.WriteLine("First Name: " + de.Properties["givenName"].Value);
Console.WriteLine("Last Name : " + de.Properties["sn"].Value);
Console.WriteLine("SAM account name : " + de.Properties["samAccountName"].Value);
Console.WriteLine("User principal name: " + de.Properties["userPrincipalName"].Value);
Console.WriteLine("Object Sid: " + System.Text.Encoding.UTF8.GetString(sidByte)); //Here is the changement
Console.WriteLine();
}
}
}
Console.ReadLine();
}
static public byte[] ObjectToByteArray(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
}
de.Properties["objectSid"].value returns a Byte [] array, to view the SID you will need to parse this into a string to get the functionality you are looking for. A good post on how to do that can be found here.
Below is the function you will need to convert the array into a usable string:
public static string ConvertByteToStringSid(Byte[] sidBytes)
{
StringBuilder strSid = new StringBuilder();
strSid.Append("S-");
try
{
// Add SID revision.
strSid.Append(sidBytes[0].ToString());
// Next six bytes are SID authority value.
if (sidBytes[6] != 0 || sidBytes[5] != 0)
{
string strAuth = String.Format
("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
(Int16)sidBytes[1],
(Int16)sidBytes[2],
(Int16)sidBytes[3],
(Int16)sidBytes[4],
(Int16)sidBytes[5],
(Int16)sidBytes[6]);
strSid.Append("-");
strSid.Append(strAuth);
}
else
{
Int64 iVal = (Int32)(sidBytes[1]) +
(Int32)(sidBytes[2] << 8) +
(Int32)(sidBytes[3] << 16) +
(Int32)(sidBytes[4] << 24);
strSid.Append("-");
strSid.Append(iVal.ToString());
// Get sub authority count...
int iSubCount = Convert.ToInt32(sidBytes[7]);
int idxAuth = 0;
for (int i = 0; i < iSubCount; i++)
{
idxAuth = 8 + i * 4;
UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
strSid.Append("-");
strSid.Append(iSubAuth.ToString());
}
}
catch (Exception ex)
{
}
return strSid.ToString();
}
And here is what you will need to call the function:
System.DirectoryServices.PropertyCollection coll = de.Properties;
object obVal = coll["objectSid"].Value;
string yourSID;
if (null != obVal)
{
yourSID = ConvertByteToStringSid((Byte[])obVal);
}
EDIT :
Declare this function :
private byte[] ObjectToByteArray(Object obj)
{
if(obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
Than do this :
byte[] bytes = Encoding.Default.GetBytes(de.Properties["objectSid"].value);
sidByte= Encoding.UTF8.GetString(bytes);
Console.WriteLine("Object Sid: " + sidByte ); //Here is the changement
Or you try this approcah (if the first one didn't work) but keep the first function that will convert your byte object to byte :
Declare a function
static string BytesToStringConverted(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
{
using (var streamReader = new StreamReader(stream))
{
return streamReader.ReadToEnd();
}
}
}
Than call it like that :
Console.WriteLine("Object Sid: " +BytesToStringConverted (sidByte)
There is already a dedicated Sid class that you can use for decoding Sid data.
var sidBytes = (byte[])de.Properties["objectSId"].Value;
var sid = new SecurityIdentifier(sidBytes ,0);
string strSid = sid.Value;//Something like S-1-5-21..
.
For hexadecimal form, it should be: string strAuth = String.Format("0x{0:x2}{1:x2}{2:x2}{3:x2}{4:x2}{5:x2}",
For .NET 5, SecurityIdentifier only available on Windows.
https://github.com/dotnet/runtime/blob/6bc6560e51d1cf58b54561f7be44801864479b8d/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs#L403-L478
Found few bugs from the original
https://www.codeproject.com/articles/3688/how-to-get-user-sid-using-directoryservices-classe
public static string ConvertByteToStringSid(Byte[] sidBytes)
hexadecimal conversion (Wrong "0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}", right: "0x{0:x2}{1:x2}{2:x2}{3:x2}{4:x2}{5:x2}")
Sub Authority Count at the second byte, not the 8th byte (Wrong Convert.ToInt32(sidBytes[7]), right: Convert.ToInt32(sidBytes[1]))
I have followed the original implementation and compare with the result from class SecurityIdentifier, also consider the comment:
SID decoding is wrong Pin
Hi there,
I think your SID decoding is wrong. The number of sub authorities is the 2nd byte in the SID byte array, not the 8th, and the main authority has its bytes stored in the other order from the one you're reading in.
I'd like to share a better version, can be found at:
https://gist.github.com/thohng/8820153f7d1e107b6619b34fd765f887:
public static string ConvertByteToStringSid(byte[] sidBytes)
{
if (sidBytes == null || sidBytes.Length < 8 ||
sidBytes.Length > 68) // maximum 15 sub authorities
return string.Empty;
var span = new ReadOnlySpan<byte>(sidBytes);
var strSid = new StringBuilder("S-");
// Add SID revision.
strSid.Append(span[0]);
// Get sub authority count...
var subAuthoritiesLength = Convert.ToInt32(span[1]);
if (sidBytes.Length != 8 + subAuthoritiesLength * 4)
return string.Empty;
long identifierAuthority =
(((long)span[2]) << 40) +
(((long)span[3]) << 32) +
(((long)span[4]) << 24) +
(((long)span[5]) << 16) +
(((long)span[6]) << 8) +
span[7];
strSid.Append('-');
strSid.Append(identifierAuthority);
span = span[8..];
for (int i = 0; i < subAuthoritiesLength; i++, span = span[4..])
{
strSid.Append('-');
strSid.Append(BitConverter.ToUInt32(span.Slice(0, 4)));
}
return strSid.ToString();
}
And unit tests:
private static Func<byte[], string> GetConvertByteToStringSidService() => LdapHelper.ConvertByteToStringSid;
[Fact]
public void ConvertByteToStringSid_Builtin()
{
var service = GetConvertByteToStringSidService();
var sid = new byte[] { 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0 };
var result = service(sid);
Assert.Equal("S-1-5-32-551", result);
}
[Fact]
[SupportedOSPlatform("windows")]
public void ConvertByteToStringSid_Builtin_Windows()
{
var sid = new byte[] { 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0 };
var s2 = new SecurityIdentifier(sid, 0);
Assert.Equal("S-1-5-32-551", s2.ToString());
}
[Fact]
public void ConvertByteToStringSid_Malformed()
{
var service = GetConvertByteToStringSidService();
var sid1 = new byte[] { 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0, 1 };
var result1 = service(sid1);
Assert.Equal("", result1);
var sid2 = new byte[] { 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0 };
var result2 = service(sid2);
Assert.Equal("", result2);
var sid3 = new byte[] { 1, 4, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0 };
var result3 = service(sid3);
Assert.Equal("", result3);
}
[Fact]
public void ConvertByteToStringSid_Max()
{
var service = GetConvertByteToStringSidService();
var sid = new byte[] { 1, 1, 255, 254, 253, 252, 0, 0, 251, 250, 249, 248 };
var result = service(sid);
Assert.Equal("S-1-281470647926784-4177132283", result);
var sid2 = new byte[] { 1, 5, 136, 0, 44, 89, 0xFE, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0 };
var result2 = service(sid2);
Assert.Equal("S-1-149534325472773-21-71093982-54227939-39018152-1025", result2);
}
[Fact]
[SupportedOSPlatform("windows")]
public void ConvertByteToStringSid_Max_Windows()
{
var sid = new byte[] { 1, 1, 255, 254, 253, 252, 0, 0, 251, 250, 249, 248 };
var s1 = new SecurityIdentifier(sid, 0);
Assert.Equal("S-1-281470647926784-4177132283", s1.ToString());
var sid2 = new byte[] { 1, 5, 136, 0, 44, 89, 0xFE, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0 };
var s2 = new SecurityIdentifier(sid2, 0);
Assert.Equal("S-1-149534325472773-21-71093982-54227939-39018152-1025", s2.ToString());
}
[Fact]
public void ConvertByteToStringSid_NullEmpty()
{
var service = GetConvertByteToStringSidService();
var sid1 = Array.Empty<byte>();
var result1 = service(sid1);
Assert.Equal("", result1);
var result2 = service(null);
Assert.Equal("", result2);
}
[Fact]
public void ConvertByteToStringSid_Success()
{
var service = GetConvertByteToStringSidService();
var sid = new byte[] { 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0 };
var result = service(sid);
Assert.Equal("S-1-5-21-71093982-54227939-39018152-1025", result);
}
[Fact]
[SupportedOSPlatform("windows")]
public void ConvertByteToStringSid_Windows()
{
var sid = new byte[] { 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 222, 206, 60, 4, 227, 115, 59, 3, 168, 94, 83, 2, 1, 4, 0, 0 };
var s1 = new SecurityIdentifier(sid, 0);
Assert.Equal("S-1-5-21-71093982-54227939-39018152-1025", s1.ToString());
}
Related
Why did I have to use an int to combine these enum flag values together?
Perhaps someone can just explain the logic behind why this is actually an issue. In my C# DLL I have a set of flag values that expose via the COM API: [Flags] [Guid("~~~")] [ComVisible(true)] public enum AssignmentType { None = 0, Attendant = 1, ConductorCBS = 2, ReaderCBS = 4, Chairman = 8, Mike = 16, PlatformAttendant = 32, Prayer = 64, OCLM = 128, Sound = 256, Student = 512, Custom = 1024, Demonstration = 2048, Assistant = 4096, Host = 8192, CoHost = 16384, OCLMTreasures = 32768, OCLMGems = 65536, OCLMLiving = 131072, StudentBibleReading = 262144, StudentDiscussion = 524288, StudentTalk = 1048576 } In my C++ MFC project, the above is exposed as follows: enum __declspec(uuid("~~~")) AssignmentType { AssignmentType_None = 0, AssignmentType_Attendant = 1, AssignmentType_ConductorCBS = 2, AssignmentType_ReaderCBS = 4, AssignmentType_Chairman = 8, AssignmentType_Mike = 16, AssignmentType_PlatformAttendant = 32, AssignmentType_Prayer = 64, AssignmentType_OCLM = 128, AssignmentType_Sound = 256, AssignmentType_Student = 512, AssignmentType_Custom = 1024, AssignmentType_Demonstration = 2048, AssignmentType_Assistant = 4096, AssignmentType_Host = 8192, AssignmentType_CoHost = 16384, AssignmentType_OCLMTreasures = 32768, AssignmentType_OCLMGems = 65536, AssignmentType_OCLMLiving = 131072, AssignmentType_StudentBibleReading = 262144, AssignmentType_StudentDiscussion = 524288, AssignmentType_StudentTalk = 1048576 }; This is the part of don't get: int iFlag = MSAToolsLibrary::AssignmentType::AssignmentType_None; for (int iIndex = 0; iIndex < m_lbAssignmentsOCLM.GetCount(); iIndex++) { if (m_lbAssignmentsOCLM.GetCheck(iIndex) == BST_CHECKED) { iFlag |= static_cast<MSAToolsLibrary::AssignmentType>(m_lbAssignmentsOCLM.GetItemData(iIndex));; } } theApp.WriteProfileInt( theApp.GetActiveScheduleSection(_T("Options")), _T("SRR_AssignmentsOCLM"), iFlag); I had to use int for the iFlag variable. If I try to make that variable a MSAToolsLibrary::AssignmentType then the |= line will not work. Yet, I am able to make calls like this to the API: const COleDateTime datMeeting = GetMeetingDate(iRow); auto eTypesToInclude = static_cast<MSAToolsLibrary::AssignmentType>(GetAssignmentsOCLMFlag()); CStringArray aryStrMeetingPersonnel; theApp.MSAToolsInterface().GetPersonnelForMeeting( datMeeting, theApp.GetAssignHistoryPathEx(), eTypesToInclude, aryStrMeetingPersonnel); In short, why is it OK to pass the combined flag values as a MSAToolsLibrary::AssignmentType to a function in the API, but I had to use an int to build the compiled flags value first. Make sense?
Get the shortest path between two linked object
I have a "Contact" object which contains a list called "Linked" containing the "Contact" linked to it. public class Contact { public int Id { get; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public List<Contact> Linked { get; set; } } For example, Contact "A" has 3 linked contacts: B, C and D. As the links are made in both directions each time, B, C and D all have A in their "Linked" contacts. B can then have E as a contact, and so on. There is no limit. I have to make an algo which takes a starting contact and an ending contact as a parameter and which finds the shortest path that links them. The result must be in the form: A > B > F > H > X, if I have to find the path that goes from A to X. We must therefore find all the steps of the path in the result. I've tried a lot of stuff (recursion, ...) but it's still getting stuck somewhere. Do you have an idea?
Dijkstra's algorithm is probably what you are looking for. http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm Dijkstra's algorithm (/ˈdaɪkstrəz/ DYKE-strəz) is an algorithm for finding the shortest paths between nodes in a graph, which may represent, for example, road networks. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.[4][5][6] It should be relatively straight forward to find examples in your given language. Here is one in C#, stolen from programmingalgorithms.com private static int MinimumDistance(int[] distance, bool[] shortestPathTreeSet, int verticesCount) { int min = int.MaxValue; int minIndex = 0; for (int v = 0; v < verticesCount; ++v) { if (shortestPathTreeSet[v] == false && distance[v] <= min) { min = distance[v]; minIndex = v; } } return minIndex; } private static void Print(int[] distance, int verticesCount) { Console.WriteLine("Vertex Distance from source"); for (int i = 0; i < verticesCount; ++i) Console.WriteLine("{0}\t {1}", i, distance[i]); } public static void Dijkstra(int[,] graph, int source, int verticesCount) { int[] distance = new int[verticesCount]; bool[] shortestPathTreeSet = new bool[verticesCount]; for (int i = 0; i < verticesCount; ++i) { distance[i] = int.MaxValue; shortestPathTreeSet[i] = false; } distance[source] = 0; for (int count = 0; count < verticesCount - 1; ++count) { int u = MinimumDistance(distance, shortestPathTreeSet, verticesCount); shortestPathTreeSet[u] = true; for (int v = 0; v < verticesCount; ++v) if (!shortestPathTreeSet[v] && Convert.ToBoolean(graph[u, v]) && distance[u] != int.MaxValue && distance[u] + graph[u, v] < distance[v]) distance[v] = distance[u] + graph[u, v]; } Print(distance, verticesCount); } It would then be used like so: int[,] graph = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 }, { 4, 0, 8, 0, 0, 0, 0, 11, 0 }, { 0, 8, 0, 7, 0, 4, 0, 0, 2 }, { 0, 0, 7, 0, 9, 14, 0, 0, 0 }, { 0, 0, 0, 9, 0, 10, 0, 0, 0 }, { 0, 0, 4, 0, 10, 0, 2, 0, 0 }, { 0, 0, 0, 14, 0, 2, 0, 1, 6 }, { 8, 11, 0, 0, 0, 0, 1, 0, 7 }, { 0, 0, 2, 0, 0, 0, 6, 7, 0 } }; Dijkstra(graph, 0, 9); The example above consist of 9 nodes, and the distance to each of the other nodes. If it has 0, there is no connection. In your case, there is no weight - so either there is a connection (1), or there isn't (0). You have to change the algorithm to take in a list of contacts, instead of a two dimensional array. Try to think of the two dimensional array as a list of lists - very similar to a list of contacts, where each contact has another list of contacts. Lets for example create a simple contacts list and their contacts: Peter can contact Mary Mary can contact Peter and John John can contact Mary This would be represented something like this in a two dimensional array: int[,] contacts = new int[] { { 0, 1, 0 }, //Peter: Peter no, Mary yes, John no { 1, 0, 1 }, //Mary: Peter yes, Mary no, John yes { 0, 1, 0 } //John: Peter no, Mary yes, John no } You would also have to modify the algorithm to keep track of the current path. That should be a relatively straight forward change. Hope that it helps!
Error splitting an array into two
So I need to cut off the first 16 bytes from my byte array. I followed another post I saw on Stack Overflow to use the following code: //split message into iv and encrypted bytes byte[] iv = new byte[16]; byte[] workingHash = new byte[rage.Length - 16]; //put first 16 bytes into iv for (int i = 0; i < 16; i++) { iv[i] = rage[i]; } Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length); What we are trying here is to cut off the first 16 bytes from the byte[] rage and put the rest into byte[] workingHash The error occurs at Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length); Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. Any help will be much appreciated.
The problem is trivial: Buffer.BlockCopy's last argument requires the correct number of bytes to be copied, which (taking the starting index into account) may not exceed the array's bounds (docs). Hence the code should look like this, avoiding any for cycles: Buffer.BlockCopy(rage, 0, iv, 0, 16); Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length - 16); Notice the “- 16” at the second line, fixing the original code. The first line replaces the for cycle for the sake of consistency.
Lets assume rage is a byte array of length 20: var rage = new byte[20] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; After byte[] iv = new byte[16];, iv will contain: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } After byte[] workingHash = new byte[rage.Length - 16];, workingHash will contain: { 0, 0, 0, 0 } After the for loop iv is: { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } You need: Buffer.BlockCopy(rage, 16, workingHash, 0, rage.Length - 16); Copy rage.Length - 16 (4) elements from rage's 16th element (which is 17) to workingHash starting from the 0th element. The result: { 17, 18, 19, 20 } By the way there is a very readable way, probably not as fast as copying arrays, but worth mentioning: var firstSixteenElements = rage.Take(16).ToArray(); var remainingElements = rage.Skip(16).ToArray();
Fixed: //split message into iv and encrypted bytes byte[] iv = new byte[16]; byte[] workingHash = new byte[rage.Length - 16]; //put first 16 bytes into iv for (int i = 0; i < 16; i++) { iv[i] = rage[i]; } for (int i = 0; i < rage.Length - 16; i++) { workingHash[i] = rage[i + 16]; }
Interview test - adding using A Recursive Algorithm c#
Below is an interview question about using recursion to add two arrays. I can't figure it out though because it does not seem to allow any kind of index to keep track of where you are, I have been down a few roads - trying to test for null / default values in the array but because it is a byte[] type nothing worked. Any help would be great thanks - this is not a homework question. public AddResult UsingARecursiveAlgorithm_ValuesAreAdded(byte[] a, byte[] b) { var result = AddRecursive(a, b); // Assert return new AddResult(a, b, result); } e.g. Input : { 1, 1, 1 }, { 1, 1, 1 } Result: { 2, 2, 2 } Input : { 1, 1, 255 }, { 0, 0, 1 } Result: { 1, 2, 0 } Conditions: a & b are never null, and are always of the same length. The algorithm should be non destructive to the inputs. Edit: the second result is incorrect. It should be { 1,1,0 } -that's the way it was presented though.
private int carry = 0; public byte[] AddRecursive(byte[] a, byte[] b) { //Start from bottom of the byte[] array a = a.Reverse().ToArray(); b = b.Reverse().ToArray(); if (a.Length == 0) return new byte[] { }; int tempresult = a[0] + b[0] + carry; byte[] z = new byte[] { (byte)(tempresult) }; carry = tempresult / (byte.MaxValue + 1); return z.Concat(AddRecursive(a.Skip(1).ToArray(), b.Skip(1).ToArray())).ToArray(); } //Test// [Test] public void Add_UsingARecursiveAlgorithm_ValuesAreAdded() { //First Test byte[] expectedResult = addthisaddthat.AddRecursive(new byte[] { 1, 1, 1 }, new byte[] { 1, 1, 1 }).Reverse().ToArray(); Assert.That(expectedResult, Is.EqualTo(new byte[] { 2, 2, 2 })); //Sec Test expectedResult = addthisaddthat.AddRecursive(new byte[] { 1, 1, 255 }, new byte[] { 0, 0, 1 }).Reverse().ToArray(); Assert.That(expectedResult, Is.EqualTo(new byte[] { 1, 2, 0 })); //Third Test expectedResult = addthisaddthat.AddRecursive(new byte[] { 255, 255, 255 }, new byte[] { 255, 255, 255 }).Reverse().ToArray(); Assert.That(expectedResult, Is.EqualTo(new byte[] { 255, 255, 254 })); }
Ok here is some rather "ugly" code that does what you want. I tried to write it for clarity rather than brevity: static byte[] AddArray(byte[] ary1, byte[] ary2) { System.Diagnostics.Debug.Assert(ary1.Length == ary2.Length); if ((ary1 == null) || (ary2 == null)) { throw new ArgumentException("Empty or null array"); } // sum the last element var ix = ary1.Length - 1; var sum = (ary1[ix] + ary2[ix]); if (sum > byte.MaxValue) { if (ix == 0) { throw new ArgumentException("Overflow"); } // Add carry by recursing on ary1 var carry = (byte) (sum - byte.MaxValue); var carryAry = new byte[ary1.Length]; carryAry[ix - 1] = carry; ary1 = AddArray(ary1, carryAry); } if ((ary1.Length == 1) || (ary2.Length == 1)) { return new byte[] { (byte) sum }; // end recursion } // create the remainder, elements from 0 it (len-1) var ary1Remainder = new byte[ary1.Length - 1]; var ary2Remainder = new byte[ary2.Length - 1]; Array.Copy(ary1, 0, ary1Remainder, 0, ary1.Length - 1); Array.Copy(ary2, 0, ary2Remainder, 0, ary2.Length - 1); // recurse var remainder = AddArray(ary1Remainder, ary2Remainder); // build return array (using linq Concat) var rv = (remainder.Concat(new byte[] { (byte) sum })); return rv.ToArray(); // return as an array }
This would be cleaner without all the casting and ToArray required because the values are byte[] and not IEnumerable<int>, but: private byte[] AddRecursive(byte[] a, byte[] b) { if (a.Length == 0) return new byte[]{}; return new byte[] { (byte)(a[0] + b[0]) }.Concat( AddRecursive(a.Skip(1).ToArray(), b.Skip(1).ToArray()) ).ToArray(); }
Maybe your interviewer had something like this in mind: using System; using System.Linq; public class Program { public static byte[] Add(byte[] a, byte[] b, int index = -1) { if (index < 0) { return Add((byte[])a.Clone(), b, 0); } if (index < a.Length) { Add(a, b, index + 1); a[index] += b[index]; } return a; } public static void Main(string[] args) { var r1 = Add(new byte[] { 1, 1, 1 }, new byte[] { 1, 1, 1 }); var r2 = Add(new byte[] { 1, 1, 255 }, new byte[] { 0, 0, 1 }); var r3 = Add(new byte[] { 0, 100, 200 }, new byte[] { 3, 2, 1 }); // Outputs: 2, 2, 2 Console.WriteLine(string.Join(", ", r1.Select(n => "" + n).ToArray())); // Outputs: 1, 1, 0 Console.WriteLine(string.Join(", ", r2.Select(n => "" + n).ToArray())); // Outputs: 3, 102, 201 Console.WriteLine(string.Join(", ", r3.Select(n => "" + n).ToArray())); } } https://dotnetfiddle.net/UqSQb3 Note this (only partial) solution doesn't handle the carry on byte overflows, though. 'Hope this helps,
6 bytes timestamp to DateTime
I use 3rd party API. According to its specification the following byte[] timestamp = new byte[] {185, 253, 177, 161, 51, 1} represents Number of milliseconds from Jan 1, 1970 when the message was generated for transmission The issue is that I don't know how it could be translated into DateTime. I've tried DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); long milliseconds = BitConverter.ToUInt32(timestamp, 0); var result = Epoch + TimeSpan.FromMilliseconds(milliseconds); The result is {2/1/1970 12:00:00 AM}, but year 2012 is expected.
byte[] timestamp = new byte[] { 185, 253, 177, 161, 51, 1, 0, 0, }; DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); ulong milliseconds = BitConverter.ToUInt64(timestamp, 0); var result = Epoch + TimeSpan.FromMilliseconds(milliseconds); Result is 11/14/2011 Adding padding code special for CodeInChaos: byte[] oldStamp = new byte[] { 185, 253, 177, 161, 51, 1 }; byte[] newStamp = new byte[sizeof(UInt64)]; Array.Copy(oldStamp, newStamp, oldStamp.Length); For running on big-endian machines : if (!BitConverter.IsLittleEndian) { newStamp = newStamp.Reverse().ToArray(); }
I assume timestamp uses little endian format. I also left out parameter validation. long GetLongLE(byte[] buffer,int startIndex,int count) { long result=0; long multiplier=1; for(int i=0;i<count;i++) { result += buffer[startIndex+i]*multiplier; multiplier *= 256; } return result; } long milliseconds = GetLongLE(timestamp, 0, 6);