Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/archive/dlink/encrpted_img.py: 58%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

43 statements  

1import io 

2from pathlib import Path 

3 

4from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 

5from structlog import get_logger 

6 

7from unblob.file_utils import File, InvalidInputFormat 

8from unblob.models import ( 

9 Endian, 

10 Extractor, 

11 HandlerDoc, 

12 HandlerType, 

13 Reference, 

14 Regex, 

15 StructHandler, 

16 ValidChunk, 

17) 

18 

19logger = get_logger() 

20 

21C_DEFINITIONS = r""" 

22 typedef struct encrpted_img_header { 

23 char magic[12]; /* encrpted_img */ 

24 uint32 size; /* total size of file */ 

25 } dlink_header_t; 

26""" 

27 

28HEADER_LEN = 16 

29PEB_SIZE = 0x20000 

30UBI_HEAD = b"\x55\x42\x49\x23\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 

31UBI_HEAD_LEN = len(UBI_HEAD) 

32KEY = b"he9-4+M!)d6=m~we1,q2a3d1n&2*Z^%8" 

33IV = b"J%1iQl8$=lm-;8AE" 

34 

35 

36class EncrptedExtractor(Extractor): 

37 def extract(self, inpath: Path, outdir: Path): 

38 cipher = Cipher(algorithms.AES(KEY), modes.CBC(IV)) 

39 decryptor = cipher.decryptor() 

40 outpath = outdir.joinpath(f"{inpath.name}.decrypted") 

41 outfile = outpath.open("wb") 

42 with inpath.open("rb") as f: 

43 f.seek(HEADER_LEN, io.SEEK_SET) # skip header 

44 ciphertext = f.read(PEB_SIZE) 

45 while ciphertext and len(ciphertext) % 16 == 0: 

46 plaintext = decryptor.update(ciphertext) 

47 outfile.write(UBI_HEAD + plaintext[UBI_HEAD_LEN:]) 

48 ciphertext = f.read(PEB_SIZE) 

49 outfile.write(decryptor.finalize()) 

50 outfile.close() 

51 

52 

53class EncrptedHandler(StructHandler): 

54 NAME = "encrpted_img" 

55 

56 PATTERNS = [ 

57 Regex(r"encrpted_img"), 

58 ] 

59 C_DEFINITIONS = C_DEFINITIONS 

60 HEADER_STRUCT = "dlink_header_t" 

61 EXTRACTOR = EncrptedExtractor() 

62 

63 DOC = HandlerDoc( 

64 name="D-Link encrpted_img", 

65 description="A binary format used by D-Link to store encrypted firmware or data. It consists of a custom 12-byte magic header followed by the encrypted payload.", 

66 handler_type=HandlerType.ARCHIVE, 

67 vendor="D-Link", 

68 references=[ 

69 Reference( 

70 title="How-To: Extracting Decryption Keys for D-Link", 

71 url="https://www.onekey.com/resource/extracting-decryption-keys-dlink", # Replace with actual reference if available 

72 ) 

73 ], 

74 limitations=[], 

75 ) 

76 

77 def is_valid_header(self, header) -> bool: 

78 return header.size >= len(header) 

79 

80 def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk | None: 

81 header = self.parse_header(file, endian=Endian.BIG) 

82 

83 if not self.is_valid_header(header): 

84 raise InvalidInputFormat("Invalid header length") 

85 

86 return ValidChunk( 

87 start_offset=start_offset, 

88 end_offset=start_offset + len(header) + header.size, 

89 )