Home > Back-end >  C# Decoding Active Directory SID third digit being decoded incorrectly. All other's correct
C# Decoding Active Directory SID third digit being decoded incorrectly. All other's correct

Time:05-06

I retrieve an objectsid value from Active Directory. It comes as a base64 encoded string.

I have the following function (below) to decode this into an actual SID text string.

The following function works just fine in all cases except a few.

When examined in the Active Directory Attribute Editor, a SID of "S-1-5-21-3477787073-812361429-1014394821" is being returned instead as "S-1-4-21-3477787073-812361429-1014394821". The third digit is off by one.

Likewise, a SID of "S-1-5-32-573" is being returned as "S-1-2-32-573", and again, the third digit is short by 3.

I've debugged it enough to figure out that it is the length of the byte[] array that is different, and I think is the cause of this error.

When the byte array is 28 bits, it decodes correctly. If it is shorter than 28 bits, the third SID digit is off directly relative to how much shorter the byte[] array is.

I think there is something about the for() loop condition i < bytes[7], even though byte[7] seems to always be 5 in all cases (at least the ones that I have breakpointed).

Or possibly the BitConverter's second parameter (8 (i * 4)). If byte[7] is always 5, then (5*4) 8 = 28. And when the byte array is 28 bits, the return value is always correct. It is when the byte[] array is less than 28 bits that the return value is wrong.

I did not write this function (found on another stack overflow question answer), so I do not really understand what it is doing beyond what I've described here. I did add the code comments.

public static string Base64DecodeSID(string data) {

if (data == "") {
    return "";
}

byte[] bytes = Convert.FromBase64String(data);

try {

    string sid = "S-"   bytes[0].ToString();                                        // Add SID revision.

    if (bytes[6] != 0 || bytes[5] != 0) {                                           // SID authority

        sid  = ("-"  
            String.Format(                                                          // Left 0-pad hex
                "0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",                           // values to 2 places.
                bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6]
            )
        );

    } else {
        sid  = ("-"   (bytes[1]   (bytes[2] << 8)   (bytes[3] << 16)   (bytes[4] << 24)).ToString());
    }

    for (int i = 0; i < bytes[7]; i  ) {                                            // Sub-Authority...
        sid  = ("-"   BitConverter.ToUInt32(bytes, 8   (i * 4)).ToString()); 
        
    }

    return sid;

}

(I excluded the catch() for brevity)

Example

Base64: "AQQAAAAAAAUVAAAAwdFKz9WmazDFb3Y8"

Decoded byte[] array:

[00] 1
[01] 4
[02] 0
[03] 0
[04] 0
[05] 0
[06] 0
[07] 5
[08] 21
[09] 0
[10] 0
[11] 0
[12] 193
[13] 209
[14] 74
[15] 207
[16] 213
[17] 166
[18] 107
[19] 48
[20] 197
[21] 111
[22] 118
[23] 60

Expected return value: "S-1-5-21-3477787073-812361429-1014394821"

Actual return value: "S-1-4-21-3477787073-812361429-1014394821"

Any idea how to fix this? Do I need to pad the array out to 28, or even 32 bits?

CodePudding user response:

As noted in the comments, the SecurityIdentifier class makes this easy:

public static string Base64DecodeSID(string data) {

    var bytes = Convert.FromBase64String(data);
    
    var sid = new SecurityIdentifier(bytes, 0);
    
    return sid.Value;
}

You may want to add some error checks in there in case it's passed a bad value.

Calling Base64DecodeSID("AQQAAAAAAAUVAAAAwdFKz9WmazDFb3Y8") returns S-1-5-21-3477787073-812361429-1014394821

  • Related