diff --git a/utils/key2pub.py b/utils/key2pub.py index 9bb04cd..8d86ed9 100755 --- a/utils/key2pub.py +++ b/utils/key2pub.py @@ -1,129 +1,133 @@ -#!/usr/bin/env python - + #!/usr/bin/env python + +import io import sys try: - from M2Crypto import RSA -except ImportError, e: - sys.stderr.write('ERROR: Failed to import the "M2Crypto" module: %s\n' % e.message) - sys.stderr.write('Please install the "M2Crypto" Python module.\n') - sys.stderr.write('On Debian GNU/Linux the package is called "python-m2crypto".\n') - sys.exit(1) - + from Cryptodome.PublicKey import RSA +except ImportError as e: + sys.stderr.write('ERROR: Failed to import the "Cryptodome.PublicKey" module: %s\n' % e.message) + sys.stderr.write('Please install the "pycryptodomex" Python module.\n') + sys.stderr.write('Run 'pip install pycryptodomex' as ${USER} \n') + sys.exit(1) + + +def bitwise_collect(value, radix_bits): + words = [] + radix_mask = (1 << radix_bits) - 1 + while value != 0: + words.append(value & radix_mask) + value >>= radix_bits + return words + def print_ssl_64(output, name, val): - while val[0] == '\0': - val = val[1:] - while len(val) % 8: - val = '\0' + val - vnew = [] - while len(val): - vnew.append((val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7])) - val = val[8:] - vnew.reverse() - output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) + # OpenSSL expects 64-bit words given least-significant-word first. + vwords = bitwise_collect(val, 64) + + output.write(u'static BN_ULONG {}[] = {{\n'.format(name)) idx = 0 - for v1, v2, v3, v4, v5, v6, v7, v8 in vnew: - if not idx: - output.write('\t') - output.write('0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4), ord(v5), ord(v6), ord(v7), ord(v8))) - idx += 1 - if idx == 2: + for vword in vwords: + if not idx: + output.write(u'\t') + output.write(u'0x{:016x}ULL, '.format(vword)) + idx += 1 + if idx == 2: idx = 0 - output.write('\n') + output.write(u'\n') if idx: - output.write('\n') - output.write('};\n\n') - + output.write(u'\n') + output.write(u'};\n\n') + def print_ssl_32(output, name, val): - while val[0] == '\0': - val = val[1:] - while len(val) % 4: - val = '\0' + val - vnew = [] - while len(val): - vnew.append((val[0], val[1], val[2], val[3], )) - val = val[4:] - vnew.reverse() - output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) + # OpenSSL expects 32-bit words given least-significant-word first. + vwords = bitwise_collect(val, 32) + + output.write(u'static BN_ULONG {}[] = {{\n'.format(name)) idx = 0 - for v1, v2, v3, v4 in vnew: + for vword in vwords: if not idx: - output.write('\t') - output.write('0x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4))) + output.write(u'\t') + output.write(u'0x{:08x}, '.format(vword)) idx += 1 if idx == 4: idx = 0 - output.write('\n') + output.write(u'\n') if idx: - output.write('\n') - output.write('};\n\n') - + output.write(u'\n') + output.write(u'};\n\n') + def print_ssl(output, name, val): + + output.write(u'#include \n') + output.write(u'#include \n') + import struct - output.write('#include \n') if len(struct.pack('@L', 0)) == 8: return print_ssl_64(output, name, val) else: return print_ssl_32(output, name, val) - + def print_ssl_keys(output, n): - output.write(r''' -struct pubkey { - struct bignum_st e, n; -}; - -#define KEY(data) { \ - .d = data, \ - .top = sizeof(data)/sizeof(data[0]), \ -} - -#define KEYS(e,n) { KEY(e), KEY(n), } - -static struct pubkey keys[] = { -''') + output.write(u''' + struct pubkey { + struct bignum_st e, n; + }; + +#define KEY(data) { \\ + .d = data, \\ + .top = sizeof(data)/sizeof(data[0]), \\ + } + +#define KEYS(e,n) { KEY(e), KEY(n), } + + static struct pubkey keys[] = { + ''') for n in xrange(n + 1): - output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) - output.write('};\n') + output.write(u' KEYS(e_{0}, n_{0}),\n'.format(n)) + output.write(u'};\n') pass - + def print_gcrypt(output, name, val): - output.write('#include \n') - while val[0] == '\0': - val = val[1:] - output.write('static const uint8_t %s[%d] = {\n' % (name, len(val))) + # gcrypt expects 8-bit words most-significant-word first + vwords = bitwise_collect(val, 8) + vwords.reverse() + + output.write(u'#include \n') + output.write(u'static const uint8_t %s[%d] = {\n' % (name, len(vwords))) idx = 0 - for v in val: - if not idx: - output.write('\t') - output.write('0x%.2x, ' % ord(v)) - idx += 1 - if idx == 8: + for vword in vwords: + if not idx: + output.write(u'\t') + output.write(u'0x{:02x}, '.format(vword)) + idx += 1 + if idx == 8: idx = 0 - output.write('\n') + output.write(u'\n') if idx: - output.write('\n') - output.write('};\n\n') - + output.write(u'\n') + output.write(u'};\n\n') + def print_gcrypt_keys(output, n): - output.write(r''' -struct key_params { - const uint8_t *e, *n; - uint32_t len_e, len_n; -}; - -#define KEYS(_e, _n) { \ - .e = _e, .len_e = sizeof(_e), \ - .n = _n, .len_n = sizeof(_n), \ -} - -static const struct key_params __attribute__ ((unused)) keys[] = { -''') - for n in xrange(n + 1): - output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) - output.write('};\n') - - + output.write(u''' + struct key_params { + const uint8_t *e, *n; + uint32_t len_e, len_n; + }; + +#define KEYS(_e, _n) { \\ + .e = _e, .len_e = sizeof(_e), \\ + .n = _n, .len_n = sizeof(_n), \\ + } + + static const struct key_params __attribute__ ((unused)) keys[] = { + ''') + + for n in range(n + 1): + output.write(u' KEYS(e_{0}, n_{0}),\n'.format(n)) + output.write(u'};\n') + + modes = { - '--ssl': (print_ssl, print_ssl_keys), + '--ssl': (print_ssl, print_ssl_keys), '--gcrypt': (print_gcrypt, print_gcrypt_keys), } @@ -135,21 +139,20 @@ def print_gcrypt_keys(output, n): mode = None if not mode in modes: - print 'Usage: %s [%s] input-file... output-file' % (sys.argv[0], '|'.join(modes.keys())) + print('Usage: {} [{}] input-file... output-file'.format(sys.argv[0], '|'.join(modes.keys()))) sys.exit(2) - -output = open(outfile, 'w') - -# load key + +output = io.open(outfile, 'w') + + # load key idx = 0 for f in files: - try: - key = RSA.load_pub_key(f) - except RSA.RSAError: - key = RSA.load_key(f) + key_contents = io.open(f, 'rb').read() + key = RSA.importKey(key_contents) - modes[mode][0](output, 'e_%d' % idx, key.e[4:]) - modes[mode][0](output, 'n_%d' % idx, key.n[4:]) - idx += 1 + modes[mode][0](output, 'e_{}'.format(idx), key.e) + modes[mode][0](output, 'n_{}'.format(idx), key.n) + idx += 1 + modes[mode][1](output, idx - 1)