Как загрузить adbkey.pub с помощью Python RSA

Начиная с Android v4.2.2, Google применяет аутентификацию RSA через ADB. У меня есть плата Cortex-M0 с USB OTG, которая общается с Android над ADB. Теперь мне нужно развернуть аутентификацию RSA в прошивке.

Я собрал исходный код из Android ADB, AVRCryptolib / ARMCryptolib. Поскольку я новичок в RSA-аутентификации, я использую Python RSA-модуль в качестве моего начинающего стиля.

Python RSA

Python RSA может генерировать 2048-битную пару ключей RSA и шифровать / расшифровывать, правильно подписывать / проверять с помощью сгенерированной пары ключей. Вот мой исходный код:

-*- coding: utf-8 -*- # with_statement is used in Python 2.6+, from __future__ import with_statement import rsa from datetime import datetime # load pub/private keys with open('adbkey.pub.pem') as publickfile: p = publickfile.read() pubkey = rsa.PublicKey.load_pkcs1(p) with open('adbkey.pem') as privatefile: p = privatefile.read() privkey = rsa.PrivateKey.load_pkcs1(p) message = 'http://ennovation.sinaapp.com/' begin = datetime.now() # Encrypt message with pubkey, decrypt it with private key crypto = rsa.encrypt(message, pubkey) stop1 = datetime.now() message = rsa.decrypt(crypto, privkey) stop2 = datetime.now() print message print "EncryptTime = %s, DecryptTime = %s"%(stop1-begin,stop2-stop1) begin = datetime.now() # Sign message with private key, verify it with public key signature = rsa.sign(message, privkey, 'SHA-1') stop1 = datetime.now() #result = rsa.verify('hello', signature, pubkey) result = rsa.verify(message, signature, pubkey) stop2 = datetime.now() print result print "SignTime = %s, VerifyTime = %s"%(stop1-begin,stop2-stop1) 

Android RSA Key

Пара Android-ключей использует разные форматирования. Закрытый ключ в файле Adbkey использует стандартный формат PEM, а открытый ключ в adbkey.pub использует формат base64 без заголовков и нижних колонтитулов.

Оригинал adbkey.public:

QAAAAOlEXtSnLMF3igx8NMi7u8+LeD7BoVC+v2bvBJnvVsaJ31QtwEzbicob8mlLxEhbGSKdaoXIwwAsWR+7FzlSUW57G9vuqpJDGJ7iEG4+5uYs7KarhiRF3K+hUX6PDIF7gEo/0TgglxvNXmTkfV9zZb3VxmgV66z68VeBXK46kM7MffKiHyu7P3Jdtdptm2p7jU7XwvfgWH6a0rrrGzUWONEfteh6ruHIxP1Z3CdxYVZ0YF9uHWsweQzgf7N2RG0g4cxNJDLs0CXqaao7xS16tzaCYfn7cZQPIKCb057oo+jMWvgsh+8gY8qgQtI5EHBizd7cPp3S/rVbzN8gUCo4aSuIn9TfT6uJ0S3D3TPWbHXs9Y8nskhIOM1Hkgv3CAODfzwH+ZM3nWmFD77FMtiWo/hJrMRcH63yvX5pVPYnqQyHcdembEM1Fbxg/qWAVtLxNFJqoFKYXYHl9ktGcM+3Izwvea5fAebmbWIuezKYF6F49Y3dIPA+fWxunGkbehih7o0S9RoWIQIYByteF+b/EN2ntSpwfuhD8G9n6Bfaz4mEVTG82Lj8YeK6+CYyEirSCl4Al7SGsb66E74Fnt+v+NouQFpZxCrrefm7sYug11NHSNiDeYa8cnatQsla+Cfd91GmgKsu+ZDO8uF8UR7/r3MKEDohfMCrWdIiZ0w6Ad6hata1OgEAAQA= unknown@unknown

Кроме того, я нашел 2048-битный RSA-файл из Python RSA, а Adb имеет разную длину. Я вручную переформатирую adbkey.public в формате PEM, например:

 ----BEGIN RSA PUBLIC KEY----- QAAAAOlEXtSnLMF3igx8NMi7u8+LeD7BoVC+v2bvBJnvVsaJ31QtwEzbicob8mlL xEhbGSKdaoXIwwAsWR+7FzlSUW57G9vuqpJDGJ7iEG4+5uYs7KarhiRF3K+hUX6P DIF7gEo/0TgglxvNXmTkfV9zZb3VxmgV66z68VeBXK46kM7MffKiHyu7P3Jdtdpt m2p7jU7XwvfgWH6a0rrrGzUWONEfteh6ruHIxP1Z3CdxYVZ0YF9uHWsweQzgf7N2 RG0g4cxNJDLs0CXqaao7xS16tzaCYfn7cZQPIKCb057oo+jMWvgsh+8gY8qgQtI5 EHBizd7cPp3S/rVbzN8gUCo4aSuIn9TfT6uJ0S3D3TPWbHXs9Y8nskhIOM1Hkgv3 CAODfzwH+ZM3nWmFD77FMtiWo/hJrMRcH63yvX5pVPYnqQyHcdembEM1Fbxg/qWA VtLxNFJqoFKYXYHl9ktGcM+3Izwvea5fAebmbWIuezKYF6F49Y3dIPA+fWxunGkb ehih7o0S9RoWIQIYByteF+b/EN2ntSpwfuhD8G9n6Bfaz4mEVTG82Lj8YeK6+CYy EirSCl4Al7SGsb66E74Fnt+v+NouQFpZxCrrefm7sYug11NHSNiDeYa8cnatQsla +Cfd91GmgKsu+ZDO8uF8UR7/r3MKEDohfMCrWdIiZ0w6Ad6hata1OgEAAQA= -----END RSA PUBLIC KEY----- 

Затем он выдает ошибку:

 Traceback (most recent call last): File "D:\Freescale FRDM KL25Z\RSA\rsa_speed_adb.py", line 10, in <module> pubkey = rsa.PublicKey.load_pkcs1(p) File "build\bdist.win32\egg\rsa\key.py", line 65, in load_pkcs1 File "build\bdist.win32\egg\rsa\key.py", line 192, in _load_pkcs1_pem File "build\bdist.win32\egg\rsa\key.py", line 160, in _load_pkcs1_der File "C:\Python25\lib\site-packages\pyasn1-0.1.7-py2.5.egg\pyasn1\codec\ber\decoder.py", line 798, in __call__ pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=64, tagFormat=0, tagId=0)) not in asn1Spec: AsnPubKey() 

Я думаю, что пара ключей RSA RS может использовать разные параметры (например, заполнение) во время генерации ключей. Однако я понятия не имею, что это такое и как его проверить.

Любые идеи могут помочь мне?


ОБНОВИТЬ

Теперь я нашел способ загрузить и декодировать файл adbkey.pub. Проверьте следующий код

 import base64 import binascii f = open('adbkey.pub','r') # load file from adbkey.pub line = f.readline() # actually oneline is enough line = line.replace(" unknown@unknown","") # remove text information print line print len(line) b = base64.b64decode(line) # decode base64 into binary s = binascii.hexlify(b) # get hexdecimal of the binary print s 

Теперь у меня есть шестнадцатеричное представление pubkey.

 40000000e9445ed4a72cc1778a0c7c34c8bbbbcf8b783ec1a150bebf66ef0499ef56c689df542dc0 4cdb89ca1bf2694bc4485b19229d6a85c8c3002c591fbb173952516e7b1bdbeeaa9243189ee2106e 3ee6e62ceca6ab862445dcafa1517e8f0c817b804a3fd13820971bcd5e64e47d5f7365bdd5c66815 ebacfaf157815cae3a90cecc7df2a21f2bbb3f725db5da6d9b6a7b8d4ed7c2f7e0587e9ad2baeb1b 351638d11fb5e87aaee1c8c4fd59dc2771615674605f6e1d6b30790ce07fb376446d20e1cc4d2432 ecd025ea69aa3bc52d7ab7368261f9fb71940f20a09bd39ee8a3e8cc5af82c87ef2063caa042d239 107062cddedc3e9dd2feb55bccdf20502a38692b889fd4df4fab89d12dc3dd33d66c75ecf58f27b2 484838cd47920bf70803837f3c07f993379d69850fbec532d896a3f849acc45c1fadf2bd7e6954f6 27a90c8771d7a66c433515bc60fea58056d2f134526aa052985d81e5f64b4670cfb7233c2f79ae5f 01e6e66d622e7b329817a178f58ddd20f03e7d6c6e9c691b7a18a1ee8d12f51a16210218072b5e17 e6ff10dda7b52a707ee843f06f67e817dacf89845531bcd8b8fc61e2baf82632122ad20a5e0097b4 86b1beba13be059edfaff8da2e405a59c42aeb79f9bbb18ba0d7534748d8837986bc7276ad42c95a f827ddf751a680ab2ef990cef2e17c511effaf730a103a217cc0ab59d222674c3a01dea16ad6b53a 01000100 

ОБНОВЛЕНИЕ 02

После брифинга через исходный код системной платформы Android я нашел комментарий о том, что открытый ключ RSA конфликтует с OpenSSL, но в решении для микрококтов.

Однако я все еще работаю над его загрузкой на Python, прежде чем перейти к реализации C / C ++.

У вас уже есть весь открытый ключ; Вам просто нужно извлечь нужные фрагменты.

Соответствующим заголовочным файлом для открытого ключа ADB является mincrypt / rsa.h в проекте AOSP.

Он определяет структуру с пятью полями, например:

 Field Size ================================ len 4 bytes (1 word) n0inv 4 btyes (1 word) n 256 bytes (64 words) rr 256 bytes (64 words) exponent 4 bytes (1 word) 

Вся структура, все 524 байта, кодируется base64 и затем сопровождается вашим именем пользователя и хоста ( user@host format) для создания файла adbkey.pub .

При первом обновлении вы можете прочитать содержимое adbkey.pub . Теперь, когда у вас есть b , вы можете извлечь два компонента, которые вам нужны для открытого ключа, например:

 n_bytes = bytearray(reversed(b[8:256+8])) # reversed because LSB is first n_str = binascii.hexlify(n_bytes) # convert to hex string n = int(n_str, 16) # make an integer e_bytes = bytearray(reversed(b[-4:])) # last four bytes are the exponent e_str = binascii.hexlify(n_bytes) e = int(e_str, 16) 

Затем сделайте открытый ключ из этих частей:

 pubkey = rsa.PublicKey(n, e) 

Вот полный проверенный фрагмент кода в Java. Я знаю, что это не Python, но может быть просто преобразовать его:

 /** * Parses an Android public RSA key like stored under .android/adbkey.pub and returns a Java public RSA key. * @param inputKey The Android public key. * @return the public RSA key. * @throws Exception */ public static PublicKey parseAndroidPubKey(String inputKey) { BufferedReader bufferedReader = new BufferedReader(new StringReader(inputKey)); String line = null; try { line = bufferedReader.readLine(); } catch (IOException e) { throw new RuntimeException(e); } line = line.replaceAll(" .*@.*", ""); byte[] raw = Base64.getDecoder().decode(line); ByteBuffer bb = ByteBuffer.wrap(raw); bb.order(ByteOrder.LITTLE_ENDIAN); IntBuffer intBuffer = bb.asIntBuffer(); int len = intBuffer.get(); BigInteger n0Inv = BigInteger.valueOf(intBuffer.get()); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(len*4); int[] dst = new int[len]; intBuffer.get(dst); ArrayUtils.reverse(dst); for (int i = 0; i < len; i++) { int value = dst[i]; byte[] convertedBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array(); byteArrayOutputStream.write(convertedBytes, 0, convertedBytes.length); } byte[] n = byteArrayOutputStream.toByteArray(); byteArrayOutputStream.reset(); dst = new int[len]; intBuffer.get(dst); ArrayUtils.reverse(dst); for (int i = 0; i < len; i++) { int value = dst[i]; byte[] convertedBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array(); byteArrayOutputStream.write(convertedBytes, 0, convertedBytes.length); } int e = intBuffer.get(); RSAPublicKey publicKey; try { publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger(1, n), BigInteger.valueOf(e))); } catch (Exception ex) { throw new RuntimeException(ex); } return publicKey; }