Skip to content

Commit

Permalink
Update README.md - Fix Base46 input example
Browse files Browse the repository at this point in the history
  • Loading branch information
oviliz committed Sep 5, 2023
1 parent e52d9db commit 14a1507
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 92 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Python library to convert Windows [SIDs](https://en.wikipedia.org/wiki/Security_Identifier)

## Install

E.g:
`python3 setup.py install`

## Example

String input
Expand All @@ -22,7 +27,7 @@ Base46 input
import sid

mysid = sid.sid('AQUAAAAAAAUVAAAAoGXPfnhLm1/nfIdwCRwBAA==', sid.SID_BASE64)
print mysid
print(mysid)
```

Output
Expand Down
24 changes: 12 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''
"""
The MIT License (MIT)
Copyright (c) 2015 Sascha Spreitzer, Red Hat
Expand All @@ -20,23 +20,23 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
"""


from setuptools import setup


setup(
name = "sid",
version = "0.2",
author = "Sascha Spreitzer",
author_email = "[email protected]",
description = ("Python library to convert Windows SIDs"),
license = "MIT",
keywords = "windows sid",
url = "https://github.com/sspreitzer/python-sid",
package_dir = {'': 'src'},
packages = ['sid'],
name="sid",
version="0.3",
author="Sascha Spreitzer",
author_email="[email protected]",
description=("Python library to convert Windows SIDs"),
license="MIT",
keywords="windows sid",
url="https://github.com/sspreitzer/python-sid",
package_dir={"": "src"},
packages=["sid"],
classifiers=[
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
Expand Down
4 changes: 2 additions & 2 deletions src/sid/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'''
"""
A Python module to convert Windows SIDs
import sid
s = sid.sid('S-1-5-21-2127521184-1604012920-1887927527-72713')
print s.base64()
'''
"""


from .lib import *
112 changes: 57 additions & 55 deletions src/sid/lib.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''The lib contains exceptions, constants and the sid class'''
"""The lib contains exceptions, constants and the sid class"""

import base64
import struct
Expand All @@ -11,23 +11,25 @@


class sidException(Exception):
'''Base exception derived from Exception class'''
"""Base exception derived from Exception class"""

pass


class sidExceptionNoSuchType(sidException):
'''No such type exception. Used when class is not initialized properly.'''
"""No such type exception. Used when class is not initialized properly."""

pass


class sid(object):
'''Class to manage Windows SIDs'''
"""Class to manage Windows SIDs"""

def __init__(self, data, sidtype=SID_STRING):
'''
"""
Initialize class with either a string, binary or base64 sid.
For example, Anonymous user is string 'S-1-5-7'
'''
"""
if sidtype == SID_STRING:
self._sid = data
return
Expand All @@ -39,120 +41,120 @@ def __init__(self, data, sidtype=SID_STRING):
return
else:
raise sidExceptionNoSuchType()

def ldap(self):
'''Return ldap filter version of sid'''
"""Return ldap filter version of sid"""
return self.byteldap(self._sid)

def binary(self):
'''Return binary version of sid'''
"""Return binary version of sid"""
return self.byte(self._sid)

def base64(self):
'''Return base64 encoded version of binary sid'''
"""Return base64 encoded version of binary sid"""
return self.byteB64(self._sid)

def str(self):
'''Return sid as a string'''
"""Return sid as a string"""
return str(self)

def __str__(self):
'''sid class can be used as a string'''
"""sid class can be used as a string"""
return self._sid

def __repr__(self):
'''Return representation of sid'''
return repr( self._sid )
"""Return representation of sid"""
return repr(self._sid)

@classmethod
def longToByte(cls, integer, little_endian=True, size=4):
'''
"""
Convert a Python integer into bytes
integer - integer to convert
little_endian - True (default) or False for little or big endian
size - size to be returned, default is 4 (thats 32bit)
'''
"""
if little_endian:
return struct.pack('<q', integer)[0:size]
return struct.pack("<q", integer)[0:size]
else:
return struct.pack('>q', integer)[8-size:]
return struct.pack(">q", integer)[8 - size :]

@classmethod
def byteToLong(cls, byte, little_endian=True):
'''
"""
Convert bytes into a Python integer
byte - bytes to convert
little_endian - True (default) or False for little or big endian
'''
"""
if len(byte) > 8:
raise Exception('Bytes too long. Needs to be <= 8 or 64bit')
raise Exception("Bytes too long. Needs to be <= 8 or 64bit")
else:
if little_endian:
a = byte.ljust(8, b'\x00')
return struct.unpack('<q', a)[0]
a = byte.ljust(8, b"\x00")
return struct.unpack("<q", a)[0]
else:
a = byte.rjust(8, b'\x00')
return struct.unpack('>q', a)[0]
a = byte.rjust(8, b"\x00")
return struct.unpack(">q", a)[0]

@classmethod
def strsid(cls, byte):
'''
"""
Convert bytes into a string SID
byte - bytes to convert
'''
ret = 'S'
"""
ret = "S"
sid = []
sid.append(cls.byteToLong(byte[0:1]))
sid.append(cls.byteToLong(byte[2:2+6], False))
sid.append(cls.byteToLong(byte[2 : 2 + 6], False))
for i in range(8, len(byte), 4):
sid.append(cls.byteToLong(byte[i:i+4]))
sid.append(cls.byteToLong(byte[i : i + 4]))
for i in sid:
ret += '-' + str(i)
ret += "-" + str(i)
return ret

@classmethod
def byte(cls, strsid):
'''
"""
Convert a SID into bytes
strdsid - SID to convert into bytes
'''
sid = str.split(strsid, '-')
"""
sid = str.split(strsid, "-")
ret = bytearray()
sid.remove('S')
sid.remove("S")
for i in range(len(sid)):
sid[i] = int(sid[i])
sid.insert(1, len(sid)-2)
sid.insert(1, len(sid) - 2)
ret += cls.longToByte(sid[0], size=1)
ret += cls.longToByte(sid[1], size=1)
ret += cls.longToByte(sid[2], False, 6)
for i in range(3, len(sid)):
ret += cls.longToByte(sid[i])
return ret

@classmethod
def byteldap(cls, strsid):
'''
"""
Encode a sid into AD ldap search form
strsid - SID to encode
'''
ret = ''
a = binascii.hexlify(cls.byte(strsid)).decode('utf-8')
"""
ret = ""
a = binascii.hexlify(cls.byte(strsid)).decode("utf-8")
for i in range(0, len(a), 2):
ret += '\\' + a[i:i+2]
ret += "\\" + a[i : i + 2]
return ret

@classmethod
def byteB64(cls, strsid):
'''
"""
Encode a sid into base64
strsid - SID to encode
'''
"""
return base64.b64encode(cls.byte(strsid))

@classmethod
def b64Strsid(cls, data):
'''
"""
Decode a base64 SID into string
data - base64 encoded sid
'''
"""
return cls.strsid(base64.b64decode(data))
43 changes: 21 additions & 22 deletions src/sid/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

class Testsid(unittest.TestCase):
"""Class for testing sid"""
sid_null = 'S-1-0-0'
sid_sample = 'S-1-5-21-2127521184-1604012920-1887927527-72713'
sid_null_bin = bytearray(
b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

sid_null = "S-1-0-0"
sid_sample = "S-1-5-21-2127521184-1604012920-1887927527-72713"
sid_null_bin = bytearray(b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
sid_sample_bin = bytearray(
b'\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\xa0e\xcf~xK\x9b_\xe7|\x87p\t\x1c\x01\x00')
sid_null_b64 = b'AQEAAAAAAAAAAAAA'
sid_sample_b64 = b'AQUAAAAAAAUVAAAAoGXPfnhLm1/nfIdwCRwBAA=='
b"\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\xa0e\xcf~xK\x9b_\xe7|\x87p\t\x1c\x01\x00"
)
sid_null_b64 = b"AQEAAAAAAAAAAAAA"
sid_sample_b64 = b"AQUAAAAAAAUVAAAAoGXPfnhLm1/nfIdwCRwBAA=="

def test_init_string(self):
"""Test creating sids from strings"""
Expand All @@ -21,37 +22,35 @@ def test_init_string(self):

def test_init_base64(self):
"""Test creating sids from base64"""
self.assertEqual(self.sid_null, str(
sid.sid(self.sid_null_b64, sid.SID_BASE64)))
self.assertEqual(self.sid_sample, str(
sid.sid(self.sid_sample_b64, sid.SID_BASE64)))
self.assertEqual(self.sid_null, str(sid.sid(self.sid_null_b64, sid.SID_BASE64)))
self.assertEqual(
self.sid_sample, str(sid.sid(self.sid_sample_b64, sid.SID_BASE64))
)

def test_init_binary(self):
"""Test creating sids from binary"""
self.assertEqual(self.sid_null, str(
sid.sid(self.sid_null_bin, sid.SID_BINARY)))
self.assertEqual(self.sid_sample, str(
sid.sid(self.sid_sample_bin, sid.SID_BINARY)))
self.assertEqual(self.sid_null, str(sid.sid(self.sid_null_bin, sid.SID_BINARY)))
self.assertEqual(
self.sid_sample, str(sid.sid(self.sid_sample_bin, sid.SID_BINARY))
)

def test_ldap(self):
"""Test ldap filter form of sid"""
sid_null_ldap = '\\01\\01\\00\\00\\00\\00\\00\\00\\00\\00\\00\\00'
sid_sample_ldap = '\\01\\05\\00\\00\\00\\00\\00\\05\\15\\00\\00\\00\\a0\\65\\cf\\7e\\78\\4b\\9b\\5f\\e7\\7c\\87\\70\\09\\1c\\01\\00'
sid_null_ldap = "\\01\\01\\00\\00\\00\\00\\00\\00\\00\\00\\00\\00"
sid_sample_ldap = "\\01\\05\\00\\00\\00\\00\\00\\05\\15\\00\\00\\00\\a0\\65\\cf\\7e\\78\\4b\\9b\\5f\\e7\\7c\\87\\70\\09\\1c\\01\\00"
self.assertEqual(sid_null_ldap, sid.sid(self.sid_null).ldap())
self.assertEqual(sid_sample_ldap, sid.sid(self.sid_sample).ldap())

def test_binary(self):
"""Test binary form of sid"""
self.assertEqual(self.sid_null_bin, sid.sid(self.sid_null).binary())
self.assertEqual(self.sid_sample_bin,
sid.sid(self.sid_sample).binary())
self.assertEqual(self.sid_sample_bin, sid.sid(self.sid_sample).binary())

def test_base64(self):
"""Test base64 form of sid"""
self.assertEqual(self.sid_null_b64, sid.sid(self.sid_null).base64())
self.assertEqual(self.sid_sample_b64,
sid.sid(self.sid_sample).base64())
self.assertEqual(self.sid_sample_b64, sid.sid(self.sid_sample).base64())


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

0 comments on commit 14a1507

Please sign in to comment.