Merge pull request #1076 from androguard/oscrypto

removed oscrypto
This commit is contained in:
erev0s 2024-09-20 22:02:24 +03:00 committed by GitHub
commit a458772eac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 113 additions and 10 deletions

View File

@ -11,7 +11,6 @@ from loguru import logger
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters.terminal import TerminalFormatter
from oscrypto import asymmetric
# internal modules
from androguard.core.axml import ARSCParser
@ -22,6 +21,7 @@ from androguard.core.axml import AXMLPrinter
from androguard.core.dex import get_bytecodes_method
from androguard.util import readFile
from androguard.ui import DynamicUI
from androguard.util import parse_public, calculate_fingerprint
def androaxml_main(
inp:str,
@ -375,12 +375,12 @@ def androsign_main(args_apk:list[str], args_hash:str, args_all:bool, show:bool)
for public_key in pkeys:
if show:
x509_public_key = asymmetric.load_public_key(public_key)
print("PublicKey Algorithm:", x509_public_key.algorithm)
print("Bit Size:", x509_public_key.bit_size)
print("Fingerprint:", binascii.hexlify(x509_public_key.fingerprint))
parsed_key = parse_public(public_key)
print(f"Algorithm: {parsed_key.algorithm}")
print(f"Bit size: {parsed_key.bit_size}")
print(f"Fingerprint: {calculate_fingerprint(parsed_key).hex()}")
try:
print("Hash Algorithm:", x509_public_key.asn1.hash_algo)
print(f"Hash Algorithm: {parsed_key.hash_algo}")
except ValueError as ve:
# RSA pkey does not have a hash algorithm
pass

View File

@ -1,7 +1,9 @@
import sys
from typing import Union, BinaryIO
from asn1crypto import keys, x509
import hashlib
import binascii
#  External dependencies
# import asn1crypto
@ -93,3 +95,95 @@ def get_certificate_name_string(name:Union[dict,Name], short:bool=False, delimit
'organization_identifier': ("organizationIdentifier", "organizationIdentifier"),
}
return delimiter.join(["{}={}".format(_.get(attr, (attr, attr))[0 if short else 1], name[attr]) for attr in name])
def parse_public(data):
from asn1crypto import pem, keys, x509
"""
Loads a public key from a DER or PEM-formatted input.
Supports RSA, DSA, EC public keys, and X.509 certificates.
:param data: A byte string of the public key or certificate
:raises ValueError: If the input data is not a known format
:return: A keys.PublicKeyInfo object containing the parsed public key
"""
# Check if the data is in PEM format (starts with "-----")
if pem.detect(data):
type_name, _, der_bytes = pem.unarmor(data)
if type_name in ['PRIVATE KEY', 'RSA PRIVATE KEY']:
raise ValueError("The data specified appears to be a private key, not a public key.")
else:
# If not PEM, assume it's DER-encoded
der_bytes = data
# Try to parse the data as PublicKeyInfo (standard public key structure)
try:
public_key_info = keys.PublicKeyInfo.load(der_bytes)
public_key_info.native # Fully parse the object (asn1crypto is lazy)
return public_key_info
except ValueError:
pass # Not a PublicKeyInfo structure
# Try to parse the data as an X.509 certificate
try:
certificate = x509.Certificate.load(der_bytes)
public_key_info = certificate['tbs_certificate']['subject_public_key_info']
public_key_info.native # Fully parse the object
return public_key_info
except ValueError:
pass # Not a certificate
# Try to parse the data as RSAPublicKey
try:
rsa_public_key = keys.RSAPublicKey.load(der_bytes)
rsa_public_key.native # Fully parse the object
# Wrap the RSAPublicKey in PublicKeyInfo
return keys.PublicKeyInfo.wrap(rsa_public_key, 'rsa')
except ValueError:
pass # Not an RSAPublicKey structure
raise ValueError("The data specified does not appear to be a known public key or certificate format.")
def calculate_fingerprint(key_object):
"""
Calculates a SHA-256 fingerprint of the public key based on its components.
:param key_object: A keys.PublicKeyInfo object containing the parsed public key
:return: The fingerprint of the public key as a byte string
"""
to_hash = None
# RSA Public Key
if key_object.algorithm == 'rsa':
key = key_object['public_key'].parsed
# Prepare string with modulus and public exponent
to_hash = '%d:%d' % (key['modulus'].native, key['public_exponent'].native)
# DSA Public Key
elif key_object.algorithm == 'dsa':
key = key_object['public_key'].parsed
params = key_object['algorithm']['parameters']
# Prepare string with p, q, g, and public key
to_hash = '%d:%d:%d:%d' % (
params['p'].native,
params['q'].native,
params['g'].native,
key.native,
)
# EC Public Key
elif key_object.algorithm == 'ec':
public_key = key_object['public_key'].native
# Prepare byte string with curve name and public key
to_hash = '%s:' % key_object.curve[1]
to_hash = to_hash.encode('utf-8') + public_key
# Ensure to_hash is encoded as bytes if it's a string
if isinstance(to_hash, str):
to_hash = to_hash.encode('utf-8')
# Return the SHA-256 hash of the formatted key data
return hashlib.sha256(to_hash).digest()

View File

@ -28,7 +28,6 @@ apkInspector = ">=1.1.7"
matplotlib = "*"
networkx = "*"
pyyaml = "*"
oscrypto = ">=1.3.0"
[tool.setuptools.package_data]
"androguard.core.api_specific_resources" = ["aosp_permissions/*.json", "api_permission_mappings/*.json"]

View File

@ -13,4 +13,3 @@ apkInspector>=1.2.1
matplotlib
networkx
pyyaml
oscrypto>=1.3.0

View File

@ -714,5 +714,16 @@ class APKTest(unittest.TestCase):
self.assertEqual(a.get_app_name(locale='ru-rRU'), "values-ru-rRU")
def testPublicKeysofApk(self):
a = APK(os.path.join(test_dir, 'data/APK/com.example.android.wearable.wear.weardrawers.apk'))
pkeys = set(a.get_public_keys_der_v3() + a.get_public_keys_der_v2())
for public_key in pkeys:
from androguard.util import parse_public
from androguard.util import calculate_fingerprint
parsed_key = parse_public(public_key)
self.assertEqual(parsed_key.algorithm, 'rsa')
self.assertEqual(parsed_key.bit_size, 2048)
self.assertEqual(calculate_fingerprint(parsed_key).hex(), '98917cd03c6277d73d58b661d614c442f2981a35a5aa122a61049215ba85c1d4')
if __name__ == '__main__':
unittest.main(failfast=True)