summaryrefslogtreecommitdiff
path: root/paramiko/ber.py
diff options
context:
space:
mode:
authorRobey Pointer <robey@lag.net>2003-12-27 01:49:19 +0000
committerRobey Pointer <robey@lag.net>2003-12-27 01:49:19 +0000
commit877cd974b8182d26fa76d566072917ea67b64e67 (patch)
tree577da518d93f7b4d1d6b6fa48dbbbe95ab36ceca /paramiko/ber.py
parentf6e1e84d60ae75cd28030b4c41856ec768566a46 (diff)
downloadparamiko-877cd974b8182d26fa76d566072917ea67b64e67.tar.gz
[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-14]
move the paramiko files into a paramiko/ folder. just moving the files into a folder. it won't build this way yet.
Diffstat (limited to 'paramiko/ber.py')
-rw-r--r--paramiko/ber.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/paramiko/ber.py b/paramiko/ber.py
new file mode 100644
index 00000000..7fe1dd09
--- /dev/null
+++ b/paramiko/ber.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+
+import struct
+
+def inflate_long(s, always_positive=0):
+ "turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"
+ out = 0L
+ if len(s) % 4:
+ filler = '\x00'
+ if not always_positive and (ord(s[0]) >= 0x80):
+ # negative
+ filler = '\xff'
+ s = filler * (4 - len(s) % 4) + s
+ # FIXME: this doesn't actually handle negative.
+ # luckily ssh never uses negative bignums.
+ for i in range(0, len(s), 4):
+ out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
+ return out
+
+def deflate_long(n, add_sign_padding=1):
+ "turns a long-int into a normalized byte string (adapted from Crypto.Util.number)"
+ # after much testing, this algorithm was deemed to be the fastest
+ s = ''
+ n = long(n)
+ while n > 0:
+ s = struct.pack('>I', n & 0xffffffffL) + s
+ n = n >> 32
+ # strip off leading zeros
+ for i in enumerate(s):
+ if i[1] != '\000':
+ break
+ else:
+ # only happens when n == 0
+ s = '\000'
+ i = (0,)
+ s = s[i[0]:]
+ if (ord(s[0]) >= 0x80) and add_sign_padding:
+ s = '\x00' + s
+ return s
+
+
+class BER(object):
+
+ def __init__(self, content=''):
+ self.content = content
+ self.idx = 0
+
+ def __str__(self):
+ return self.content
+
+ def __repr__(self):
+ return 'BER(' + repr(self.content) + ')'
+
+ def decode(self):
+ return self.decode_next()
+
+ def decode_next(self):
+ if self.idx >= len(self.content):
+ return None
+ id = ord(self.content[self.idx])
+ self.idx += 1
+ if (id & 31) == 31:
+ # identifier > 30
+ id = 0
+ while self.idx < len(self.content):
+ t = ord(self.content[self.idx])
+ if not (t & 0x80):
+ break
+ id = (id << 7) | (t & 0x7f)
+ self.idx += 1
+ if self.idx >= len(self.content):
+ return None
+ # now fetch length
+ size = ord(self.content[self.idx])
+ self.idx += 1
+ if size & 0x80:
+ # more complimicated...
+ # FIXME: theoretically should handle indefinite-length (0x80)
+ t = size & 0x7f
+ if self.idx + t > len(self.content):
+ return None
+ size = 0
+ while t > 0:
+ size = (size << 8) | ord(self.content[self.idx])
+ self.idx += 1
+ t -= 1
+ if self.idx + size > len(self.content):
+ # can't fit
+ return None
+ data = self.content[self.idx : self.idx + size]
+ self.idx += size
+ # now switch on id
+ if id == 0x30:
+ # sequence
+ return self.decode_sequence(data)
+ elif id == 2:
+ # int
+ return inflate_long(data)
+ else:
+ # 1: boolean (00 false, otherwise true)
+ raise Exception('Unknown ber encoding type %d (robey is lazy)' % id)
+
+ def decode_sequence(data):
+ out = []
+ b = BER(data)
+ while 1:
+ x = b.decode_next()
+ if x == None:
+ return out
+ out.append(x)
+ decode_sequence = staticmethod(decode_sequence)
+