Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit 1d4b6ca

Browse files
committed
Merge pull request #11 from maruel/sign
Split off M2CryptoSigner into its own file.
2 parents 1c9ac27 + 72d9dbe commit 1d4b6ca

File tree

5 files changed

+108
-17
lines changed

5 files changed

+108
-17
lines changed

CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ Fahrzin Hemmati <[email protected]>
22
Alex Lusco <[email protected]>
33
44
Jamey Hicks <[email protected]>
5+
Marc-Antoine Ruel <[email protected]>
56
Max Borghino <[email protected]>

adb/adb_commands.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
import os
2727
import socket
2828

29-
from M2Crypto import RSA
30-
3129
import adb_protocol
3230
import common
3331
import filesync_protocol
@@ -40,20 +38,12 @@
4038
DeviceIsAvailable = common.InterfaceMatcher(CLASS, SUBCLASS, PROTOCOL)
4139

4240

43-
class M2CryptoSigner(adb_protocol.AuthSigner):
44-
"""AuthSigner using M2Crypto."""
45-
46-
def __init__(self, rsa_key_path):
47-
with open(rsa_key_path + '.pub') as rsa_pub_file:
48-
self.public_key = rsa_pub_file.read()
49-
50-
self.rsa_key = RSA.load_key(rsa_key_path)
51-
52-
def Sign(self, data):
53-
return self.rsa_key.sign(data, 'sha1')
54-
55-
def GetPublicKey(self):
56-
return self.public_key
41+
try:
42+
# Imported locally to keep compatibility with previous code.
43+
from sign_m2crypto import M2CryptoSigner
44+
except ImportError:
45+
# Ignore this error when M2Crypto is not installed, there are other options.
46+
pass
5747

5848

5949
class AdbCommands(object):

adb/adb_debug.py

100644100755
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env python
12
# Copyright 2014 Google Inc. All rights reserved.
23
#
34
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +24,7 @@
2324

2425
import adb_commands
2526
import common_cli
27+
import sign_m2crypto
2628

2729
gflags.ADOPT_module_key_flags(common_cli)
2830

@@ -37,7 +39,7 @@
3739
def GetRSAKwargs():
3840
if FLAGS.rsa_key_path:
3941
return {
40-
'rsa_keys': [adb_commands.M2CryptoSigner(os.path.expanduser(path))
42+
'rsa_keys': [sign_m2crypto.M2CryptoSigner(os.path.expanduser(path))
4143
for path in FLAGS.rsa_key_path],
4244
'auth_timeout_ms': int(FLAGS.auth_timeout_s * 1000.0),
4345
}

adb/sign_m2crypto.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2014 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from M2Crypto import RSA
16+
17+
from adb import adb_protocol
18+
19+
20+
class M2CryptoSigner(adb_protocol.AuthSigner):
21+
"""AuthSigner using M2Crypto."""
22+
23+
def __init__(self, rsa_key_path):
24+
with open(rsa_key_path + '.pub') as rsa_pub_file:
25+
self.public_key = rsa_pub_file.read()
26+
27+
self.rsa_key = RSA.load_key(rsa_key_path)
28+
29+
def Sign(self, data):
30+
return self.rsa_key.sign(data, 'sha1')
31+
32+
def GetPublicKey(self):
33+
return self.public_key
34+

adb/sign_pythonrsa.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright 2014 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import rsa
16+
17+
from pyasn1.codec.der import decoder
18+
from pyasn1.type import univ
19+
from rsa import pkcs1
20+
21+
22+
# python-rsa lib hashes all messages it signs. ADB does it already, we just
23+
# need to slap a signature on top of already hashed message. Introduce "fake"
24+
# hashing algo for this.
25+
class _Accum(object):
26+
def __init__(self):
27+
self._buf = ''
28+
def update(self, msg):
29+
self._buf += msg
30+
def digest(self):
31+
return self._buf
32+
pkcs1.HASH_METHODS['SHA-1-PREHASHED'] = _Accum
33+
pkcs1.HASH_ASN1['SHA-1-PREHASHED'] = pkcs1.HASH_ASN1['SHA-1']
34+
35+
36+
def _load_rsa_private_key(pem):
37+
"""PEM encoded PKCS#8 private key -> rsa.PrivateKey."""
38+
# ADB uses private RSA keys in pkcs#8 format. 'rsa' library doesn't support
39+
# them natively. Do some ASN unwrapping to extract naked RSA key
40+
# (in der-encoded form). See https://www.ietf.org/rfc/rfc2313.txt.
41+
# Also http://superuser.com/a/606266.
42+
try:
43+
der = rsa.pem.load_pem(pem, 'PRIVATE KEY')
44+
keyinfo, _ = decoder.decode(der)
45+
if keyinfo[1][0] != univ.ObjectIdentifier(
46+
'1.2.840.113549.1.1.1'): # pragma: no cover
47+
raise ValueError('Not a DER-encoded OpenSSL private RSA key')
48+
private_key_der = keyinfo[2].asOctets()
49+
except IndexError: # pragma: no cover
50+
raise ValueError('Not a DER-encoded OpenSSL private RSA key')
51+
return rsa.PrivateKey.load_pkcs1(private_key_der, format='DER')
52+
53+
54+
class PythonRSASigner(object):
55+
"""Implements adb_protocol.AuthSigner using http://stuvel.eu/rsa."""
56+
def __init__(self, pub, priv):
57+
self.priv_key = _load_rsa_private_key(priv)
58+
self.pub_key = pub
59+
60+
def Sign(self, data):
61+
return rsa.sign(data, self.priv_key, 'SHA-1-PREHASHED')
62+
63+
def GetPublicKey(self):
64+
return self.pub_key

0 commit comments

Comments
 (0)