Android 如何使用Python RSA加载adbkey.pub

Android 如何使用Python RSA加载adbkey.pub,android,python,rsa,Android,Python,Rsa,自Android v4.2.2以来,谷歌通过ADB实施RSA认证。我有一个带有USB OTG的Cortex-M0板,它通过ADB与Android进行通信。现在我必须在固件中部署RSA身份验证 我已经从androidadb、AVRCryptolib/ARMCryptolib收集了源代码。因为我是RSA认证的新手,所以我使用PythonRSA模块作为学习的起点 Python RSA Python RSA可以生成2048位RSA密钥对,并使用生成的密钥对正确加密/解密、签名/验证。以下是我的源代码:

自Android v4.2.2以来,谷歌通过ADB实施RSA认证。我有一个带有USB OTG的Cortex-M0板,它通过ADB与Android进行通信。现在我必须在固件中部署RSA身份验证

我已经从androidadb、AVRCryptolib/ARMCryptolib收集了源代码。因为我是RSA认证的新手,所以我使用PythonRSA模块作为学习的起点

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)
安卓RSA密钥

Android密钥对使用不同的fortmat。Adbkey文件中的私钥使用标准PEM格式,而Adbkey.pub中的公钥使用base64编码格式,不带页眉和页脚行

原始adbkey.public:

《代码>代码>QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQTI5EHBIZD7CPP3S/rVbzN8g2.文中给出了一个具体的概念,一个概念,一个概念,一个概念,一个概念,一个概念,一个概念,一个概念,一个概念,一个概念,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvR3MKEDOHFMCRWDIIZ0W6AD6HA/r3MKEDohfMCrWdIiZ0w6Ad6hata1OgEAAQA=unknown@unknown

此外,我发现Python RSA和Adb的2048位RSA公钥长度不同。我以PEM格式手动重新格式化adbkey.public,如下所示:

----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()
现在我有了pubkey的十六进制表示

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

更新02

在简要介绍了Android系统平台的源代码之后,我发现一条评论说RSA公钥与OpenSSL冲突,但在microcrypt解决方案中


但是,在我进入C/C++实现之前,我仍在用Python加载它。

您已经解码了所有公钥;你只需要提取正确的片段

ADB公钥的相关头文件位于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)
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)
整个结构(全部524字节)是base64编码的,然后是用户和主机名(
user@host
format)生成
adbkey.pub
文件

第一次更新时,您可以阅读
adbkey.pub
的内容。现在您有了
b
,可以提取公钥所需的两个组件,如下所示:

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)
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;
}
/**
*解析存储在.Android/adbkey.pub下的Android公钥,并返回Java公钥。
*@param inputKey是Android公钥。
*@返回公共RSA密钥。
*@抛出异常
*/
公共静态公钥parseandridpubkey(字符串inputKey){
BufferedReader BufferedReader=新的BufferedReader(新的StringReader(inputKey));
字符串行=null;
试一试{
line=bufferedReader.readLine();
}捕获(IOE异常){
抛出新的运行时异常(e);
}
line=line.replaceAll(“.@.*”,“”);
字节[]raw=Base64.getDecoder().decode(行);
ByteBuffer bb=ByteBuffer.wrap(未加工);
bb.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer IntBuffer=bb.asIntBuffer();
int len=intBuffer.get();
biginger n0Inv=biginger.valueOf(intBuffer.get());
ByteArrayOutputStream ByteArrayOutputStream=新的ByteArrayOutputStream(len*4);
int[]dst=新的int[len];
intBuffer.get(dst);
逆序排列(dst);
对于(int i=0;i
我可以在这里补充一点,标准RSA密钥到Android RSA密钥之间的转换是在