1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Migrate all Python scripts to Python 3.

Most of them are now _mandatory_ P3 scripts, because I'm tired of
maintaining everything to be compatible with both versions.

The current exceptions are gdb.py (which has to live with whatever gdb
gives it), and kh2reg.py (which is actually designed for other people
to use, and some of them might still be stuck on P2 for the moment).
This commit is contained in:
Simon Tatham 2020-03-04 21:23:49 +00:00
parent cdffb995df
commit 2ec2b796ed
15 changed files with 116 additions and 93 deletions

View File

@ -4,14 +4,21 @@
# The idea of this is that you can use it to manually construct key # The idea of this is that you can use it to manually construct key
# exchange sequences of interesting kinds, for testing purposes. # exchange sequences of interesting kinds, for testing purposes.
import struct, random import sys
import struct
import random
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
def tobytes(s):
return s if isinstance(s, bytes) else s.encode('ASCII')
def boolean(b): def boolean(b):
return "\1" if b else "\0" return b"\1" if b else b"\0"
def byte(b): def byte(b):
assert 0 <= b < 0x100 assert 0 <= b < 0x100
return chr(b) return bytes([b])
def uint32(u): def uint32(u):
assert 0 <= u < 0x100000000 assert 0 <= u < 0x100000000
@ -22,25 +29,24 @@ def uint64(u):
return struct.pack(">L", u) return struct.pack(">L", u)
def string(s): def string(s):
return uint32(len(s)) + s return uint32(len(s)) + tobytes(s)
def mpint(m): def mpint(m):
s = "" s = []
lastbyte = 0
while m > 0: while m > 0:
lastbyte = m & 0xFF s.append(m & 0xFF)
s = chr(lastbyte) + s
m >>= 8 m >>= 8
if lastbyte & 0x80: if len(s) > 0 and (s[-1] & 0x80):
s = "\0" + s s.append(0)
return string(s) s.reverse()
return string(bytes(s))
def name_list(ns): def name_list(ns):
s = "" s = b""
for n in ns: for n in map(tobytes, ns):
assert "," not in n assert b"," not in n
if s != "": if s != b"":
s += "," s += b","
s += n s += n
return string(s) return string(s)
@ -52,7 +58,7 @@ def ssh_rsa_signature_blob(signature):
def greeting(string): def greeting(string):
# Greeting at the start of an SSH connection. # Greeting at the start of an SSH connection.
return string + "\r\n" return tobytes(string) + b"\r\n"
# Packet types. # Packet types.
SSH2_MSG_DISCONNECT = 1 SSH2_MSG_DISCONNECT = 1
@ -122,8 +128,5 @@ def decode_uint32(s):
def read_clearpkt(fh): def read_clearpkt(fh):
length_field = fh.read(4) length_field = fh.read(4)
s = fh.read(decode_uint32(length_field)) s = fh.read(decode_uint32(length_field))
import sys padlen, msgtype = s[:2]
padlen = ord(s[0]) return msgtype, s[2:-padlen]
s = s[1:-padlen]
msgtype = ord(s[0])
return msgtype, s[1:]

View File

@ -1,4 +1,4 @@
#! /usr/bin/env python #!/usr/bin/env python3
# Convert OpenSSH known_hosts and known_hosts2 files to "new format" PuTTY # Convert OpenSSH known_hosts and known_hosts2 files to "new format" PuTTY
# host keys. # host keys.

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python3
import sys import sys
import string import string
from collections import namedtuple from collections import namedtuple
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
class Multiprecision(object): class Multiprecision(object):
def __init__(self, target, minval, maxval, words): def __init__(self, target, minval, maxval, words):
self.target = target self.target = target
@ -89,21 +91,21 @@ class Multiprecision(object):
for i in range(nwords): for i in range(nwords):
srcpos = i * self.target.bits + start srcpos = i * self.target.bits + start
maxbits = min(self.target.bits, start + bits - srcpos) maxbits = min(self.target.bits, start + bits - srcpos)
wordindex = srcpos / self.target.bits wordindex = srcpos // self.target.bits
if srcpos % self.target.bits == 0: if srcpos % self.target.bits == 0:
word = self.getword(srcpos / self.target.bits) word = self.getword(srcpos // self.target.bits)
elif (wordindex+1 >= len(self.words) or elif (wordindex+1 >= len(self.words) or
srcpos % self.target.bits + maxbits < self.target.bits): srcpos % self.target.bits + maxbits < self.target.bits):
word = self.target.new_value( word = self.target.new_value(
"(%%s) >> %d" % (srcpos % self.target.bits), "(%%s) >> %d" % (srcpos % self.target.bits),
self.getword(srcpos / self.target.bits)) self.getword(srcpos // self.target.bits))
else: else:
word = self.target.new_value( word = self.target.new_value(
"((%%s) >> %d) | ((%%s) << %d)" % ( "((%%s) >> %d) | ((%%s) << %d)" % (
srcpos % self.target.bits, srcpos % self.target.bits,
self.target.bits - (srcpos % self.target.bits)), self.target.bits - (srcpos % self.target.bits)),
self.getword(srcpos / self.target.bits), self.getword(srcpos // self.target.bits),
self.getword(srcpos / self.target.bits + 1)) self.getword(srcpos // self.target.bits + 1))
if maxbits < self.target.bits and maxbits < bits: if maxbits < self.target.bits and maxbits < bits:
word = self.target.new_value( word = self.target.new_value(
"(%%s) & ((((BignumInt)1) << %d)-1)" % maxbits, "(%%s) & ((((BignumInt)1) << %d)-1)" % maxbits,
@ -127,11 +129,11 @@ class CodegenTarget(object):
self.valindex = 0 self.valindex = 0
self.stmts = [] self.stmts = []
self.generators = {} self.generators = {}
self.bv_words = (130 + self.bits - 1) / self.bits self.bv_words = (130 + self.bits - 1) // self.bits
self.carry_index = 0 self.carry_index = 0
def nwords(self, maxval): def nwords(self, maxval):
return (maxval.bit_length() + self.bits - 1) / self.bits return (maxval.bit_length() + self.bits - 1) // self.bits
def stmt(self, stmt, needed=False): def stmt(self, stmt, needed=False):
index = len(self.stmts) index = len(self.stmts)
@ -149,7 +151,7 @@ class CodegenTarget(object):
return name return name
def bigval_input(self, name, bits): def bigval_input(self, name, bits):
words = (bits + self.bits - 1) / self.bits words = (bits + self.bits - 1) // self.bits
# Expect not to require an entire extra word # Expect not to require an entire extra word
assert words == self.bv_words assert words == self.bv_words

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Example Python script to synthesise the server end of an SSH key exchange. # Example Python script to synthesise the server end of an SSH key exchange.
@ -27,6 +27,8 @@
import sys, random import sys, random
from encodelib import * from encodelib import *
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
# A random Diffie-Hellman group, taken from an SSH server I made a # A random Diffie-Hellman group, taken from an SSH server I made a
# test connection to. # test connection to.
groupgen = 5 groupgen = 5
@ -37,7 +39,7 @@ rsaexp = 0x10001
rsamod = 0xB98FE0C0BEE1E05B35FDDF5517B3E29D8A9A6A7834378B6783A19536968968F755E341B5822CAE15B465DECB80EE4116CF8D22DB5A6C85444A68D0D45D9D42008329619BE3CAC3B192EF83DD2B75C4BB6B567E11B841073BACE92108DA7E97E543ED7F032F454F7AC3C6D3F27DB34BC9974A85C7963C546662AE300A61CBABEE274481FD041C41D0145704F5FA9C77A5A442CD7A64827BB0F21FB56FDE388B596A20D7A7D1C5F22DA96C6C2171D90A673DABC66596CD99499D75AD82FEFDBE04DEC2CC7E1414A95388F668591B3F4D58249F80489646ED2C318E77D4F4E37EE8A588E79F2960620E6D28BF53653F1C974C91845F0BABFE5D167E1CA7044EE20D rsamod = 0xB98FE0C0BEE1E05B35FDDF5517B3E29D8A9A6A7834378B6783A19536968968F755E341B5822CAE15B465DECB80EE4116CF8D22DB5A6C85444A68D0D45D9D42008329619BE3CAC3B192EF83DD2B75C4BB6B567E11B841073BACE92108DA7E97E543ED7F032F454F7AC3C6D3F27DB34BC9974A85C7963C546662AE300A61CBABEE274481FD041C41D0145704F5FA9C77A5A442CD7A64827BB0F21FB56FDE388B596A20D7A7D1C5F22DA96C6C2171D90A673DABC66596CD99499D75AD82FEFDBE04DEC2CC7E1414A95388F668591B3F4D58249F80489646ED2C318E77D4F4E37EE8A588E79F2960620E6D28BF53653F1C974C91845F0BABFE5D167E1CA7044EE20D
# 16 bytes of random data for the start of KEXINIT. # 16 bytes of random data for the start of KEXINIT.
cookie = "".join([chr(random.randint(0,255)) for i in range(16)]) cookie = bytes(random.randint(0,255) for i in range(16))
def expect(var, expr): def expect(var, expr):
expected_val = eval(expr) expected_val = eval(expr)
@ -46,12 +48,12 @@ def expect(var, expr):
expr, repr(expected_val), repr(var))) expr, repr(expected_val), repr(var)))
sys.exit(1) sys.exit(1)
sys.stdout.write(greeting("SSH-2.0-Example KEX synthesis")) sys.stdout.buffer.write(greeting("SSH-2.0-Example KEX synthesis"))
greeting = sys.stdin.readline() greeting = sys.stdin.buffer.readline()
expect(greeting[:8], '"SSH-2.0-"') expect(greeting[:8].decode("ASCII"), '"SSH-2.0-"')
sys.stdout.write( sys.stdout.buffer.write(
clearpkt(SSH2_MSG_KEXINIT, clearpkt(SSH2_MSG_KEXINIT,
cookie, cookie,
name_list(("diffie-hellman-group-exchange-sha256",)), # kex name_list(("diffie-hellman-group-exchange-sha256",)), # kex
@ -66,27 +68,27 @@ sys.stdout.write(
name_list(()), # server->client languages name_list(()), # server->client languages
boolean(False), # first kex packet does not follow boolean(False), # first kex packet does not follow
uint32(0))) uint32(0)))
sys.stdout.flush() sys.stdout.buffer.flush()
intype, inpkt = read_clearpkt(sys.stdin) intype, inpkt = read_clearpkt(sys.stdin.buffer)
expect(intype, "SSH2_MSG_KEXINIT") expect(intype, "SSH2_MSG_KEXINIT")
intype, inpkt = read_clearpkt(sys.stdin) intype, inpkt = read_clearpkt(sys.stdin.buffer)
expect(intype, "SSH2_MSG_KEX_DH_GEX_REQUEST") expect(intype, "SSH2_MSG_KEX_DH_GEX_REQUEST")
expect(inpkt, "uint32(0x400) + uint32(0x400) + uint32(0x2000)") expect(inpkt, "uint32(0x400) + uint32(0x400) + uint32(0x2000)")
sys.stdout.write( sys.stdout.buffer.write(
clearpkt(SSH2_MSG_KEX_DH_GEX_GROUP, clearpkt(SSH2_MSG_KEX_DH_GEX_GROUP,
mpint(group), mpint(group),
mpint(groupgen))) mpint(groupgen)))
sys.stdout.flush() sys.stdout.buffer.flush()
intype, inpkt = read_clearpkt(sys.stdin) intype, inpkt = read_clearpkt(sys.stdin.buffer)
expect(intype, "SSH2_MSG_KEX_DH_GEX_INIT") expect(intype, "SSH2_MSG_KEX_DH_GEX_INIT")
sys.stdout.write( sys.stdout.buffer.write(
clearpkt(SSH2_MSG_KEX_DH_GEX_REPLY, clearpkt(SSH2_MSG_KEX_DH_GEX_REPLY,
ssh_rsa_key_blob(rsaexp, rsamod), ssh_rsa_key_blob(rsaexp, rsamod),
mpint(random.randint(2, group-2)), mpint(random.randint(2, group-2)),
ssh_rsa_signature_blob(random.randint(2, rsamod-2)))) ssh_rsa_signature_blob(random.randint(2, rsamod-2))))
sys.stdout.flush() sys.stdout.buffer.flush()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Generate Mac OS X .icns files, or at least the simple subformats # Generate Mac OS X .icns files, or at least the simple subformats
# that don't involve JPEG encoding and the like. # that don't involve JPEG encoding and the like.
@ -10,6 +10,8 @@ import sys
import struct import struct
import subprocess import subprocess
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
# The file format has a typical IFF-style (type, length, data) chunk # The file format has a typical IFF-style (type, length, data) chunk
# structure, with one outer chunk containing subchunks for various # structure, with one outer chunk containing subchunks for various
# different icon sizes and formats. # different icon sizes and formats.
@ -33,18 +35,18 @@ def make_mono_icon(size, rgba):
for index in range(len(rgba))] for index in range(len(rgba))]
# Encode in 1-bit big-endian format. # Encode in 1-bit big-endian format.
data = "" data = b''
for i in range(0, len(pixels), 8): for i in range(0, len(pixels), 8):
byte = 0 byte = 0
for j in range(8): for j in range(8):
if pixels[i+j] >= 0x80: if pixels[i+j] >= 0x80:
byte |= 0x80 >> j byte |= 0x80 >> j
data += chr(byte) data += bytes(byte)
# This size-32 chunk id is an anomaly in what would otherwise be a # This size-32 chunk id is an anomaly in what would otherwise be a
# consistent system of using {s,l,h,t} for {16,32,48,128}-pixel # consistent system of using {s,l,h,t} for {16,32,48,128}-pixel
# icon sizes. # icon sizes.
chunkid = { 16: "ics#", 32: "ICN#", 48: "ich#" }[size] chunkid = { 16: b"ics#", 32: b"ICN#", 48: b"ich#" }[size]
return make_chunk(chunkid, data) return make_chunk(chunkid, data)
# Mask for full-colour icons: a chunk containing an 8 bpp alpha # Mask for full-colour icons: a chunk containing an 8 bpp alpha
@ -52,9 +54,9 @@ def make_mono_icon(size, rgba):
def make_colour_mask(size, rgba): def make_colour_mask(size, rgba):
assert len(rgba) == size * size assert len(rgba) == size * size
data = "".join(map(lambda pix: chr(pix[3]), rgba)) data = bytes(map(lambda pix: pix[3], rgba))
chunkid = { 16: "s8mk", 32: "l8mk", 48: "h8mk", 128: "t8mk" }[size] chunkid = { 16: b"s8mk", 32: b"l8mk", 48: b"h8mk", 128: b"t8mk" }[size]
return make_chunk(chunkid, data) return make_chunk(chunkid, data)
# Helper routine for deciding when to start and stop run-length # Helper routine for deciding when to start and stop run-length
@ -69,19 +71,18 @@ def runof3(string, position):
def make_colour_icon(size, rgba): def make_colour_icon(size, rgba):
assert len(rgba) == size * size assert len(rgba) == size * size
data = "" data = b""
# Mysterious extra zero header word appearing only in the size-128 # Mysterious extra zero header word appearing only in the size-128
# icon chunk. libicns doesn't know what it's for, and neither do # icon chunk. libicns doesn't know what it's for, and neither do
# I. # I.
if size == 128: if size == 128:
data += "\0\0\0\0" data += b"\0\0\0\0"
# Handle R,G,B channels in sequence. (Ignore the alpha channel; it # Handle R,G,B channels in sequence. (Ignore the alpha channel; it
# goes into the separate mask chunk constructed above.) # goes into the separate mask chunk constructed above.)
for chan in range(3): for chan in range(3):
pixels = "".join([chr(rgba[index][chan]) pixels = bytes([rgba[index][chan] for index in range(len(rgba))])
for index in range(len(rgba))])
# Run-length encode each channel using the following format: # Run-length encode each channel using the following format:
# * byte 0x80-0xFF followed by one literal byte means repeat # * byte 0x80-0xFF followed by one literal byte means repeat
@ -98,15 +99,15 @@ def make_colour_icon(size, rgba):
pos < len(pixels) and pos < len(pixels) and
pixels[pos] == pixval): pixels[pos] == pixval):
pos += 1 pos += 1
data += chr(0x80 + pos-start - 3) + pixval data += bytes(0x80 + pos-start - 3) + pixval
else: else:
while (pos - start < 128 and while (pos - start < 128 and
pos < len(pixels) and pos < len(pixels) and
not runof3(pixels, pos)): not runof3(pixels, pos)):
pos += 1 pos += 1
data += chr(0x00 + pos-start - 1) + pixels[start:pos] data += bytes(0x00 + pos-start - 1) + pixels[start:pos]
chunkid = { 16: "is32", 32: "il32", 48: "ih32", 128: "it32" }[size] chunkid = { 16: b"is32", 32: b"il32", 48: b"ih32", 128: b"it32" }[size]
return make_chunk(chunkid, data) return make_chunk(chunkid, data)
# Load an image file from disk and turn it into a simple list of # Load an image file from disk and turn it into a simple list of
@ -117,10 +118,10 @@ def make_colour_icon(size, rgba):
# here that the file is in RGBA .pam format (as mkicon.py will have # here that the file is in RGBA .pam format (as mkicon.py will have
# generated it). # generated it).
def load_rgba(filename): def load_rgba(filename):
with open(filename) as f: with open(filename, "rb") as f:
assert f.readline() == "P7\n" assert f.readline() == b"P7\n"
for line in iter(f.readline, ''): for line in iter(f.readline, ''):
words = line.rstrip("\n").split() words = line.decode("ASCII").rstrip("\n").split()
if words[0] == "WIDTH": if words[0] == "WIDTH":
width = int(words[1]) width = int(words[1])
elif words[0] == "HEIGHT": elif words[0] == "HEIGHT":
@ -135,10 +136,10 @@ def load_rgba(filename):
assert width == height assert width == height
data = f.read() data = f.read()
assert len(data) == width*height*4 assert len(data) == width*height*4
rgba = [map(ord, data[i:i+4]) for i in range(0, len(data), 4)] rgba = [list(data[i:i+4]) for i in range(0, len(data), 4)]
return width, rgba return width, rgba
data = "" data = b""
# Trivial argument format: each argument is a filename prefixed with # Trivial argument format: each argument is a filename prefixed with
# "mono:", "colour:" or "output:". The first two indicate image files # "mono:", "colour:" or "output:". The first two indicate image files
@ -157,7 +158,7 @@ for arg in sys.argv[1:]:
else: else:
assert False, "bad argument '%s'" % arg assert False, "bad argument '%s'" % arg
data = make_chunk("icns", data) data = make_chunk(b"icns", data)
with open(outfile, "w") as f: with open(outfile, "wb") as f:
f.write(data) f.write(data)

View File

@ -2,9 +2,12 @@
from __future__ import division from __future__ import division
import sys
import decimal import decimal
import math import math
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
# Python code which draws the PuTTY icon components at a range of # Python code which draws the PuTTY icon components at a range of
# sizes. # sizes.

View File

@ -10,6 +10,8 @@ import collections
from ssh import * from ssh import *
import agenttestdata import agenttestdata
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
test_session_id = b'Test16ByteSessId' test_session_id = b'Test16ByteSessId'
assert len(test_session_id) == 16 assert len(test_session_id) == 16
test_message_to_sign = b'test message to sign' test_message_to_sign = b'test message to sign'

View File

@ -1,5 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
def generate(): def generate():
import hashlib import hashlib

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
import unittest import unittest
import struct import struct
import itertools import itertools
@ -17,6 +18,8 @@ from eccref import *
from testcrypt import * from testcrypt import *
from ssh import * from ssh import *
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
try: try:
base64decode = base64.decodebytes base64decode = base64.decodebytes
except AttributeError: except AttributeError:
@ -90,7 +93,7 @@ def last(iterable):
def queued_random_data(nbytes, seed): def queued_random_data(nbytes, seed):
hashsize = 512 // 8 hashsize = 512 // 8
data = b''.join( data = b''.join(
hashlib.sha512(unicode_to_bytes("preimage:{:d}:{}".format(i, seed))) hashlib.sha512("preimage:{:d}:{}".format(i, seed).encode('ascii'))
.digest() for i in range((nbytes + hashsize - 1) // hashsize)) .digest() for i in range((nbytes + hashsize - 1) // hashsize))
data = data[:nbytes] data = data[:nbytes]
random_queue(data) random_queue(data)
@ -199,9 +202,9 @@ class mpint(MyTestBase):
n = mp_from_hex(hexstr) n = mp_from_hex(hexstr)
i = int(hexstr, 16) i = int(hexstr, 16)
self.assertEqual(mp_get_hex(n), self.assertEqual(mp_get_hex(n),
unicode_to_bytes("{:x}".format(i))) "{:x}".format(i).encode('ascii'))
self.assertEqual(mp_get_hex_uppercase(n), self.assertEqual(mp_get_hex_uppercase(n),
unicode_to_bytes("{:X}".format(i))) "{:X}".format(i).encode('ascii'))
checkHex("0") checkHex("0")
checkHex("f") checkHex("f")
checkHex("00000000000000000000000000000000000000000000000000") checkHex("00000000000000000000000000000000000000000000000000")
@ -212,7 +215,7 @@ class mpint(MyTestBase):
n = mp_from_hex(hexstr) n = mp_from_hex(hexstr)
i = int(hexstr, 16) i = int(hexstr, 16)
self.assertEqual(mp_get_decimal(n), self.assertEqual(mp_get_decimal(n),
unicode_to_bytes("{:d}".format(i))) "{:d}".format(i).encode('ascii'))
checkDec("0") checkDec("0")
checkDec("f") checkDec("f")
checkDec("00000000000000000000000000000000000000000000000000") checkDec("00000000000000000000000000000000000000000000000000")
@ -1857,10 +1860,10 @@ culpa qui officia deserunt mollit anim id est laborum.
# both parts. Other than that, we don't do much to # both parts. Other than that, we don't do much to
# make this a rigorous cryptographic test. # make this a rigorous cryptographic test.
for n, d in [(1,3),(2,3)]: for n, d in [(1,3),(2,3)]:
sigbytes = list(bytevals(sigblob)) sigbytes = list(sigblob)
bit = 8 * len(sigbytes) * n // d bit = 8 * len(sigbytes) * n // d
sigbytes[bit // 8] ^= 1 << (bit % 8) sigbytes[bit // 8] ^= 1 << (bit % 8)
badsig = valbytes(sigbytes) badsig = bytes(sigbytes)
for key in [pubkey, privkey, privkey2]: for key in [pubkey, privkey, privkey2]:
self.assertFalse(ssh_key_verify( self.assertFalse(ssh_key_verify(
key, badsig, test_message)) key, badsig, test_message))

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Reference implementation of DES. # Reference implementation of DES.
# #
@ -15,6 +15,8 @@ import struct
import functools import functools
import argparse import argparse
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
def bitor(x, y): def bitor(x, y):
return x | y return x | y
def split_words(val, width=32): def split_words(val, width=32):

View File

@ -1,6 +1,9 @@
import sys
import numbers import numbers
import itertools import itertools
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
from numbertheory import * from numbertheory import *
class AffinePoint(object): class AffinePoint(object):

View File

@ -1,7 +1,10 @@
import sys
import numbers import numbers
import itertools import itertools
import unittest import unittest
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
def invert(a, b): def invert(a, b):
"Multiplicative inverse of a mod b. a,b must be coprime." "Multiplicative inverse of a mod b. a,b must be coprime."
A = (a, 1, 0) A = (a, 1, 0)

View File

@ -1,6 +1,9 @@
import sys
import struct import struct
import itertools import itertools
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
def nbits(n): def nbits(n):
# Mimic mp_get_nbits for ordinary Python integers. # Mimic mp_get_nbits for ordinary Python integers.
assert 0 <= n assert 0 <= n

View File

@ -6,21 +6,14 @@ import re
import struct import struct
from binascii import hexlify from binascii import hexlify
assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
# Expect to be run from the 'test' subdirectory, one level down from # Expect to be run from the 'test' subdirectory, one level down from
# the main source # the main source
putty_srcdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) putty_srcdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def unicode_to_bytes(arg): def coerce_to_bytes(arg):
# Slightly fiddly way to do this which should work in Python 2 and 3 return arg.encode("UTF-8") if isinstance(arg, str) else arg
if isinstance(arg, type(u'a')) and not isinstance(arg, type(b'a')):
arg = arg.encode("UTF-8")
return arg
def bytevals(b):
return struct.unpack("{:d}B".format(len(b)), b)
def valbytes(b):
b = list(b)
return struct.pack("{:d}B".format(len(b)), *b)
class ChildProcessFailure(Exception): class ChildProcessFailure(Exception):
pass pass
@ -75,8 +68,8 @@ class ChildProcess(object):
if self.sp is None: if self.sp is None:
assert self.exitstatus is None assert self.exitstatus is None
self.start() self.start()
self.write_line(unicode_to_bytes(cmd) + b" " + b" ".join( self.write_line(coerce_to_bytes(cmd) + b" " + b" ".join(
unicode_to_bytes(arg) for arg in args)) coerce_to_bytes(arg) for arg in args))
argcount = int(self.read_line()) argcount = int(self.read_line())
return [self.read_line() for arg in range(argcount)] return [self.read_line() for arg in range(argcount)]
def wait_for_exit(self): def wait_for_exit(self):
@ -154,11 +147,10 @@ def make_argword(arg, argtype, fnname, argindex, to_preserve):
return "NULL" return "NULL"
typename = typename[4:] typename = typename[4:]
if typename == "val_string": if typename == "val_string":
arg = unicode_to_bytes(arg) arg = coerce_to_bytes(arg)
if isinstance(arg, bytes): if isinstance(arg, bytes):
retwords = childprocess.funcall( retwords = childprocess.funcall(
"newstring", ["".join("%{:02x}".format(b) "newstring", ["".join("%{:02x}".format(b) for b in arg)])
for b in bytevals(arg))])
arg = make_retvals([typename], retwords, unpack_strings=False)[0] arg = make_retvals([typename], retwords, unpack_strings=False)[0]
to_preserve.append(arg) to_preserve.append(arg)
if typename == "val_mpint" and isinstance(arg, numbers.Integral): if typename == "val_mpint" and isinstance(arg, numbers.Integral):
@ -179,7 +171,7 @@ def make_argword(arg, argtype, fnname, argindex, to_preserve):
if typename in { if typename in {
"hashalg", "macalg", "keyalg", "cipheralg", "hashalg", "macalg", "keyalg", "cipheralg",
"dh_group", "ecdh_alg", "rsaorder", "primegenpolicy"}: "dh_group", "ecdh_alg", "rsaorder", "primegenpolicy"}:
arg = unicode_to_bytes(arg) arg = coerce_to_bytes(arg)
if isinstance(arg, bytes) and b" " not in arg: if isinstance(arg, bytes) and b" " not in arg:
return arg return arg
if typename == "mpint_list": if typename == "mpint_list":
@ -188,7 +180,7 @@ def make_argword(arg, argtype, fnname, argindex, to_preserve):
for val in arg: for val in arg:
sublist.append(make_argword(val, ("val_mpint", False), sublist.append(make_argword(val, ("val_mpint", False),
fnname, argindex, to_preserve)) fnname, argindex, to_preserve))
return b" ".join(unicode_to_bytes(sub) for sub in sublist) return b" ".join(coerce_to_bytes(sub) for sub in sublist)
raise TypeError( raise TypeError(
"Can't convert {}() argument {:d} to {} (value was {!r})".format( "Can't convert {}() argument {:d} to {} (value was {!r})".format(
fnname, argindex, typename, arg)) fnname, argindex, typename, arg))
@ -197,7 +189,7 @@ def unpack_string(identifier):
retwords = childprocess.funcall("getstring", [identifier]) retwords = childprocess.funcall("getstring", [identifier])
childprocess.funcall("free", [identifier]) childprocess.funcall("free", [identifier])
return re.sub(b"%[0-9A-F][0-9A-F]", return re.sub(b"%[0-9A-F][0-9A-F]",
lambda m: valbytes([int(m.group(0)[1:], 16)]), lambda m: bytes([int(m.group(0)[1:], 16)]),
retwords[0]) retwords[0])
def unpack_mp(identifier): def unpack_mp(identifier):

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import argparse import argparse
import os import os