Difference between revisions of "Sage Sandbox"
Jump to navigation
Jump to search
(3 intermediate revisions by 2 users not shown) | |||
Line 9: | Line 9: | ||
while i: |
while i: |
||
l[0:0]=chr(i&0xff) |
l[0:0]=chr(i&0xff) |
||
− | + | i>>=8 |
|
return ''.join(l) |
return ''.join(l) |
||
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
Line 20: | Line 20: | ||
while i: |
while i: |
||
l.append(chr(i&0xff)) |
l.append(chr(i&0xff)) |
||
− | + | i>>=8 |
|
return ''.join(l[::-1]) |
return ''.join(l[::-1]) |
||
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
Line 36: | Line 36: | ||
import math |
import math |
||
def long2string(i): |
def long2string(i): |
||
− | return |
+ | return ('%0*x' % (int(math.ceil(math.log(i,2)/8)*2) , i)).decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#4.77 µs per loop |
#4.77 µs per loop |
||
Line 43: | Line 43: | ||
################################################################################### |
################################################################################### |
||
def long2string(i): |
def long2string(i): |
||
− | return |
+ | return ('%0*x' % (len(hex(i)) & -2 , i)).decode('hex').lstrip('\x00') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#3.64 µs per loop |
#3.64 µs per loop |
||
Line 49: | Line 49: | ||
#3.78 µs per loop |
#3.78 µs per loop |
||
################################################################################### |
################################################################################### |
||
− | + | ('%0*x' % (2 * 16 , 123456789012345678901234)).decode('hex') |
|
#2.06 µs per loop |
#2.06 µs per loop |
||
− | + | ('%0*x' % (2 * 16 , 1234567890123456789012345)).decode('hex') |
|
#2.01 µs per loop |
#2.01 µs per loop |
||
− | #Ok if you want fixed length buffer, e.g. |
+ | #Ok if you want fixed length buffer, e.g. 16 bytes |
################################################################################### |
################################################################################### |
||
def long2string(i): |
def long2string(i): |
||
Line 59: | Line 59: | ||
if len(s) % 2: |
if len(s) % 2: |
||
s='0'+s |
s='0'+s |
||
− | return |
+ | return s.decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#2.88 µs per loop |
#2.88 µs per loop |
||
Line 67: | Line 67: | ||
def long2string(i): |
def long2string(i): |
||
s='0'+hex(long(i))[2:-1] |
s='0'+hex(long(i))[2:-1] |
||
− | return |
+ | return s[len(s) % 2:].decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#3.04 µs per loop |
#3.04 µs per loop |
||
Line 77: | Line 77: | ||
if len(s) % 2: |
if len(s) % 2: |
||
s='0'+s |
s='0'+s |
||
− | return |
+ | return s.decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#2.75 µs per loop |
#2.75 µs per loop |
||
Line 86: | Line 86: | ||
def long2string(i): |
def long2string(i): |
||
s='0'+hex(i)[2:-1] |
s='0'+hex(i)[2:-1] |
||
− | return |
+ | return s[len(s) % 2:].decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#2.66 µs per loop |
#2.66 µs per loop |
||
Line 96: | Line 96: | ||
if len(s) % 2: |
if len(s) % 2: |
||
s='0'+s |
s='0'+s |
||
− | return |
+ | return s.decode('hex') |
long2string(123456789012345678901234) |
long2string(123456789012345678901234) |
||
#2.42 µs per loop |
#2.42 µs per loop |
||
Line 103: | Line 103: | ||
################################################################################### |
################################################################################### |
||
# There is still room ;-) |
# There is still room ;-) |
||
+ | '1a249b1f10a06c96aff2'.decode('hex') |
||
− | binascii.unhexlify('1a249b1f10a06c96aff2') |
||
#990 ns per loop |
#990 ns per loop |
||
################################################################################### |
################################################################################### |
||
Line 116: | Line 116: | ||
################################################################################### |
################################################################################### |
||
int('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16) |
int('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16) |
||
− | #3.15 µs per loop |
||
− | ################################################################################### |
||
− | int(binascii.hexlify('\x01\x05n\x0f6\xa6D=\xe2\xdfy'),16) |
||
#1.64 µs per loop |
#1.64 µs per loop |
||
################################################################################### |
################################################################################### |
||
− | long |
+ | long('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16) |
#1.38 µs per loop |
#1.38 µs per loop |
||
</source> |
</source> |
||
Line 149: | Line 146: | ||
{{#fileanchor: padding.py}} |
{{#fileanchor: padding.py}} |
||
<source lang=python> |
<source lang=python> |
||
− | from binascii import hexlify |
||
import random |
import random |
||
import sys |
import sys |
||
− | import |
+ | from optparse import OptionParser |
try: |
try: |
||
Line 184: | Line 180: | ||
After changing the source: |
After changing the source: |
||
− | del |
+ | del padder |
− | del |
+ | del Padding |
from padding import * |
from padding import * |
||
""" |
""" |
||
def pad (self, toPad, algo): |
def pad (self, toPad, algo): |
||
− | + | #private function has to be accessed by it's public name when using getattr... |
|
+ | return getattr(self,"_%(classname)s__%(algo)s" % {'classname':self.__class__.__name__,'algo':algo})(toPad) |
||
def unpad (self, padded, algo): |
def unpad (self, padded, algo): |
||
Line 213: | Line 210: | ||
def __bitPadding_unpad (self, padded ): |
def __bitPadding_unpad (self, padded ): |
||
if padded.rstrip('\x00')[-1] == '\x80': |
if padded.rstrip('\x00')[-1] == '\x80': |
||
− | return padded.rstrip( |
+ | return padded.rstrip('\x00')[:-1] |
else: |
else: |
||
return padded |
return padded |
||
Line 236: | Line 233: | ||
pattern = self.blockSize - len(toPad)%self.blockSize |
pattern = self.blockSize - len(toPad)%self.blockSize |
||
+ | patternstring = chr(pattern) |
||
− | # 0 -> zero padding for numeric values; 2 -> print "String to be padded: %r" % toPadlength modifier; x -> hex output |
||
− | # string formatting options: http://docs.python.org/lib/typesseq-strings.html |
||
− | code = "%02x" % pattern |
||
− | patternstring = ('\\x' + code).decode('string_escape') |
||
amount = self.blockSize - len(toPad)%self.blockSize |
amount = self.blockSize - len(toPad)%self.blockSize |
||
− | pad = |
+ | pad = patternstring * amount |
return toPad + pad |
return toPad + pad |
||
def __PKCS7_unpad (self, padded ): |
def __PKCS7_unpad (self, padded ): |
||
pattern = padded[-1] |
pattern = padded[-1] |
||
− | length = |
+ | length = ord(pattern) |
+ | #check if the bytes to be removed are all the same pattern |
||
− | flag = 0 |
||
− | + | if padded.endswith(pattern*length): |
|
− | + | return padded[:-length] |
|
− | flag = 1 |
||
− | if flag == 0: |
||
− | unpadded = padded[:-length] |
||
else: |
else: |
||
− | + | return padded |
|
print 'error: padding pattern not recognized' |
print 'error: padding pattern not recognized' |
||
− | return unpadded |
||
def __ANSI_X923 (self, toPad ): |
def __ANSI_X923 (self, toPad ): |
||
bytesToPad = self.blockSize - len(toPad)%self.blockSize |
bytesToPad = self.blockSize - len(toPad)%self.blockSize |
||
− | + | pattern = '\x00'*(bytesToPad -1) + chr(bytesToPad) |
|
− | pattern = '\x00'*(bytesToPad -1) + ('\\x' + trail).decode('string_escape') |
||
return toPad + pattern |
return toPad + pattern |
||
def __ANSI_X923_unpad (self, padded ): |
def __ANSI_X923_unpad (self, padded ): |
||
− | length = |
+ | length = ord(padded[-1]) |
#check if the bytes to be removed are all zero |
#check if the bytes to be removed are all zero |
||
if padded.count('\x00',-length,-1) == length - 1: |
if padded.count('\x00',-length,-1) == length - 1: |
||
return padded[:-length] |
return padded[:-length] |
||
else: |
else: |
||
− | unpadded = padded |
||
print 'error: padding pattern not recognized %s' % padded.count('\x00',-length,-1) |
print 'error: padding pattern not recognized %s' % padded.count('\x00',-length,-1) |
||
− | return unpadded |
+ | return unpadded |
def __ISO_10126 (self, toPad): |
def __ISO_10126 (self, toPad): |
||
bytesToPad = self.blockSize - len(toPad)%self.blockSize |
bytesToPad = self.blockSize - len(toPad)%self.blockSize |
||
− | pattern1 = ''.join(( |
+ | pattern1 = ''.join(chr(random.randrange(256)) for x in range(bytesToPad-1)) |
− | pattern2 = ( |
+ | pattern2 = chr(bytesToPad) |
return toPad + pattern1 + pattern2 |
return toPad + pattern1 + pattern2 |
||
def __ISO_10126_unpad (self, padded): |
def __ISO_10126_unpad (self, padded): |
||
− | return padded[ |
+ | return padded[:-ord(padded[-1])] |
def main(): |
def main(): |
||
+ | usage = "usage: %prog [options] [texttopad]" |
||
− | try: |
||
+ | parser = OptionParser(usage=usage) |
||
− | opts, args = getopt.getopt(sys.argv[1:], "") |
||
+ | parser.add_option("-b", "--blocksize", dest='blocksize', default=8, help="specify the bloksize", type='int') |
||
− | except getopt.GetoptError, err: |
||
+ | (options, args) = parser.parse_args() |
||
− | print str(err) |
||
+ | |||
− | sys.exit(2) |
||
if len(args) > 1: |
if len(args) > 1: |
||
− | + | parser.error("Program takes maximum 1 argument") |
|
+ | |||
try: |
try: |
||
− | testbench(args[0]) |
+ | testbench(args[0].decode('string_escape'),options.blocksize) |
except IndexError: |
except IndexError: |
||
− | testbench() |
+ | testbench(blocksize=options.blocksize) |
− | def testbench(toPad='test'): |
+ | def testbench(toPad='test',blocksize=8): |
testbench = ('bitPadding','zerosPadding','PKCS7','ANSI_X923','ISO_10126') |
testbench = ('bitPadding','zerosPadding','PKCS7','ANSI_X923','ISO_10126') |
||
− | padder = Padding() |
+ | padder = Padding(blocksize) |
print "String to be padded: %r, with length %i\n" % (toPad,len(toPad)) |
print "String to be padded: %r, with length %i\n" % (toPad,len(toPad)) |
||
for test in testbench: |
for test in testbench: |
Latest revision as of 12:18, 18 July 2011
Back to SAGE & cryptology
Helper functions
Conversion from int or long to raw string and back is discussed on the Python bug tracking list but since the problem is not yet solved, let's see how to make our own helper functions in a clean and fast way: (measures with %timeit of ipython)
############################### long2string ########################################
def long2string(i):
l=[]
while i:
l[0:0]=chr(i&0xff)
i>>=8
return ''.join(l)
long2string(123456789012345678901234)
#46 µs per loop
long2string(1234567890123456789012345)
#51.8 µs per loop
###################################################################################
def long2string(i):
l=[]
while i:
l.append(chr(i&0xff))
i>>=8
return ''.join(l[::-1])
long2string(123456789012345678901234)
#15.1 µs per loop
long2string(1234567890123456789012345)
#16.4 µs per loop
###################################################################################
def long2string(i):
return ''.join([chr(i>>j & 0xFF) for j in range(int(math.log(i,2)//8)<<3,-1,-8)])
long2string(123456789012345678901234)
#15.5 µs per loop
long2string(1234567890123456789012345)
#16.7 µs per loop
###################################################################################
import math
def long2string(i):
return ('%0*x' % (int(math.ceil(math.log(i,2)/8)*2) , i)).decode('hex')
long2string(123456789012345678901234)
#4.77 µs per loop
long2string(1234567890123456789012345)
#4.83 µs per loop
###################################################################################
def long2string(i):
return ('%0*x' % (len(hex(i)) & -2 , i)).decode('hex').lstrip('\x00')
long2string(123456789012345678901234)
#3.64 µs per loop
long2string(1234567890123456789012345)
#3.78 µs per loop
###################################################################################
('%0*x' % (2 * 16 , 123456789012345678901234)).decode('hex')
#2.06 µs per loop
('%0*x' % (2 * 16 , 1234567890123456789012345)).decode('hex')
#2.01 µs per loop
#Ok if you want fixed length buffer, e.g. 16 bytes
###################################################################################
def long2string(i):
s=hex(i)[2:].rstrip('L')
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.88 µs per loop
long2string(1234567890123456789012345)
#3.22 µs per loop
###################################################################################
def long2string(i):
s='0'+hex(long(i))[2:-1]
return s[len(s) % 2:].decode('hex')
long2string(123456789012345678901234)
#3.04 µs per loop
long2string(1234567890123456789012345)
#3.03 µs per loop
###################################################################################
def long2string(i):
s=hex(long(i))[2:-1]
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.75 µs per loop
long2string(1234567890123456789012345)
#3.06 µs per loop
###################################################################################
#If we are sure our argument is a long we can remove the cast in the 2 previous codes:
def long2string(i):
s='0'+hex(i)[2:-1]
return s[len(s) % 2:].decode('hex')
long2string(123456789012345678901234)
#2.66 µs per loop
long2string(1234567890123456789012345)
#2.62 µs per loop
###################################################################################
def long2string(i):
s=hex(i)[2:-1]
if len(s) % 2:
s='0'+s
return s.decode('hex')
long2string(123456789012345678901234)
#2.42 µs per loop
long2string(1234567890123456789012345)
#2.76 µs per loop
###################################################################################
# There is still room ;-)
'1a249b1f10a06c96aff2'.decode('hex')
#990 ns per loop
###################################################################################
############################### string2long ########################################
def string2long(s):
i=0
for c in s:
i=(i<<8)+ord(c)
return i
string2long('\x01\x05n\x0f6\xa6D=\xe2\xdfy')
#8.91 µs per loop
###################################################################################
int('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16)
#1.64 µs per loop
###################################################################################
long('\x01\x05n\x0f6\xa6D=\xe2\xdfy'.encode('hex'),16)
#1.38 µs per loop
Learning Python
Some code to make some padding functions available. The code is used as a way to learn python, so it contains things that don't make sense or could be done better.
{{#fileanchor: helper.py}}
from __future__ import division #http://www.python.org/dev/peps/pep-0238/
import math
def roundUp (n, p):
"""Round an integer up to the nearest multiple
A given integer n will be round up to the nearest multiple of p
Example:
>>> roundUp(13,8)
16
"""
return int(math.ceil(n/p)*p)
#return (n+p)/p*p
Download code: [{{#filelink: helper.py}} helper.py]
{{#fileanchor: padding.py}}
import random
import sys
from optparse import OptionParser
try:
import helper
except ImportError:
print 'ERROR: helper.py should be placed in the same location as padding.py'
raise ImportError
class BlockOperator:
"""Class for BlockOperator
Only holds a variable blocksize. Class only exist for testing purpose.
"""
def __init__(self, bs=8):
self.blockSize = bs
class Padding(BlockOperator):
"""Class for padding functions
Inherits from the BlockOperator class
padding info here: http://en.wikipedia.org/wiki/Padding_(cryptography)
Example:
from padding import *
padder = Padding()
padded = padder.pad('test','bitpadding)
padder.unpad(padded,'bitpadding)
After changing the source:
del padder
del Padding
from padding import *
"""
def pad (self, toPad, algo):
#private function has to be accessed by it's public name when using getattr...
return getattr(self,"_%(classname)s__%(algo)s" % {'classname':self.__class__.__name__,'algo':algo})(toPad)
def unpad (self, padded, algo):
#there is no switch statement in python
#discussion with alternatives: http://simonwillison.net/2004/May/7/switch/
if algo == 'bitPadding':
return self.__bitPadding_unpad(padded)
elif algo == 'zerosPadding':
return self.__zerosPadding_unpad(padded)
elif algo == 'PKCS7':
return self.__PKCS7_unpad(padded)
elif algo == 'ANSI_X923':
return self.__ANSI_X923_unpad(padded)
elif algo == 'ISO_10126':
return self.__ISO_10126_unpad(padded)
raise NotImplementedError()
def __bitPadding (self, toPad ):
padded = toPad + '\x80' + '\x00'*(self.blockSize - len(toPad)%self.blockSize -1)
return padded
def __bitPadding_unpad (self, padded ):
if padded.rstrip('\x00')[-1] == '\x80':
return padded.rstrip('\x00')[:-1]
else:
return padded
def __zerosPadding (self, toPad ):
totalLength = helper.roundUp(len(toPad),self.blockSize)
return toPad.ljust(totalLength,'\x00')
def __zerosPadding_unpad (self, padded ):
return padded.rstrip('\x00')
def __PKCS7 (self, toPad ):
"""Pad a binary string
Input:
toPad: binary string to be padded
self.blockSize: the padded result will be a multiple of the self.blockSize(default=8)
Output:
return a binary string
"""
pattern = self.blockSize - len(toPad)%self.blockSize
patternstring = chr(pattern)
amount = self.blockSize - len(toPad)%self.blockSize
pad = patternstring * amount
return toPad + pad
def __PKCS7_unpad (self, padded ):
pattern = padded[-1]
length = ord(pattern)
#check if the bytes to be removed are all the same pattern
if padded.endswith(pattern*length):
return padded[:-length]
else:
return padded
print 'error: padding pattern not recognized'
def __ANSI_X923 (self, toPad ):
bytesToPad = self.blockSize - len(toPad)%self.blockSize
pattern = '\x00'*(bytesToPad -1) + chr(bytesToPad)
return toPad + pattern
def __ANSI_X923_unpad (self, padded ):
length = ord(padded[-1])
#check if the bytes to be removed are all zero
if padded.count('\x00',-length,-1) == length - 1:
return padded[:-length]
else:
print 'error: padding pattern not recognized %s' % padded.count('\x00',-length,-1)
return unpadded
def __ISO_10126 (self, toPad):
bytesToPad = self.blockSize - len(toPad)%self.blockSize
pattern1 = ''.join(chr(random.randrange(256)) for x in range(bytesToPad-1))
pattern2 = chr(bytesToPad)
return toPad + pattern1 + pattern2
def __ISO_10126_unpad (self, padded):
return padded[:-ord(padded[-1])]
def main():
usage = "usage: %prog [options] [texttopad]"
parser = OptionParser(usage=usage)
parser.add_option("-b", "--blocksize", dest='blocksize', default=8, help="specify the bloksize", type='int')
(options, args) = parser.parse_args()
if len(args) > 1:
parser.error("Program takes maximum 1 argument")
try:
testbench(args[0].decode('string_escape'),options.blocksize)
except IndexError:
testbench(blocksize=options.blocksize)
def testbench(toPad='test',blocksize=8):
testbench = ('bitPadding','zerosPadding','PKCS7','ANSI_X923','ISO_10126')
padder = Padding(blocksize)
print "String to be padded: %r, with length %i\n" % (toPad,len(toPad))
for test in testbench:
padded = padder.pad(toPad,'%s'%test)
print "padded: %r" % padded
unpadded = padder.unpad(padded,'%s'%test)
print "unpadded: %r" % unpadded
if unpadded == toPad:
print "%s test OK!\n" % test
else:
print "%s test not OK!\n" % test
if __name__ == "__main__":
main()
Download code: [{{#filelink: padding.py}} padding.py]