5

Android v4.2.2 以降、Google は ADB 経由で RSA 認証を実施しました。ADB経由でAndroidと通信するUSB​​ OTGを備えたCortex-M0ボードがあります。ここで、RSA 認証をファームウェアに展開する必要があります。

Android ADB、AVRCryptolib/ARMCryptolib からソース コードを収集しました。私は RSA 認証の初心者なので、学習の開始点として Python RSA モジュールを使用します。

パイソン 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 キー

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

さらに、Python RSA と Adb の 2048bit RSA 公開鍵の長さが異なることがわかりました。次のように、手動で 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()

Android RSA キー ペアは、キー生成中に異なるパラメーター (パディングなど) を使用する可能性があると思います。しかし、私はそれが何であり、それを確認する方法がわかりません。

どんなアイデアでも私を助けることができますか?


アップデート

これで、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 の 16 進数表示ができました。

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

更新 02

Android システム プラットフォームのソース コードを簡単に説明した後、RSA 公開鍵が OpenSSL と競合するというコメントを見つけましたが、マイクロクリプト ソリューションに含まれています。

ただし、C/C++ の実装に進む前に、Python でロードする作業を続けています。

4

2 に答える 2

3

すでにすべての公開鍵がデコードされています。適切な部分を抽出するだけです。

ADB 公開鍵に関連するヘッダー ファイルは、AOSP プロジェクトのmincrypt/rsa.hです。

次のように、5 つのフィールドを持つ構造体を定義します。

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形式) が続き、adbkey.pubファイルが生成されます。

最初の更新で、 の内容を読むことができますadbkey.pubbができたので、次のように、公開鍵に必要な 2 つのコンポーネントを抽出できます。

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)
于 2014-02-27T02:48:08.590 に答える
-1

以下は、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;
}
于 2016-02-17T00:22:01.623 に答える