hashlib: killed during calculation of signature hash

27 Views Asked by At

I am trying to run the Android check_ota_package_signature.py https://android.googlesource.com/platform/build/+/refs/heads/main/tools/releasetools/check_ota_package_signature.py

on a low-end computer. The program is used to check the signature of an Android OTA update. Unfortunately the program is getting killed. IMHO the relevant part is:

with open(package, 'rb') as package_file:
 package_bytes = package_file.read()
length = len(package_bytes)
footer = bytearray(package_bytes[-6:])
signature_start_from_end = (footer[1] << 8) + footer[0]
signature_start = length - signature_start_from_end
comment_len = (footer[5] << 8) + footer[4]
signed_len = length - comment_len - 2

comment_len = (footer[5] << 8) + footer[4]
signed_len = length - comment_len - 2

print('Package length: %d' % (length,))
print('Comment length: %d' % (comment_len,))
print('Signed data length: %d' % (signed_len,))
print('Signature start: %d' % (signature_start,))

use_sha256 = CertUsesSha256(cert)
print('Use SHA-256: %s' % (use_sha256,))

h = sha256() if use_sha256 else sha1()
h.update(package_bytes[:signed_len])

package_digest = h.hexdigest().lower()

h.update(package_bytes[:signed_len]) is getting killed. My understanding is that this happens due to a out of memory because the file of approx. 1.1GB is read ad once. How can I change the program to read the file in small chunks so that I do not run into this problem?

I expected to verify the signature. Instead I got the following message:

Package length: 1182903653
Comment length: 1983
Signed data length: 1182901668
Signature start: 1182901688
Use SHA-256: True
Killed
1

There are 1 best solutions below

2
Charles Duffy On

Using mmap() to map the file into virtual memory, and then letting the OS page that virtual memory in and out of physical memory, is one way to reduce memory requirements (compared to the original behavior of running a big read() that copies the whole file into newly-allocated memory that isn't disk-backed and can't be paged out unless you have adequate swap defined).

#!/usr/bin/env python3

import mmap
import sys
from hashlib import sha256, sha1

with open(sys.argv[1], 'rb') as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
        length = len(mm)
        footer = bytearray(mm[-6:])
        signature_start_from_end = (footer[1] << 8) + footer[0]
        signature_start = length - signature_start_from_end
        comment_len = (footer[5] << 8) + footer[4]
        signed_len = length - comment_len - 2

        comment_len = (footer[5] << 8) + footer[4]
        signed_len = length - comment_len - 2

        print('Package length: %d' % (length,))
        print('Comment length: %d' % (comment_len,))
        print('Signed data length: %d' % (signed_len,))
        print('Signature start: %d' % (signature_start,))

        h = sha256()

        ## slower, but more explicit about only dealing with small chunks at a time
        current_pos=0
        block_size=4096
        while current_pos < signed_len:
            block_end = min(current_pos+block_size, signed_len)
            h.update(mm[current_pos:block_end])
            current_pos = block_end
            gc.collect()

        ## faster but depends on CPython implementation details
        # h.update(mm[:signed_len])

        print(h.hexdigest().lower())