Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load adbkey.pub with Python RSA

Since Android v4.2.2, Google enforced RSA authentication over ADB. I have a Cortex-M0 board with USB OTG, which communicates with Android over ADB. Now I have to deploy RSA authentication in firmware.

I have collected sources code from Android ADB, AVRCryptolib/ARMCryptolib. Since I am a newbie of RSA authentication, I use Python RSA module as my leanring start.

Python RSA

Python RSA can generate 2048bit RSA key pair, and encrypt/decrypt, sign/verify correctly with generated key pair. Here is my source code:

-*- 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

The Android key pair uses different fortmat. The private key in Adbkey file uses standard PEM format, while the public key in adbkey.pub uses base64 encoded format without header and footer lines.

original 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

Furthermore, I found 2048bit RSA publice key from Python RSA and Adb have difference length. I manually reformat the adbkey.public in PEM format like following:

----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-----

Then it throws an error:

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()

I guess Android RSA key pair may use different parameters (like padding) during key generation. However I have no idea what it is and how to check it.

Any ideas can help me out?


UPDATE

Now I found a way to load and decode the adbkey.pub. Check the following code

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

Now I have a hexdecimal presentation of pubkey.

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

UPDATE 02

After briefing through source code of Android system platform, I found a comment that RSA public key conflicts with OpenSSL, but in microcrypt solution.

However I still working on to load it in Python before I goes to C/C++ implementation.

like image 466
Allan K Liu Avatar asked Nov 01 '22 13:11

Allan K Liu


1 Answers

You already have all of the public key decoded; you just need to extract the right pieces.

The relevant header file for the ADB public key is mincrypt/rsa.h, in the AOSP project.

It defines a structure with five fields, like this:

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)

The entire structure, all 524 bytes, is base64-encoded, and then followed with your user and hostname (user@host format) to produce the adbkey.pub file.

With your first update, you can read the contents of adbkey.pub. Now that you have b, you can extract the two components that you need for the public key, like this:

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)

Then make a public key from those parts:

pubkey = rsa.PublicKey(n, e)
like image 96
Ian Clelland Avatar answered Nov 15 '22 03:11

Ian Clelland